Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'x86/ld-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 linker bug workarounds from Peter Anvin.

GNU ld-2.22.52.0.[12] (*) has an unfortunate bug where it incorrectly
turns certain relocation entries absolute. Section-relative symbols
that are part of otherwise empty sections are silently changed them to
absolute. We rely on section-relative symbols staying section-relative,
and actually have several sections in the linker script solely for this
purpose.

See for example

http://sourceware.org/bugzilla/show_bug.cgi?id=14052

We could just black-list the buggy linker, but it appears that it got
shipped in at least F17, and possibly other distros too, so it's sadly
not some rare unusual case.

This backports the workaround from the x86/trampoline branch, and as
Peter says: "This is not a minimal fix, not at all, but it is a tested
code base."

* 'x86/ld-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86, relocs: When printing an error, say relative or absolute
x86, relocs: Workaround for binutils 2.22.52.0.1 section bug
x86, realmode: 16-bit real-mode code support for relocs tool

(*) That's a manly release numbering system. Stupid, sure. But manly.

+205 -65
+6 -3
Makefile
··· 442 442 443 443 no-dot-config-targets := clean mrproper distclean \ 444 444 cscope gtags TAGS tags help %docs check% coccicheck \ 445 - include/linux/version.h headers_% archheaders \ 445 + include/linux/version.h headers_% archheaders archscripts \ 446 446 kernelversion %src-pkg 447 447 448 448 config-targets := 0 ··· 979 979 include/config/auto.conf 980 980 $(cmd_crmodverdir) 981 981 982 - archprepare: archheaders prepare1 scripts_basic 982 + archprepare: archheaders archscripts prepare1 scripts_basic 983 983 984 984 prepare0: archprepare FORCE 985 985 $(Q)$(MAKE) $(build)=. ··· 1049 1049 PHONY += archheaders 1050 1050 archheaders: 1051 1051 1052 + PHONY += archscripts 1053 + archscripts: 1054 + 1052 1055 PHONY += __headers 1053 - __headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE 1056 + __headers: include/linux/version.h scripts_basic asm-generic archheaders archscripts FORCE 1054 1057 $(Q)$(MAKE) $(build)=scripts build_unifdef 1055 1058 1056 1059 PHONY += headers_install_all
+3
arch/x86/Makefile
··· 134 134 KBUILD_CFLAGS += $(mflags-y) 135 135 KBUILD_AFLAGS += $(mflags-y) 136 136 137 + archscripts: 138 + $(Q)$(MAKE) $(build)=arch/x86/tools relocs 139 + 137 140 ### 138 141 # Syscall table generation 139 142
+4 -5
arch/x86/boot/compressed/Makefile
··· 40 40 $(obj)/vmlinux.bin: vmlinux FORCE 41 41 $(call if_changed,objcopy) 42 42 43 + targets += vmlinux.bin.all vmlinux.relocs 43 44 44 - targets += vmlinux.bin.all vmlinux.relocs relocs 45 - hostprogs-$(CONFIG_X86_NEED_RELOCS) += relocs 46 - 45 + CMD_RELOCS = arch/x86/tools/relocs 47 46 quiet_cmd_relocs = RELOCS $@ 48 - cmd_relocs = $(obj)/relocs $< > $@;$(obj)/relocs --abs-relocs $< 49 - $(obj)/vmlinux.relocs: vmlinux $(obj)/relocs FORCE 47 + cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $< 48 + $(obj)/vmlinux.relocs: vmlinux FORCE 50 49 $(call if_changed,relocs) 51 50 52 51 vmlinux.bin.all-y := $(obj)/vmlinux.bin
+185 -57
arch/x86/boot/compressed/relocs.c arch/x86/tools/relocs.c
··· 18 18 static Elf32_Ehdr ehdr; 19 19 static unsigned long reloc_count, reloc_idx; 20 20 static unsigned long *relocs; 21 + static unsigned long reloc16_count, reloc16_idx; 22 + static unsigned long *relocs16; 21 23 22 24 struct section { 23 25 Elf32_Shdr shdr; ··· 30 28 }; 31 29 static struct section *secs; 32 30 31 + enum symtype { 32 + S_ABS, 33 + S_REL, 34 + S_SEG, 35 + S_LIN, 36 + S_NSYMTYPES 37 + }; 38 + 39 + static const char * const sym_regex_kernel[S_NSYMTYPES] = { 33 40 /* 34 41 * Following symbols have been audited. There values are constant and do 35 42 * not change if bzImage is loaded at a different physical address than 36 43 * the address for which it has been compiled. Don't warn user about 37 44 * absolute relocations present w.r.t these symbols. 38 45 */ 39 - static const char abs_sym_regex[] = 46 + [S_ABS] = 40 47 "^(xen_irq_disable_direct_reloc$|" 41 48 "xen_save_fl_direct_reloc$|" 42 49 "VDSO|" 43 - "__crc_)"; 44 - static regex_t abs_sym_regex_c; 45 - static int is_abs_reloc(const char *sym_name) 46 - { 47 - return !regexec(&abs_sym_regex_c, sym_name, 0, NULL, 0); 48 - } 50 + "__crc_)", 49 51 50 52 /* 51 53 * These symbols are known to be relative, even if the linker marks them 52 54 * as absolute (typically defined outside any section in the linker script.) 53 55 */ 54 - static const char rel_sym_regex[] = 55 - "^_end$"; 56 - static regex_t rel_sym_regex_c; 57 - static int is_rel_reloc(const char *sym_name) 56 + [S_REL] = 57 + "^(__init_(begin|end)|" 58 + "__x86_cpu_dev_(start|end)|" 59 + "(__parainstructions|__alt_instructions)(|_end)|" 60 + "(__iommu_table|__apicdrivers|__smp_locks)(|_end)|" 61 + "_end)$" 62 + }; 63 + 64 + 65 + static const char * const sym_regex_realmode[S_NSYMTYPES] = { 66 + /* 67 + * These are 16-bit segment symbols when compiling 16-bit code. 68 + */ 69 + [S_SEG] = 70 + "^real_mode_seg$", 71 + 72 + /* 73 + * These are offsets belonging to segments, as opposed to linear addresses, 74 + * when compiling 16-bit code. 75 + */ 76 + [S_LIN] = 77 + "^pa_", 78 + }; 79 + 80 + static const char * const *sym_regex; 81 + 82 + static regex_t sym_regex_c[S_NSYMTYPES]; 83 + static int is_reloc(enum symtype type, const char *sym_name) 58 84 { 59 - return !regexec(&rel_sym_regex_c, sym_name, 0, NULL, 0); 85 + return sym_regex[type] && 86 + !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); 60 87 } 61 88 62 - static void regex_init(void) 89 + static void regex_init(int use_real_mode) 63 90 { 64 91 char errbuf[128]; 65 92 int err; 66 - 67 - err = regcomp(&abs_sym_regex_c, abs_sym_regex, 68 - REG_EXTENDED|REG_NOSUB); 69 - if (err) { 70 - regerror(err, &abs_sym_regex_c, errbuf, sizeof errbuf); 71 - die("%s", errbuf); 72 - } 93 + int i; 73 94 74 - err = regcomp(&rel_sym_regex_c, rel_sym_regex, 75 - REG_EXTENDED|REG_NOSUB); 76 - if (err) { 77 - regerror(err, &rel_sym_regex_c, errbuf, sizeof errbuf); 78 - die("%s", errbuf); 95 + if (use_real_mode) 96 + sym_regex = sym_regex_realmode; 97 + else 98 + sym_regex = sym_regex_kernel; 99 + 100 + for (i = 0; i < S_NSYMTYPES; i++) { 101 + if (!sym_regex[i]) 102 + continue; 103 + 104 + err = regcomp(&sym_regex_c[i], sym_regex[i], 105 + REG_EXTENDED|REG_NOSUB); 106 + 107 + if (err) { 108 + regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf); 109 + die("%s", errbuf); 110 + } 79 111 } 80 112 } 81 113 ··· 190 154 REL_TYPE(R_386_RELATIVE), 191 155 REL_TYPE(R_386_GOTOFF), 192 156 REL_TYPE(R_386_GOTPC), 157 + REL_TYPE(R_386_8), 158 + REL_TYPE(R_386_PC8), 159 + REL_TYPE(R_386_16), 160 + REL_TYPE(R_386_PC16), 193 161 #undef REL_TYPE 194 162 }; 195 163 const char *name = "unknown type rel type name"; ··· 229 189 name = sym_strtab + sym->st_name; 230 190 } 231 191 else { 232 - name = sec_name(secs[sym->st_shndx].shdr.sh_name); 192 + name = sec_name(sym->st_shndx); 233 193 } 234 194 return name; 235 195 } ··· 512 472 * Before warning check if this absolute symbol 513 473 * relocation is harmless. 514 474 */ 515 - if (is_abs_reloc(name) || is_rel_reloc(name)) 475 + if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) 516 476 continue; 517 477 518 478 if (!printed) { ··· 536 496 printf("\n"); 537 497 } 538 498 539 - static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) 499 + static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym), 500 + int use_real_mode) 540 501 { 541 502 int i; 542 503 /* Walk through the relocations */ ··· 562 521 Elf32_Rel *rel; 563 522 Elf32_Sym *sym; 564 523 unsigned r_type; 524 + const char *symname; 525 + int shn_abs; 526 + 565 527 rel = &sec->reltab[j]; 566 528 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 567 529 r_type = ELF32_R_TYPE(rel->r_info); 568 - /* Don't visit relocations to absolute symbols */ 569 - if (sym->st_shndx == SHN_ABS && 570 - !is_rel_reloc(sym_name(sym_strtab, sym))) { 571 - continue; 572 - } 530 + 531 + shn_abs = sym->st_shndx == SHN_ABS; 532 + 573 533 switch (r_type) { 574 534 case R_386_NONE: 575 535 case R_386_PC32: 536 + case R_386_PC16: 537 + case R_386_PC8: 576 538 /* 577 539 * NONE can be ignored and and PC relative 578 540 * relocations don't need to be adjusted. 579 541 */ 580 542 break; 543 + 544 + case R_386_16: 545 + symname = sym_name(sym_strtab, sym); 546 + if (!use_real_mode) 547 + goto bad; 548 + if (shn_abs) { 549 + if (is_reloc(S_ABS, symname)) 550 + break; 551 + else if (!is_reloc(S_SEG, symname)) 552 + goto bad; 553 + } else { 554 + if (is_reloc(S_LIN, symname)) 555 + goto bad; 556 + else 557 + break; 558 + } 559 + visit(rel, sym); 560 + break; 561 + 581 562 case R_386_32: 582 - /* Visit relocations that need to be adjusted */ 563 + symname = sym_name(sym_strtab, sym); 564 + if (shn_abs) { 565 + if (is_reloc(S_ABS, symname)) 566 + break; 567 + else if (!is_reloc(S_REL, symname)) 568 + goto bad; 569 + } else { 570 + if (use_real_mode && 571 + !is_reloc(S_LIN, symname)) 572 + break; 573 + } 583 574 visit(rel, sym); 584 575 break; 585 576 default: 586 577 die("Unsupported relocation type: %s (%d)\n", 587 578 rel_type(r_type), r_type); 588 579 break; 580 + bad: 581 + symname = sym_name(sym_strtab, sym); 582 + die("Invalid %s %s relocation: %s\n", 583 + shn_abs ? "absolute" : "relative", 584 + rel_type(r_type), symname); 589 585 } 590 586 } 591 587 } ··· 630 552 631 553 static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 632 554 { 633 - reloc_count += 1; 555 + if (ELF32_R_TYPE(rel->r_info) == R_386_16) 556 + reloc16_count++; 557 + else 558 + reloc_count++; 634 559 } 635 560 636 561 static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 637 562 { 638 563 /* Remember the address that needs to be adjusted. */ 639 - relocs[reloc_idx++] = rel->r_offset; 564 + if (ELF32_R_TYPE(rel->r_info) == R_386_16) 565 + relocs16[reloc16_idx++] = rel->r_offset; 566 + else 567 + relocs[reloc_idx++] = rel->r_offset; 640 568 } 641 569 642 570 static int cmp_relocs(const void *va, const void *vb) ··· 652 568 return (*a == *b)? 0 : (*a > *b)? 1 : -1; 653 569 } 654 570 655 - static void emit_relocs(int as_text) 571 + static int write32(unsigned int v, FILE *f) 572 + { 573 + unsigned char buf[4]; 574 + 575 + put_unaligned_le32(v, buf); 576 + return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; 577 + } 578 + 579 + static void emit_relocs(int as_text, int use_real_mode) 656 580 { 657 581 int i; 658 582 /* Count how many relocations I have and allocate space for them. */ 659 583 reloc_count = 0; 660 - walk_relocs(count_reloc); 584 + walk_relocs(count_reloc, use_real_mode); 661 585 relocs = malloc(reloc_count * sizeof(relocs[0])); 662 586 if (!relocs) { 663 587 die("malloc of %d entries for relocs failed\n", 664 588 reloc_count); 665 589 } 590 + 591 + relocs16 = malloc(reloc16_count * sizeof(relocs[0])); 592 + if (!relocs16) { 593 + die("malloc of %d entries for relocs16 failed\n", 594 + reloc16_count); 595 + } 666 596 /* Collect up the relocations */ 667 597 reloc_idx = 0; 668 - walk_relocs(collect_reloc); 598 + walk_relocs(collect_reloc, use_real_mode); 599 + 600 + if (reloc16_count && !use_real_mode) 601 + die("Segment relocations found but --realmode not specified\n"); 669 602 670 603 /* Order the relocations for more efficient processing */ 671 604 qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); 605 + qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs); 672 606 673 607 /* Print the relocations */ 674 608 if (as_text) { ··· 695 593 */ 696 594 printf(".section \".data.reloc\",\"a\"\n"); 697 595 printf(".balign 4\n"); 698 - for (i = 0; i < reloc_count; i++) { 699 - printf("\t .long 0x%08lx\n", relocs[i]); 596 + if (use_real_mode) { 597 + printf("\t.long %lu\n", reloc16_count); 598 + for (i = 0; i < reloc16_count; i++) 599 + printf("\t.long 0x%08lx\n", relocs16[i]); 600 + printf("\t.long %lu\n", reloc_count); 601 + for (i = 0; i < reloc_count; i++) { 602 + printf("\t.long 0x%08lx\n", relocs[i]); 603 + } 604 + } else { 605 + /* Print a stop */ 606 + printf("\t.long 0x%08lx\n", (unsigned long)0); 607 + for (i = 0; i < reloc_count; i++) { 608 + printf("\t.long 0x%08lx\n", relocs[i]); 609 + } 700 610 } 611 + 701 612 printf("\n"); 702 613 } 703 614 else { 704 - unsigned char buf[4]; 705 - /* Print a stop */ 706 - fwrite("\0\0\0\0", 4, 1, stdout); 707 - /* Now print each relocation */ 708 - for (i = 0; i < reloc_count; i++) { 709 - put_unaligned_le32(relocs[i], buf); 710 - fwrite(buf, 4, 1, stdout); 615 + if (use_real_mode) { 616 + write32(reloc16_count, stdout); 617 + for (i = 0; i < reloc16_count; i++) 618 + write32(relocs16[i], stdout); 619 + write32(reloc_count, stdout); 620 + 621 + /* Now print each relocation */ 622 + for (i = 0; i < reloc_count; i++) 623 + write32(relocs[i], stdout); 624 + } else { 625 + /* Print a stop */ 626 + write32(0, stdout); 627 + 628 + /* Now print each relocation */ 629 + for (i = 0; i < reloc_count; i++) { 630 + write32(relocs[i], stdout); 631 + } 711 632 } 712 633 } 713 634 } 714 635 715 636 static void usage(void) 716 637 { 717 - die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); 638 + die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); 718 639 } 719 640 720 641 int main(int argc, char **argv) 721 642 { 722 643 int show_absolute_syms, show_absolute_relocs; 723 - int as_text; 644 + int as_text, use_real_mode; 724 645 const char *fname; 725 646 FILE *fp; 726 647 int i; 727 648 728 - regex_init(); 729 - 730 649 show_absolute_syms = 0; 731 650 show_absolute_relocs = 0; 732 651 as_text = 0; 652 + use_real_mode = 0; 733 653 fname = NULL; 734 654 for (i = 1; i < argc; i++) { 735 655 char *arg = argv[i]; 736 656 if (*arg == '-') { 737 - if (strcmp(argv[1], "--abs-syms") == 0) { 657 + if (strcmp(arg, "--abs-syms") == 0) { 738 658 show_absolute_syms = 1; 739 659 continue; 740 660 } 741 - 742 - if (strcmp(argv[1], "--abs-relocs") == 0) { 661 + if (strcmp(arg, "--abs-relocs") == 0) { 743 662 show_absolute_relocs = 1; 744 663 continue; 745 664 } 746 - else if (strcmp(argv[1], "--text") == 0) { 665 + if (strcmp(arg, "--text") == 0) { 747 666 as_text = 1; 667 + continue; 668 + } 669 + if (strcmp(arg, "--realmode") == 0) { 670 + use_real_mode = 1; 748 671 continue; 749 672 } 750 673 } ··· 782 655 if (!fname) { 783 656 usage(); 784 657 } 658 + regex_init(use_real_mode); 785 659 fp = fopen(fname, "r"); 786 660 if (!fp) { 787 661 die("Cannot open %s: %s\n", ··· 801 673 print_absolute_relocs(); 802 674 return 0; 803 675 } 804 - emit_relocs(as_text); 676 + emit_relocs(as_text, use_real_mode); 805 677 return 0; 806 678 }
+1
arch/x86/tools/.gitignore
··· 1 + relocs
+4
arch/x86/tools/Makefile
··· 36 36 $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c 37 37 38 38 $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c 39 + 40 + HOST_EXTRACFLAGS += -I$(srctree)/tools/include 41 + hostprogs-y += relocs 42 + relocs: $(obj)/relocs
+2
scripts/Makefile
··· 8 8 # conmakehash: Create arrays for initializing the kernel console tables 9 9 # docproc: Used in Documentation/DocBook 10 10 11 + HOST_EXTRACFLAGS += -I$(srctree)/tools/include 12 + 11 13 hostprogs-$(CONFIG_KALLSYMS) += kallsyms 12 14 hostprogs-$(CONFIG_LOGO) += pnmtologo 13 15 hostprogs-$(CONFIG_VT) += conmakehash