diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-07-28 19:47:53 -0400 |
---|---|---|
committer | Michal Marek <mmarek@suse.cz> | 2010-08-03 09:05:56 -0400 |
commit | 1ce53adf13a54375d2a5c7cdbe341b2558389615 (patch) | |
tree | ebd9f596daa9cdbf3eca2f964e2f58946d4b4d16 | |
parent | 4696e2958b345189afebcb52e365d16ca6e403ef (diff) |
modpost: support objects with more than 64k sections
This patch makes modpost able to process object files with more than
64k sections. Needed for huge kernel builds (allyesconfig, for example)
with -ffunction-sections. 64k sections handling is covered, for example,
by this document:
"IA-64 gABI Proposal 74: Section Indexes"
http://www.codesourcery.com/public/cxx-abi/abi/prop-74-sindex.html
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Michal Marek <mmarek@suse.cz>
-rw-r--r-- | scripts/mod/file2alias.c | 6 | ||||
-rw-r--r-- | scripts/mod/modpost.c | 102 | ||||
-rw-r--r-- | scripts/mod/modpost.h | 43 |
3 files changed, 122 insertions, 29 deletions
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 220213e603db..33f436328f9a 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c | |||
@@ -839,16 +839,16 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, | |||
839 | char *zeros = NULL; | 839 | char *zeros = NULL; |
840 | 840 | ||
841 | /* We're looking for a section relative symbol */ | 841 | /* We're looking for a section relative symbol */ |
842 | if (!sym->st_shndx || sym->st_shndx >= info->hdr->e_shnum) | 842 | if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) |
843 | return; | 843 | return; |
844 | 844 | ||
845 | /* Handle all-NULL symbols allocated into .bss */ | 845 | /* Handle all-NULL symbols allocated into .bss */ |
846 | if (info->sechdrs[sym->st_shndx].sh_type & SHT_NOBITS) { | 846 | if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { |
847 | zeros = calloc(1, sym->st_size); | 847 | zeros = calloc(1, sym->st_size); |
848 | symval = zeros; | 848 | symval = zeros; |
849 | } else { | 849 | } else { |
850 | symval = (void *)info->hdr | 850 | symval = (void *)info->hdr |
851 | + info->sechdrs[sym->st_shndx].sh_offset | 851 | + info->sechdrs[get_secindex(info, sym)].sh_offset |
852 | + sym->st_value; | 852 | + sym->st_value; |
853 | } | 853 | } |
854 | 854 | ||
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 3318692e4e76..7249ab44f44c 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c | |||
@@ -253,7 +253,7 @@ static enum export export_no(const char *s) | |||
253 | return export_unknown; | 253 | return export_unknown; |
254 | } | 254 | } |
255 | 255 | ||
256 | static enum export export_from_sec(struct elf_info *elf, Elf_Section sec) | 256 | static enum export export_from_sec(struct elf_info *elf, unsigned int sec) |
257 | { | 257 | { |
258 | if (sec == elf->export_sec) | 258 | if (sec == elf->export_sec) |
259 | return export_plain; | 259 | return export_plain; |
@@ -373,6 +373,8 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
373 | Elf_Ehdr *hdr; | 373 | Elf_Ehdr *hdr; |
374 | Elf_Shdr *sechdrs; | 374 | Elf_Shdr *sechdrs; |
375 | Elf_Sym *sym; | 375 | Elf_Sym *sym; |
376 | const char *secstrings; | ||
377 | unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; | ||
376 | 378 | ||
377 | hdr = grab_file(filename, &info->size); | 379 | hdr = grab_file(filename, &info->size); |
378 | if (!hdr) { | 380 | if (!hdr) { |
@@ -417,8 +419,27 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
417 | return 0; | 419 | return 0; |
418 | } | 420 | } |
419 | 421 | ||
422 | if (hdr->e_shnum == 0) { | ||
423 | /* | ||
424 | * There are more than 64k sections, | ||
425 | * read count from .sh_size. | ||
426 | * note: it doesn't need shndx2secindex() | ||
427 | */ | ||
428 | info->num_sections = TO_NATIVE(sechdrs[0].sh_size); | ||
429 | } | ||
430 | else { | ||
431 | info->num_sections = hdr->e_shnum; | ||
432 | } | ||
433 | if (hdr->e_shstrndx == SHN_XINDEX) { | ||
434 | info->secindex_strings = | ||
435 | shndx2secindex(TO_NATIVE(sechdrs[0].sh_link)); | ||
436 | } | ||
437 | else { | ||
438 | info->secindex_strings = hdr->e_shstrndx; | ||
439 | } | ||
440 | |||
420 | /* Fix endianness in section headers */ | 441 | /* Fix endianness in section headers */ |
421 | for (i = 0; i < hdr->e_shnum; i++) { | 442 | for (i = 0; i < info->num_sections; i++) { |
422 | sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); | 443 | sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); |
423 | sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); | 444 | sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); |
424 | sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); | 445 | sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); |
@@ -431,9 +452,8 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
431 | sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); | 452 | sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); |
432 | } | 453 | } |
433 | /* Find symbol table. */ | 454 | /* Find symbol table. */ |
434 | for (i = 1; i < hdr->e_shnum; i++) { | 455 | secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; |
435 | const char *secstrings | 456 | for (i = 1; i < info->num_sections; i++) { |
436 | = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
437 | const char *secname; | 457 | const char *secname; |
438 | int nobits = sechdrs[i].sh_type == SHT_NOBITS; | 458 | int nobits = sechdrs[i].sh_type == SHT_NOBITS; |
439 | 459 | ||
@@ -461,14 +481,26 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
461 | else if (strcmp(secname, "__ksymtab_gpl_future") == 0) | 481 | else if (strcmp(secname, "__ksymtab_gpl_future") == 0) |
462 | info->export_gpl_future_sec = i; | 482 | info->export_gpl_future_sec = i; |
463 | 483 | ||
464 | if (sechdrs[i].sh_type != SHT_SYMTAB) | 484 | if (sechdrs[i].sh_type == SHT_SYMTAB) { |
465 | continue; | 485 | unsigned int sh_link_idx; |
486 | symtab_idx = i; | ||
487 | info->symtab_start = (void *)hdr + | ||
488 | sechdrs[i].sh_offset; | ||
489 | info->symtab_stop = (void *)hdr + | ||
490 | sechdrs[i].sh_offset + sechdrs[i].sh_size; | ||
491 | sh_link_idx = shndx2secindex(sechdrs[i].sh_link); | ||
492 | info->strtab = (void *)hdr + | ||
493 | sechdrs[sh_link_idx].sh_offset; | ||
494 | } | ||
466 | 495 | ||
467 | info->symtab_start = (void *)hdr + sechdrs[i].sh_offset; | 496 | /* 32bit section no. table? ("more than 64k sections") */ |
468 | info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset | 497 | if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { |
469 | + sechdrs[i].sh_size; | 498 | symtab_shndx_idx = i; |
470 | info->strtab = (void *)hdr + | 499 | info->symtab_shndx_start = (void *)hdr + |
471 | sechdrs[sechdrs[i].sh_link].sh_offset; | 500 | sechdrs[i].sh_offset; |
501 | info->symtab_shndx_stop = (void *)hdr + | ||
502 | sechdrs[i].sh_offset + sechdrs[i].sh_size; | ||
503 | } | ||
472 | } | 504 | } |
473 | if (!info->symtab_start) | 505 | if (!info->symtab_start) |
474 | fatal("%s has no symtab?\n", filename); | 506 | fatal("%s has no symtab?\n", filename); |
@@ -480,6 +512,21 @@ static int parse_elf(struct elf_info *info, const char *filename) | |||
480 | sym->st_value = TO_NATIVE(sym->st_value); | 512 | sym->st_value = TO_NATIVE(sym->st_value); |
481 | sym->st_size = TO_NATIVE(sym->st_size); | 513 | sym->st_size = TO_NATIVE(sym->st_size); |
482 | } | 514 | } |
515 | |||
516 | if (symtab_shndx_idx != ~0U) { | ||
517 | Elf32_Word *p; | ||
518 | if (symtab_idx != | ||
519 | shndx2secindex(sechdrs[symtab_shndx_idx].sh_link)) | ||
520 | fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", | ||
521 | filename, | ||
522 | shndx2secindex(sechdrs[symtab_shndx_idx].sh_link), | ||
523 | symtab_idx); | ||
524 | /* Fix endianness */ | ||
525 | for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; | ||
526 | p++) | ||
527 | *p = TO_NATIVE(*p); | ||
528 | } | ||
529 | |||
483 | return 1; | 530 | return 1; |
484 | } | 531 | } |
485 | 532 | ||
@@ -514,7 +561,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, | |||
514 | Elf_Sym *sym, const char *symname) | 561 | Elf_Sym *sym, const char *symname) |
515 | { | 562 | { |
516 | unsigned int crc; | 563 | unsigned int crc; |
517 | enum export export = export_from_sec(info, sym->st_shndx); | 564 | enum export export = export_from_sec(info, get_secindex(info, sym)); |
518 | 565 | ||
519 | switch (sym->st_shndx) { | 566 | switch (sym->st_shndx) { |
520 | case SHN_COMMON: | 567 | case SHN_COMMON: |
@@ -656,19 +703,19 @@ static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) | |||
656 | return "(unknown)"; | 703 | return "(unknown)"; |
657 | } | 704 | } |
658 | 705 | ||
659 | static const char *sec_name(struct elf_info *elf, int shndx) | 706 | static const char *sec_name(struct elf_info *elf, int secindex) |
660 | { | 707 | { |
661 | Elf_Shdr *sechdrs = elf->sechdrs; | 708 | Elf_Shdr *sechdrs = elf->sechdrs; |
662 | return (void *)elf->hdr + | 709 | return (void *)elf->hdr + |
663 | elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + | 710 | elf->sechdrs[elf->secindex_strings].sh_offset + |
664 | sechdrs[shndx].sh_name; | 711 | sechdrs[secindex].sh_name; |
665 | } | 712 | } |
666 | 713 | ||
667 | static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) | 714 | static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) |
668 | { | 715 | { |
669 | return (void *)elf->hdr + | 716 | return (void *)elf->hdr + |
670 | elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + | 717 | elf->sechdrs[elf->secindex_strings].sh_offset + |
671 | sechdr->sh_name; | 718 | sechdr->sh_name; |
672 | } | 719 | } |
673 | 720 | ||
674 | /* if sym is empty or point to a string | 721 | /* if sym is empty or point to a string |
@@ -1047,11 +1094,14 @@ static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, | |||
1047 | Elf_Sym *near = NULL; | 1094 | Elf_Sym *near = NULL; |
1048 | Elf64_Sword distance = 20; | 1095 | Elf64_Sword distance = 20; |
1049 | Elf64_Sword d; | 1096 | Elf64_Sword d; |
1097 | unsigned int relsym_secindex; | ||
1050 | 1098 | ||
1051 | if (relsym->st_name != 0) | 1099 | if (relsym->st_name != 0) |
1052 | return relsym; | 1100 | return relsym; |
1101 | |||
1102 | relsym_secindex = get_secindex(elf, relsym); | ||
1053 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { | 1103 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { |
1054 | if (sym->st_shndx != relsym->st_shndx) | 1104 | if (get_secindex(elf, sym) != relsym_secindex) |
1055 | continue; | 1105 | continue; |
1056 | if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) | 1106 | if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) |
1057 | continue; | 1107 | continue; |
@@ -1113,9 +1163,9 @@ static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, | |||
1113 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { | 1163 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { |
1114 | const char *symsec; | 1164 | const char *symsec; |
1115 | 1165 | ||
1116 | if (sym->st_shndx >= SHN_LORESERVE) | 1166 | if (is_shndx_special(sym->st_shndx)) |
1117 | continue; | 1167 | continue; |
1118 | symsec = sec_name(elf, sym->st_shndx); | 1168 | symsec = sec_name(elf, get_secindex(elf, sym)); |
1119 | if (strcmp(symsec, sec) != 0) | 1169 | if (strcmp(symsec, sec) != 0) |
1120 | continue; | 1170 | continue; |
1121 | if (!is_valid_name(elf, sym)) | 1171 | if (!is_valid_name(elf, sym)) |
@@ -1311,7 +1361,7 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf, | |||
1311 | const char *tosec; | 1361 | const char *tosec; |
1312 | const struct sectioncheck *mismatch; | 1362 | const struct sectioncheck *mismatch; |
1313 | 1363 | ||
1314 | tosec = sec_name(elf, sym->st_shndx); | 1364 | tosec = sec_name(elf, get_secindex(elf, sym)); |
1315 | mismatch = section_mismatch(fromsec, tosec); | 1365 | mismatch = section_mismatch(fromsec, tosec); |
1316 | if (mismatch) { | 1366 | if (mismatch) { |
1317 | Elf_Sym *to; | 1367 | Elf_Sym *to; |
@@ -1339,7 +1389,7 @@ static unsigned int *reloc_location(struct elf_info *elf, | |||
1339 | Elf_Shdr *sechdr, Elf_Rela *r) | 1389 | Elf_Shdr *sechdr, Elf_Rela *r) |
1340 | { | 1390 | { |
1341 | Elf_Shdr *sechdrs = elf->sechdrs; | 1391 | Elf_Shdr *sechdrs = elf->sechdrs; |
1342 | int section = sechdr->sh_info; | 1392 | int section = shndx2secindex(sechdr->sh_info); |
1343 | 1393 | ||
1344 | return (void *)elf->hdr + sechdrs[section].sh_offset + | 1394 | return (void *)elf->hdr + sechdrs[section].sh_offset + |
1345 | (r->r_offset - sechdrs[section].sh_addr); | 1395 | (r->r_offset - sechdrs[section].sh_addr); |
@@ -1447,7 +1497,7 @@ static void section_rela(const char *modname, struct elf_info *elf, | |||
1447 | r.r_addend = TO_NATIVE(rela->r_addend); | 1497 | r.r_addend = TO_NATIVE(rela->r_addend); |
1448 | sym = elf->symtab_start + r_sym; | 1498 | sym = elf->symtab_start + r_sym; |
1449 | /* Skip special sections */ | 1499 | /* Skip special sections */ |
1450 | if (sym->st_shndx >= SHN_LORESERVE) | 1500 | if (is_shndx_special(sym->st_shndx)) |
1451 | continue; | 1501 | continue; |
1452 | check_section_mismatch(modname, elf, &r, sym, fromsec); | 1502 | check_section_mismatch(modname, elf, &r, sym, fromsec); |
1453 | } | 1503 | } |
@@ -1505,7 +1555,7 @@ static void section_rel(const char *modname, struct elf_info *elf, | |||
1505 | } | 1555 | } |
1506 | sym = elf->symtab_start + r_sym; | 1556 | sym = elf->symtab_start + r_sym; |
1507 | /* Skip special sections */ | 1557 | /* Skip special sections */ |
1508 | if (sym->st_shndx >= SHN_LORESERVE) | 1558 | if (is_shndx_special(sym->st_shndx)) |
1509 | continue; | 1559 | continue; |
1510 | check_section_mismatch(modname, elf, &r, sym, fromsec); | 1560 | check_section_mismatch(modname, elf, &r, sym, fromsec); |
1511 | } | 1561 | } |
@@ -1530,7 +1580,7 @@ static void check_sec_ref(struct module *mod, const char *modname, | |||
1530 | Elf_Shdr *sechdrs = elf->sechdrs; | 1580 | Elf_Shdr *sechdrs = elf->sechdrs; |
1531 | 1581 | ||
1532 | /* Walk through all sections */ | 1582 | /* Walk through all sections */ |
1533 | for (i = 0; i < elf->hdr->e_shnum; i++) { | 1583 | for (i = 0; i < elf->num_sections; i++) { |
1534 | check_section(modname, elf, &elf->sechdrs[i]); | 1584 | check_section(modname, elf, &elf->sechdrs[i]); |
1535 | /* We want to process only relocation sections and not .init */ | 1585 | /* We want to process only relocation sections and not .init */ |
1536 | if (sechdrs[i].sh_type == SHT_RELA) | 1586 | if (sechdrs[i].sh_type == SHT_RELA) |
diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index be987a44f250..0388cfccac8d 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h | |||
@@ -129,8 +129,51 @@ struct elf_info { | |||
129 | const char *strtab; | 129 | const char *strtab; |
130 | char *modinfo; | 130 | char *modinfo; |
131 | unsigned int modinfo_len; | 131 | unsigned int modinfo_len; |
132 | |||
133 | /* support for 32bit section numbers */ | ||
134 | |||
135 | unsigned int num_sections; /* max_secindex + 1 */ | ||
136 | unsigned int secindex_strings; | ||
137 | /* if Nth symbol table entry has .st_shndx = SHN_XINDEX, | ||
138 | * take shndx from symtab_shndx_start[N] instead */ | ||
139 | Elf32_Word *symtab_shndx_start; | ||
140 | Elf32_Word *symtab_shndx_stop; | ||
132 | }; | 141 | }; |
133 | 142 | ||
143 | static inline int is_shndx_special(unsigned int i) | ||
144 | { | ||
145 | return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; | ||
146 | } | ||
147 | |||
148 | /* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus: | ||
149 | * shndx == 0 <=> sechdrs[0] | ||
150 | * ...... | ||
151 | * shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1] | ||
152 | * shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE] | ||
153 | * shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1] | ||
154 | * ...... | ||
155 | * fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff, | ||
156 | * so basically we map 0000..feff -> 0000..feff | ||
157 | * ff00..ffff -> (you are a bad boy, dont do it) | ||
158 | * 10000..xxxx -> ff00..(xxxx-0x100) | ||
159 | */ | ||
160 | static inline unsigned int shndx2secindex(unsigned int i) | ||
161 | { | ||
162 | if (i <= SHN_HIRESERVE) | ||
163 | return i; | ||
164 | return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE); | ||
165 | } | ||
166 | |||
167 | /* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ | ||
168 | static inline unsigned int get_secindex(const struct elf_info *info, | ||
169 | const Elf_Sym *sym) | ||
170 | { | ||
171 | if (sym->st_shndx != SHN_XINDEX) | ||
172 | return sym->st_shndx; | ||
173 | return shndx2secindex(info->symtab_shndx_start[sym - | ||
174 | info->symtab_start]); | ||
175 | } | ||
176 | |||
134 | /* file2alias.c */ | 177 | /* file2alias.c */ |
135 | extern unsigned int cross_build; | 178 | extern unsigned int cross_build; |
136 | void handle_moddevtable(struct module *mod, struct elf_info *info, | 179 | void handle_moddevtable(struct module *mod, struct elf_info *info, |