aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-07-28 19:47:53 -0400
committerMichal Marek <mmarek@suse.cz>2010-08-03 09:05:56 -0400
commit1ce53adf13a54375d2a5c7cdbe341b2558389615 (patch)
treeebd9f596daa9cdbf3eca2f964e2f58946d4b4d16
parent4696e2958b345189afebcb52e365d16ca6e403ef (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.c6
-rw-r--r--scripts/mod/modpost.c102
-rw-r--r--scripts/mod/modpost.h43
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
256static enum export export_from_sec(struct elf_info *elf, Elf_Section sec) 256static 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
659static const char *sec_name(struct elf_info *elf, int shndx) 706static 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
667static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) 714static 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
143static 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 */
160static 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" */
168static 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 */
135extern unsigned int cross_build; 178extern unsigned int cross_build;
136void handle_moddevtable(struct module *mod, struct elf_info *info, 179void handle_moddevtable(struct module *mod, struct elf_info *info,