ELF files that refer to shared libs containing sym-versions, but don't refer to any dynamic symbols with symbol versions (should happen only with very simple shared libs) would generate an empty .gnu.version_r section. Some dynamic linker contain bugs in that they don't check the section size or DT_VERNEEDNUM (which are both zero for such files we generate) before accessing the first entry, and then bail out with a message like ./a.exe: error while loading shared libraries: ./a1.so: unsupported version 25960 of Verneed record (where the "version number" actually comes from neighboring bytes from different sections). So, there's not much choice, we simply must not generate such section.
Unified · Split
| @@ -558,9 +558,7 @@ version_add (TCCState *s1) · 557 unmodified lines | |||
| 558 | return; | 558 | return; |
| 559 | versym_section = new_section(s1, ".gnu.version", SHT_GNU_versym, SHF_ALLOC); | 559 | versym_section = new_section(s1, ".gnu.version", SHT_GNU_versym, SHF_ALLOC); |
| 560 | versym_section->sh_entsize = sizeof(ElfW(Half)); | 560 | versym_section->sh_entsize = sizeof(ElfW(Half)); |
| 561 | verneed_section = new_section(s1, ".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC); | ||
| 562 | versym_section->link = s1->dynsym; | 561 | versym_section->link = s1->dynsym; |
| 563 | verneed_section->link = s1->dynsym->link; | ||
| 564 | 562 | ||
| 565 | /* add needed symbols */ | 563 | /* add needed symbols */ |
| 566 | symtab = s1->dynsym; | 564 | symtab = s1->dynsym; |
| @@ -580,43 +578,50 @@ version_add (TCCState *s1) · 13 unmodified lines | |||
| 580 | } else | 578 | } else |
| 581 | versym[sym_index] = 0; | 579 | versym[sym_index] = 0; |
| 582 | } | 580 | } |
| 583 | /* generate verneed section */ | 581 | /* generate verneed section, but not when it will be empty. Some |
| 584 | for (i = nb_sym_versions; i-- > 0;) { | 582 | dynamic linkers look at their contents even when DTVERNEEDNUM and |
| 585 | struct sym_version *sv = &sym_versions[i]; | 583 | section size is zero. */ |
| 586 | int n_same_libs = 0, prev; | 584 | if (nb_versions > 2) { |
| 587 | size_t vnofs; | 585 | verneed_section = new_section(s1, ".gnu.version_r", |
| 588 | ElfW(Vernaux) *vna = 0; | 586 | SHT_GNU_verneed, SHF_ALLOC); |
| 589 | if (sv->out_index < 1) | 587 | verneed_section->link = s1->dynsym->link; |
| 590 | continue; | 588 | for (i = nb_sym_versions; i-- > 0;) { |
| 591 | vnofs = section_add(verneed_section, sizeof(*vn), 1); | 589 | struct sym_version *sv = &sym_versions[i]; |
| 592 | vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); | 590 | int n_same_libs = 0, prev; |
| 593 | vn->vn_version = 1; | 591 | size_t vnofs; |
| 594 | vn->vn_file = put_elf_str(verneed_section->link, sv->lib); | 592 | ElfW(Vernaux) *vna = 0; |
| 595 | vn->vn_aux = sizeof (*vn); | 593 | if (sv->out_index < 1) |
| 596 | do { | 594 | continue; |
| 597 | prev = sv->prev_same_lib; | 595 | vnofs = section_add(verneed_section, sizeof(*vn), 1); |
| 598 | if (sv->out_index > 0) { | 596 | vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); |
| 599 | vna = section_ptr_add(verneed_section, sizeof(*vna)); | 597 | vn->vn_version = 1; |
| 600 | vna->vna_hash = elf_hash ((const unsigned char *)sv->version); | 598 | vn->vn_file = put_elf_str(verneed_section->link, sv->lib); |
| 601 | vna->vna_flags = 0; | 599 | vn->vn_aux = sizeof (*vn); |
| 602 | vna->vna_other = sv->out_index; | 600 | do { |
| 603 | sv->out_index = -2; | 601 | prev = sv->prev_same_lib; |
| 604 | vna->vna_name = put_elf_str(verneed_section->link, sv->version); | 602 | if (sv->out_index > 0) { |
| 605 | vna->vna_next = sizeof (*vna); | 603 | vna = section_ptr_add(verneed_section, sizeof(*vna)); |
| 606 | n_same_libs++; | 604 | vna->vna_hash = elf_hash ((const unsigned char *)sv->version); |
| 607 | } | 605 | vna->vna_flags = 0; |
| 608 | if (prev >= 0) | 606 | vna->vna_other = sv->out_index; |
| 609 | sv = &sym_versions[prev]; | 607 | sv->out_index = -2; |
| 610 | } while(prev >= 0); | 608 | vna->vna_name = put_elf_str(verneed_section->link, sv->version); |
| 611 | vna->vna_next = 0; | 609 | vna->vna_next = sizeof (*vna); |
| 612 | vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); | 610 | n_same_libs++; |
| 613 | vn->vn_cnt = n_same_libs; | 611 | } |
| 614 | vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna); | 612 | if (prev >= 0) |
| 615 | nb_entries++; | 613 | sv = &sym_versions[prev]; |
| 616 | } | 614 | } while(prev >= 0); |
| 617 | if (vn) | 615 | vna->vna_next = 0; |
| 618 | vn->vn_next = 0; | 616 | vn = (ElfW(Verneed)*)(verneed_section->data + vnofs); |
| 619 | verneed_section->sh_info = nb_entries; | 617 | vn->vn_cnt = n_same_libs; |
| 618 | vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna); | ||
| 619 | nb_entries++; | ||
| 620 | } | ||
| 621 | if (vn) | ||
| 622 | vn->vn_next = 0; | ||
| 623 | verneed_section->sh_info = nb_entries; | ||
| 624 | } | ||
| 620 | dt_verneednum = nb_entries; | 625 | dt_verneednum = nb_entries; |
| 621 | } | 626 | } |
| 622 | #endif | 627 | #endif |
| @@ -2045,10 +2050,11 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 1422 unmodified lines | |||
| 2045 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); | 2050 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
| 2046 | #endif | 2051 | #endif |
| 2047 | #endif | 2052 | #endif |
| 2048 | if (versym_section) { | 2053 | if (versym_section) |
| 2054 | put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); | ||
| 2055 | if (verneed_section) { | ||
| 2049 | put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); | 2056 | put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); |
| 2050 | put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); | 2057 | put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); |
| 2051 | put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); | ||
| 2052 | } | 2058 | } |
| 2053 | s = find_section_create (s1, ".preinit_array", 0); | 2059 | s = find_section_create (s1, ".preinit_array", 0); |
| 2054 | if (s && s->data_offset) { | 2060 | if (s && s->data_offset) { |