History

Fix symbol versions with shared libs

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.

Michael Matz committed 6 years ago

Commit fdeeb621 parent d79e1de1 file · +47 −41Browse files

Unified · Split

tccelf.c+47−41
@@ -558,9 +558,7 @@ version_add (TCCState *s1) · 557 unmodified lines
558558 return;
559559 versym_section = new_section(s1, ".gnu.version", SHT_GNU_versym, SHF_ALLOC);
560560 versym_section->sh_entsize = sizeof(ElfW(Half));
561− verneed_section = new_section(s1, ".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC);
562561 versym_section->link = s1->dynsym;
563− verneed_section->link = s1->dynsym->link;
564562
565563 /* add needed symbols */
566564 symtab = s1->dynsym;
@@ -580,43 +578,50 @@ version_add (TCCState *s1) · 13 unmodified lines
580578 } else
581579 versym[sym_index] = 0;
582580 }
583− /* generate verneed section */
584− for (i = nb_sym_versions; i-- > 0;) {
585− struct sym_version *sv = &sym_versions[i];
586− int n_same_libs = 0, prev;
587− size_t vnofs;
588− ElfW(Vernaux) *vna = 0;
589− if (sv->out_index < 1)
590− continue;
591− vnofs = section_add(verneed_section, sizeof(*vn), 1);
592− vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
593− vn->vn_version = 1;
594− vn->vn_file = put_elf_str(verneed_section->link, sv->lib);
595− vn->vn_aux = sizeof (*vn);
596− do {
597− prev = sv->prev_same_lib;
598− if (sv->out_index > 0) {
599− vna = section_ptr_add(verneed_section, sizeof(*vna));
600− vna->vna_hash = elf_hash ((const unsigned char *)sv->version);
601− vna->vna_flags = 0;
602− vna->vna_other = sv->out_index;
603− sv->out_index = -2;
604− vna->vna_name = put_elf_str(verneed_section->link, sv->version);
605− vna->vna_next = sizeof (*vna);
606− n_same_libs++;
607− }
608− if (prev >= 0)
609− sv = &sym_versions[prev];
610− } while(prev >= 0);
611− vna->vna_next = 0;
612− vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
613− vn->vn_cnt = n_same_libs;
614− vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna);
615− nb_entries++;
616− }
617− if (vn)
618− vn->vn_next = 0;
619− verneed_section->sh_info = nb_entries;
581+ /* generate verneed section, but not when it will be empty. Some
582+ dynamic linkers look at their contents even when DTVERNEEDNUM and
583+ section size is zero. */
584+ if (nb_versions > 2) {
585+ verneed_section = new_section(s1, ".gnu.version_r",
586+ SHT_GNU_verneed, SHF_ALLOC);
587+ verneed_section->link = s1->dynsym->link;
588+ for (i = nb_sym_versions; i-- > 0;) {
589+ struct sym_version *sv = &sym_versions[i];
590+ int n_same_libs = 0, prev;
591+ size_t vnofs;
592+ ElfW(Vernaux) *vna = 0;
593+ if (sv->out_index < 1)
594+ continue;
595+ vnofs = section_add(verneed_section, sizeof(*vn), 1);
596+ vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
597+ vn->vn_version = 1;
598+ vn->vn_file = put_elf_str(verneed_section->link, sv->lib);
599+ vn->vn_aux = sizeof (*vn);
600+ do {
601+ prev = sv->prev_same_lib;
602+ if (sv->out_index > 0) {
603+ vna = section_ptr_add(verneed_section, sizeof(*vna));
604+ vna->vna_hash = elf_hash ((const unsigned char *)sv->version);
605+ vna->vna_flags = 0;
606+ vna->vna_other = sv->out_index;
607+ sv->out_index = -2;
608+ vna->vna_name = put_elf_str(verneed_section->link, sv->version);
609+ vna->vna_next = sizeof (*vna);
610+ n_same_libs++;
611+ }
612+ if (prev >= 0)
613+ sv = &sym_versions[prev];
614+ } while(prev >= 0);
615+ vna->vna_next = 0;
616+ vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
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+ }
620625 dt_verneednum = nb_entries;
621626 }
622627 #endif
@@ -2045,10 +2050,11 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 1422 unmodified lines
20452050 put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
20462051 #endif
20472052 #endif
2048− if (versym_section) {
2053+ if (versym_section)
2054+ put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
2055+ if (verneed_section) {
20492056 put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
20502057 put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
2051− put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
20522058 }
20532059 s = find_section_create (s1, ".preinit_array", 0);
20542060 if (s && s->data_offset) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t