Commit 1ce53adf13a54375d2a5c7cdbe341b2558389615
Committed by
Michal Marek
1 parent
4696e2958b
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>
Showing 3 changed files with 122 additions and 29 deletions Side-by-side Diff
scripts/mod/file2alias.c
... | ... | @@ -839,16 +839,16 @@ |
839 | 839 | char *zeros = NULL; |
840 | 840 | |
841 | 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 | 843 | return; |
844 | 844 | |
845 | 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 | 847 | zeros = calloc(1, sym->st_size); |
848 | 848 | symval = zeros; |
849 | 849 | } else { |
850 | 850 | symval = (void *)info->hdr |
851 | - + info->sechdrs[sym->st_shndx].sh_offset | |
851 | + + info->sechdrs[get_secindex(info, sym)].sh_offset | |
852 | 852 | + sym->st_value; |
853 | 853 | } |
854 | 854 |
scripts/mod/modpost.c
... | ... | @@ -253,7 +253,7 @@ |
253 | 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 | 258 | if (sec == elf->export_sec) |
259 | 259 | return export_plain; |
... | ... | @@ -373,6 +373,8 @@ |
373 | 373 | Elf_Ehdr *hdr; |
374 | 374 | Elf_Shdr *sechdrs; |
375 | 375 | Elf_Sym *sym; |
376 | + const char *secstrings; | |
377 | + unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; | |
376 | 378 | |
377 | 379 | hdr = grab_file(filename, &info->size); |
378 | 380 | if (!hdr) { |
379 | 381 | |
... | ... | @@ -417,8 +419,27 @@ |
417 | 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 | 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 | 443 | sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); |
423 | 444 | sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); |
424 | 445 | sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); |
... | ... | @@ -431,9 +452,8 @@ |
431 | 452 | sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); |
432 | 453 | } |
433 | 454 | /* Find symbol table. */ |
434 | - for (i = 1; i < hdr->e_shnum; i++) { | |
435 | - const char *secstrings | |
436 | - = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | |
455 | + secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; | |
456 | + for (i = 1; i < info->num_sections; i++) { | |
437 | 457 | const char *secname; |
438 | 458 | int nobits = sechdrs[i].sh_type == SHT_NOBITS; |
439 | 459 | |
440 | 460 | |
... | ... | @@ -461,14 +481,26 @@ |
461 | 481 | else if (strcmp(secname, "__ksymtab_gpl_future") == 0) |
462 | 482 | info->export_gpl_future_sec = i; |
463 | 483 | |
464 | - if (sechdrs[i].sh_type != SHT_SYMTAB) | |
465 | - continue; | |
484 | + if (sechdrs[i].sh_type == SHT_SYMTAB) { | |
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; | |
468 | - info->symtab_stop = (void *)hdr + sechdrs[i].sh_offset | |
469 | - + sechdrs[i].sh_size; | |
470 | - info->strtab = (void *)hdr + | |
471 | - sechdrs[sechdrs[i].sh_link].sh_offset; | |
496 | + /* 32bit section no. table? ("more than 64k sections") */ | |
497 | + if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { | |
498 | + symtab_shndx_idx = i; | |
499 | + info->symtab_shndx_start = (void *)hdr + | |
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 | 505 | if (!info->symtab_start) |
474 | 506 | fatal("%s has no symtab?\n", filename); |
... | ... | @@ -480,6 +512,21 @@ |
480 | 512 | sym->st_value = TO_NATIVE(sym->st_value); |
481 | 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 | 530 | return 1; |
484 | 531 | } |
485 | 532 | |
... | ... | @@ -514,7 +561,7 @@ |
514 | 561 | Elf_Sym *sym, const char *symname) |
515 | 562 | { |
516 | 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 | 566 | switch (sym->st_shndx) { |
520 | 567 | case SHN_COMMON: |
521 | 568 | |
522 | 569 | |
... | ... | @@ -656,19 +703,19 @@ |
656 | 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 | 708 | Elf_Shdr *sechdrs = elf->sechdrs; |
662 | 709 | return (void *)elf->hdr + |
663 | - elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + | |
664 | - sechdrs[shndx].sh_name; | |
710 | + elf->sechdrs[elf->secindex_strings].sh_offset + | |
711 | + sechdrs[secindex].sh_name; | |
665 | 712 | } |
666 | 713 | |
667 | 714 | static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) |
668 | 715 | { |
669 | 716 | return (void *)elf->hdr + |
670 | - elf->sechdrs[elf->hdr->e_shstrndx].sh_offset + | |
671 | - sechdr->sh_name; | |
717 | + elf->sechdrs[elf->secindex_strings].sh_offset + | |
718 | + sechdr->sh_name; | |
672 | 719 | } |
673 | 720 | |
674 | 721 | /* if sym is empty or point to a string |
675 | 722 | |
676 | 723 | |
... | ... | @@ -1047,11 +1094,14 @@ |
1047 | 1094 | Elf_Sym *near = NULL; |
1048 | 1095 | Elf64_Sword distance = 20; |
1049 | 1096 | Elf64_Sword d; |
1097 | + unsigned int relsym_secindex; | |
1050 | 1098 | |
1051 | 1099 | if (relsym->st_name != 0) |
1052 | 1100 | return relsym; |
1101 | + | |
1102 | + relsym_secindex = get_secindex(elf, relsym); | |
1053 | 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 | 1105 | continue; |
1056 | 1106 | if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) |
1057 | 1107 | continue; |
1058 | 1108 | |
... | ... | @@ -1113,9 +1163,9 @@ |
1113 | 1163 | for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { |
1114 | 1164 | const char *symsec; |
1115 | 1165 | |
1116 | - if (sym->st_shndx >= SHN_LORESERVE) | |
1166 | + if (is_shndx_special(sym->st_shndx)) | |
1117 | 1167 | continue; |
1118 | - symsec = sec_name(elf, sym->st_shndx); | |
1168 | + symsec = sec_name(elf, get_secindex(elf, sym)); | |
1119 | 1169 | if (strcmp(symsec, sec) != 0) |
1120 | 1170 | continue; |
1121 | 1171 | if (!is_valid_name(elf, sym)) |
... | ... | @@ -1311,7 +1361,7 @@ |
1311 | 1361 | const char *tosec; |
1312 | 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 | 1365 | mismatch = section_mismatch(fromsec, tosec); |
1316 | 1366 | if (mismatch) { |
1317 | 1367 | Elf_Sym *to; |
... | ... | @@ -1339,7 +1389,7 @@ |
1339 | 1389 | Elf_Shdr *sechdr, Elf_Rela *r) |
1340 | 1390 | { |
1341 | 1391 | Elf_Shdr *sechdrs = elf->sechdrs; |
1342 | - int section = sechdr->sh_info; | |
1392 | + int section = shndx2secindex(sechdr->sh_info); | |
1343 | 1393 | |
1344 | 1394 | return (void *)elf->hdr + sechdrs[section].sh_offset + |
1345 | 1395 | (r->r_offset - sechdrs[section].sh_addr); |
... | ... | @@ -1447,7 +1497,7 @@ |
1447 | 1497 | r.r_addend = TO_NATIVE(rela->r_addend); |
1448 | 1498 | sym = elf->symtab_start + r_sym; |
1449 | 1499 | /* Skip special sections */ |
1450 | - if (sym->st_shndx >= SHN_LORESERVE) | |
1500 | + if (is_shndx_special(sym->st_shndx)) | |
1451 | 1501 | continue; |
1452 | 1502 | check_section_mismatch(modname, elf, &r, sym, fromsec); |
1453 | 1503 | } |
... | ... | @@ -1505,7 +1555,7 @@ |
1505 | 1555 | } |
1506 | 1556 | sym = elf->symtab_start + r_sym; |
1507 | 1557 | /* Skip special sections */ |
1508 | - if (sym->st_shndx >= SHN_LORESERVE) | |
1558 | + if (is_shndx_special(sym->st_shndx)) | |
1509 | 1559 | continue; |
1510 | 1560 | check_section_mismatch(modname, elf, &r, sym, fromsec); |
1511 | 1561 | } |
... | ... | @@ -1530,7 +1580,7 @@ |
1530 | 1580 | Elf_Shdr *sechdrs = elf->sechdrs; |
1531 | 1581 | |
1532 | 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 | 1584 | check_section(modname, elf, &elf->sechdrs[i]); |
1535 | 1585 | /* We want to process only relocation sections and not .init */ |
1536 | 1586 | if (sechdrs[i].sh_type == SHT_RELA) |
scripts/mod/modpost.h
... | ... | @@ -129,7 +129,50 @@ |
129 | 129 | const char *strtab; |
130 | 130 | char *modinfo; |
131 | 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 | }; |
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 | +} | |
133 | 176 | |
134 | 177 | /* file2alias.c */ |
135 | 178 | extern unsigned int cross_build; |