History

Add elf version support

herman ten brugge committed 7 years ago

Commit 7268fe71 parent 491773a1 file · +368 −4Browse files

Unified · Split

tccelf.c+368−4
@@ -42,6 +42,34 @@ ST_DATA Section *symtab_section; · 41 unmodified lines
4242 /* debug sections */
4343 ST_DATA Section *stab_section, *stabstr_section;
4444
45+/* elf version information */
46+ST_DATA int nb_version_sym;
47+struct sym_info_struct {
48+ char *name;
49+ ElfW(Sym) esym;
50+};
51+ST_DATA struct def_need_struct {
52+ char *lib;
53+ char *version;
54+ unsigned int nb_sym_info;
55+ struct sym_info_struct *sym_info;
56+} *version_sym;
57+ST_DATA int nb_need;
58+ST_DATA int dt_verneednum;
59+ST_DATA struct need_struct {
60+ int offset;
61+ char *lib;
62+ int n_aux;
63+ struct aux_struct {
64+ int offset;
65+ char *version;
66+ int other;
67+ } *aux;
68+} *need;
69+ST_DATA ElfW(Half) next_version = 1;
70+ST_DATA Section *versym_section;
71+ST_DATA Section *verneed_section;
72+
4573 /* XXX: avoid static variable */
4674 static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
4775
@@ -61,6 +89,10 @@ ST_FUNC void tccelf_new(TCCState *s) · 13 unmodified lines
6189 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
6290 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
6391 bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
92+ versym_section = new_section(s, ".gnu.version", SHT_GNU_versym, SHF_ALLOC);
93+ versym_section->sh_entsize = sizeof(ElfW(Half));
94+ verneed_section = new_section(s, ".gnu.version_r", SHT_GNU_verneed, SHF_ALLOC);
95+ verneed_section->sh_info = 2;
6496 common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
6597 common_section->sh_num = SHN_COMMON;
6698
@@ -198,13 +230,18 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh · 131 unmodified lines
198230 sec->sh_type = sh_type;
199231 sec->sh_flags = sh_flags;
200232 switch(sh_type) {
233+ case SHT_GNU_versym:
234+ sec->sh_addralign = 2;
235+ break;
201236 case SHT_HASH:
202237 case SHT_REL:
203238 case SHT_RELA:
204239 case SHT_DYNSYM:
205240 case SHT_SYMTAB:
206241 case SHT_DYNAMIC:
207− sec->sh_addralign = 4;
242+ case SHT_GNU_verneed:
243+ case SHT_GNU_verdef:
244+ sec->sh_addralign = PTR_SIZE;
208245 break;
209246 case SHT_STRTAB:
210247 sec->sh_addralign = 1;
@@ -516,6 +553,220 @@ ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name) · 305 unmodified lines
516553 }
517554 #endif
518555
556+ST_FUNC void
557+save_def_need_index (int *n_def_need, struct def_need_struct **def_need,
558+ unsigned int n, const char *lib, const char *version)
559+{
560+ /* add index in table */
561+ if (*n_def_need < n + 1) {
562+ *def_need = (struct def_need_struct *)
563+ tcc_realloc (*def_need,
564+ (n + 1) * sizeof (struct def_need_struct));
565+ while (*n_def_need < n + 1) {
566+ (*def_need)[*n_def_need].lib = NULL;
567+ (*def_need)[*n_def_need].version = NULL;
568+ (*def_need)[*n_def_need].nb_sym_info = 0;
569+ (*def_need)[*n_def_need].sym_info = NULL;
570+ (*n_def_need)++;
571+ }
572+ }
573+ if ((*def_need)[n].lib == NULL) {
574+ (*def_need)[n].lib = tcc_strdup (lib);
575+ (*def_need)[n].version = tcc_strdup (version);
576+ }
577+}
578+
579+ST_FUNC void
580+free_def_need (int n_def_need, struct def_need_struct *def_need)
581+{
582+ int i;
583+
584+ for (i = 0; i < n_def_need; i++) {
585+ tcc_free (def_need[i].lib);
586+ tcc_free (def_need[i].version);
587+ }
588+ tcc_free (def_need);
589+}
590+
591+ST_FUNC void
592+add_version_sym (Section *s, int sym_index, int n_def_need,
593+ struct def_need_struct *def_need, const char *name, unsigned int n)
594+{
595+ int i, j;
596+ ElfW(Sym) *esym;
597+
598+ /* check if present */
599+ esym = &((ElfW(Sym) *)s->data)[sym_index];
600+ for (i = 0; i < nb_version_sym; i++) {
601+ for (j = 0; j < version_sym[i].nb_sym_info; j++) {
602+ if (strcmp (version_sym[i].sym_info[j].name, name) == 0) {
603+ if (memcmp (&version_sym[i].sym_info[j].esym, esym, sizeof (ElfW(Sym))) == 0) {
604+ return;
605+ }
606+ version_sym[i].nb_sym_info--;
607+ tcc_free (version_sym[i].sym_info[j].name);
608+ for (; j < version_sym[i].nb_sym_info; j++) {
609+ version_sym[i].sym_info[j] = version_sym[i].sym_info[j + 1];
610+ }
611+ }
612+ }
613+ }
614+ /* add new value */
615+ for (i = 0; i < nb_version_sym; i++) {
616+ if (strcmp (def_need[n].lib,
617+ version_sym[i].lib) == 0 &&
618+ strcmp (def_need[n].version,
619+ version_sym[i].version) == 0) {
620+ break;
621+ }
622+ }
623+ if (i == nb_version_sym) {
624+ version_sym = (struct def_need_struct *)
625+ tcc_realloc (version_sym,
626+ (nb_version_sym + 1) * sizeof (struct def_need_struct));
627+ version_sym[nb_version_sym].lib = tcc_strdup (def_need[n].lib);
628+ version_sym[nb_version_sym].version = tcc_strdup (def_need[n].version);
629+ version_sym[nb_version_sym].nb_sym_info = 0;
630+ version_sym[nb_version_sym].sym_info = NULL;
631+ nb_version_sym++;
632+ }
633+ version_sym[i].sym_info = (struct sym_info_struct *)
634+ tcc_realloc (version_sym[i].sym_info,
635+ (version_sym[i].nb_sym_info + 1) * sizeof (struct sym_info_struct));
636+ version_sym[i].sym_info[version_sym[i].nb_sym_info].name = tcc_strdup (name);
637+ version_sym[i].sym_info[version_sym[i].nb_sym_info].esym = *esym;
638+ version_sym[i].nb_sym_info++;
639+}
640+
641+static void
642+add_need_sym (Section *s, const char *soname, const char *version, const char *name, int sym_index)
643+{
644+ int i;
645+ unsigned long size;
646+ void *ptr;
647+ int ver_index = 0;
648+ struct need_struct *verlib = NULL;
649+ ElfW(Half) vers;
650+
651+ if (soname) {
652+ for (i = 0; i < nb_need; i++) {
653+ if (strcmp (soname, need[i].lib) == 0) {
654+ verlib = &need[i];
655+ break;
656+ }
657+ }
658+ if (verlib == NULL) {
659+ need = (struct need_struct *)
660+ tcc_realloc (need, (nb_need + 1) * sizeof (struct need_struct));
661+ need[nb_need].offset = put_elf_str(s->link, soname);
662+ need[nb_need].lib = tcc_strdup (soname);
663+ need[nb_need].n_aux = 0;
664+ need[nb_need].aux = NULL;
665+ verlib = &need[nb_need];
666+ nb_need++;
667+ }
668+ for (i = 0; i < verlib->n_aux; i++) {
669+ if (strcmp (version, verlib->aux[i].version) == 0) {
670+ ver_index = verlib->aux[i].other;
671+ }
672+ }
673+ if (ver_index == 0) {
674+ verlib->aux = (struct aux_struct *)
675+ tcc_realloc (verlib->aux, (verlib->n_aux + 1) * sizeof (struct aux_struct));
676+ verlib->aux[verlib->n_aux].offset = put_elf_str(s->link, version);
677+ verlib->aux[verlib->n_aux].version = tcc_strdup (version);
678+ ver_index = verlib->aux[verlib->n_aux].other = ++next_version;
679+ verlib->n_aux++;
680+ }
681+ }
682+ /* update versym section */
683+ size = versym_section->data_offset / sizeof (vers);
684+ for (i = size; i < (sym_index + 1); i++) {
685+ ptr = section_ptr_add (versym_section, sizeof (vers));
686+ vers = 0;
687+ memcpy (ptr, &vers, sizeof (vers));
688+ }
689+ ptr = versym_section->data + sym_index * sizeof (vers);
690+ vers = ver_index;
691+ memcpy (ptr, &vers, sizeof (vers));
692+}
693+
694+static void
695+version_add (TCCState *s)
696+{
697+ int i, j, found;
698+ ElfW(Sym) *sym;
699+ ElfW(Verneed) verneed;
700+ ElfW(Vernaux) aux;
701+ Section *symtab;
702+ int sym_index, end_sym;
703+ const char *name;
704+ void *ptr;
705+
706+ /* add needed symbols */
707+ symtab = s->dynsym;
708+ end_sym = symtab->data_offset / sizeof (ElfSym);
709+ for (sym_index = 0; sym_index < end_sym; ++sym_index) {
710+ sym = &((ElfW(Sym) *)symtab->data)[sym_index];
711+ name = (char *) symtab->link->data + sym->st_name;
712+ found = 0;
713+ for (i = 0; !found && i < nb_version_sym; i++) {
714+ for (j = 0; !found && j < version_sym[i].nb_sym_info; j++) {
715+ if (strcmp (version_sym[i].sym_info[j].name, name) == 0) {
716+ found = 1;
717+ add_need_sym (symtab, version_sym[i].lib, version_sym[i].version, name, sym_index);
718+ }
719+ }
720+ }
721+ if (!found) {
722+ add_need_sym (symtab, NULL, NULL, NULL, sym_index);
723+ }
724+ symtab = s->dynsym; /* symtab can be realocated by add_need_sym */
725+ }
726+ /* generate verneed section */
727+ for (i = 0; i < nb_need; i++) {
728+ verneed.vn_version = 1;
729+ verneed.vn_cnt = need[i].n_aux;
730+ verneed.vn_file = need[i].offset;
731+ verneed.vn_aux = sizeof (verneed);
732+ verneed.vn_next = i == nb_need - 1 ? 0 : sizeof (verneed) + need[i].n_aux * sizeof (aux);
733+ ptr = section_ptr_add (verneed_section, sizeof (verneed));
734+ memcpy (ptr, &verneed, sizeof (verneed));
735+ for (j = 0; j < need[i].n_aux; j++) {
736+ aux.vna_hash = elf_hash (need[i].aux[j].version);
737+ aux.vna_flags = 0;
738+ aux.vna_other = need[i].aux[j].other;
739+ aux.vna_name = need[i].aux[j].offset;
740+ aux.vna_next = j == need[i].n_aux - 1 ? 0 : sizeof (aux);
741+ ptr = section_ptr_add (verneed_section, sizeof (aux));
742+ memcpy (ptr, &aux, sizeof (aux));
743+ }
744+ }
745+ /* free all info */
746+ for (i = 0; i < nb_version_sym; i++) {
747+ for (j = 0; j < version_sym[i].nb_sym_info; j++) {
748+ tcc_free (version_sym[i].sym_info[j].name);
749+ }
750+ tcc_free (version_sym[i].lib);
751+ tcc_free (version_sym[i].version);
752+ tcc_free (version_sym[i].sym_info);
753+ }
754+ tcc_free (version_sym);
755+ nb_version_sym = 0;
756+ version_sym = NULL;
757+ for (i = 0; i < nb_need; i++) {
758+ tcc_free (need[i].lib);
759+ for (j = 0; j < need[i].n_aux; j++) {
760+ tcc_free (need[i].aux[j].version);
761+ }
762+ tcc_free (need[i].aux);
763+ }
764+ tcc_free (need);
765+ dt_verneednum = nb_need;
766+ nb_need = 0;
767+ need = NULL;
768+}
769+
519770 /* add an elf symbol : check if it is already defined and patch
520771 it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
521772 ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
@@ -1855,6 +2106,9 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 1333 unmodified lines
18552106 put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
18562107 #endif
18572108 #endif
2109+ put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
2110+ put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
2111+ put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
18582112 if (s1->do_debug)
18592113 put_dt(dynamic, DT_DEBUG, 0);
18602114 put_dt(dynamic, DT_NULL, 0);
@@ -2137,6 +2391,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 276 unmodified lines
21372391 ".dynstr",
21382392 ".hash", SHF_ALLOC);
21392393 dynstr = s1->dynsym->link;
2394+ versym_section->link = s1->dynsym;
2395+ verneed_section->link = dynstr;
21402396
21412397 /* add dynamic section */
21422398 dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
@@ -2157,6 +2413,7 @@ static int elf_output_file(TCCState *s1, const char *filename) · 14 unmodified lines
21572413 }
21582414 }
21592415 build_got_entries(s1);
2416+ version_add (s1);
21602417 }
21612418
21622419 /* we add a section for symbols */
@@ -2752,7 +3009,16 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 589 unmodified lines
27523009 int i, j, nb_syms, nb_dts, sym_bind, ret;
27533010 ElfW(Sym) *sym, *dynsym;
27543011 ElfW(Dyn) *dt, *dynamic;
3012+ int nb_versyms;
3013+ ElfW(Verdef) *verdef, *vdef;
3014+ ElfW(Verneed) *verneed, *vneed;
3015+ ElfW(Half) *versym, *vsym;
27553016 unsigned char *dynstr;
3017+ uint32_t next;
3018+ int sym_index;
3019+ char *lib, *version;
3020+ int n_def_need = 0;
3021+ struct def_need_struct *def_need = NULL;
27563022 const char *name, *soname;
27573023 DLLReference *dllref;
27583024
@@ -2774,6 +3040,10 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 15 unmodified lines
27743040 dynamic = NULL;
27753041 dynsym = NULL; /* avoid warning */
27763042 dynstr = NULL; /* avoid warning */
3043+ nb_versyms = 0;
3044+ verdef = NULL;
3045+ verneed = NULL;
3046+ versym = NULL;
27773047 for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
27783048 switch(sh->sh_type) {
27793049 case SHT_DYNAMIC:
@@ -2786,6 +3056,16 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 6 unmodified lines
27863056 sh1 = &shdr[sh->sh_link];
27873057 dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
27883058 break;
3059+ case SHT_GNU_verdef:
3060+ verdef = load_data(fd, sh->sh_offset, sh->sh_size);
3061+ break;
3062+ case SHT_GNU_verneed:
3063+ verneed = load_data(fd, sh->sh_offset, sh->sh_size);
3064+ break;
3065+ case SHT_GNU_versym:
3066+ nb_versyms = sh->sh_size / sizeof(ElfW(Half));
3067+ versym = load_data(fd, sh->sh_offset, sh->sh_size);
3068+ break;
27893069 default:
27903070 break;
27913071 }
@@ -2812,6 +3092,81 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 20 unmodified lines
28123092 }
28133093 }
28143094
3095+ if (nb_versyms != nb_syms) {
3096+ tcc_free (versym);
3097+ versym = NULL;
3098+ }
3099+
3100+#define DEBUG_VERSION 0
3101+
3102+ if (versym && verdef) {
3103+ lib = NULL;
3104+ vdef = verdef;
3105+ do {
3106+ ElfW(Verdaux) *verdaux =
3107+ (ElfW(Verdaux) *) (((char *) vdef) + vdef->vd_aux);
3108+
3109+#if DEBUG_VERSION
3110+ printf ("verdef: version:%u flags:%u index:%u, hash:%u\n",
3111+ vdef->vd_version, vdef->vd_flags, vdef->vd_ndx,
3112+ vdef->vd_hash);
3113+#endif
3114+ for (i = 0; i < vdef->vd_cnt; i++) {
3115+ version = (char *) dynstr + verdaux->vda_name;
3116+
3117+ if (lib == NULL) {
3118+ lib = version;
3119+ }
3120+ else {
3121+ save_def_need_index (&n_def_need, &def_need,
3122+ vdef->vd_ndx, lib, version);
3123+ }
3124+#if DEBUG_VERSION
3125+ printf (" verdaux(%u): %s\n", vdef->vd_ndx, version);
3126+#endif
3127+ verdaux = (ElfW(Verdaux) *) (((char *) verdaux) + verdaux->vda_next);
3128+ }
3129+ next = vdef->vd_next;
3130+ vdef = (ElfW(Verdef) *) (((char *) vdef) + next);
3131+ } while (next);
3132+ }
3133+ if (versym && verneed) {
3134+ vneed = verneed;
3135+ do {
3136+ ElfW(Vernaux) *vernaux =
3137+ (ElfW(Vernaux) *) (((char *) vneed) + vneed->vn_aux);
3138+
3139+ lib = (char *) dynstr + vneed->vn_file;
3140+#if DEBUG_VERSION
3141+ printf ("verneed: %u %s\n", vneed->vn_version, lib);
3142+#endif
3143+ for (i = 0; i < vneed->vn_cnt; i++) {
3144+ if ((vernaux->vna_other & 0x8000) == 0) { /* hidden */
3145+ version = (char *) dynstr + vernaux->vna_name;
3146+ save_def_need_index (&n_def_need, &def_need,
3147+ vernaux->vna_other, lib, version);
3148+#if DEBUG_VERSION
3149+ printf (" vernaux(%u): %u %u %s\n",
3150+ vernaux->vna_other, vernaux->vna_hash,
3151+ vernaux->vna_flags, version);
3152+#endif
3153+ }
3154+ vernaux = (ElfW(Vernaux) *) (((char *) vernaux) + vernaux->vna_next);
3155+ }
3156+ next = vneed->vn_next;
3157+ vneed = (ElfW(Verneed) *) (((char *) vneed) + next);
3158+ } while (next);
3159+ }
3160+
3161+#if DEBUG_VERSION
3162+ for (i = 0; i < n_def_need; i++) {
3163+ if (def_need[i].lib) {
3164+ printf ("%d: lib: %s, version %s\n",
3165+ i, def_need[i].lib, def_need[i].version);
3166+ }
3167+ }
3168+#endif
3169+
28153170 /* add the dll and its level */
28163171 dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
28173172 dllref->level = level;
@@ -2819,13 +3174,18 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 1 unmodified line
28193174 dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
28203175
28213176 /* add dynamic symbols in dynsym_section */
2822− for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
3177+ for(i = 1, sym = dynsym + 1, vsym = versym + 1; i < nb_syms; i++, sym++, vsym++) {
28233178 sym_bind = ELFW(ST_BIND)(sym->st_info);
28243179 if (sym_bind == STB_LOCAL)
28253180 continue;
28263181 name = (char *) dynstr + sym->st_name;
2827− set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
2828− sym->st_info, sym->st_other, sym->st_shndx, name);
3182+ sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
3183+ sym->st_info, sym->st_other, sym->st_shndx, name);
3184+ if (versym && n_def_need && (*vsym & 0x8000) == 0 &&
3185+ *vsym > 0 && *vsym < n_def_need &&
3186+ def_need[*vsym].lib) {
3187+ add_version_sym (s1->dynsymtab_section, sym_index, n_def_need, def_need, name, *vsym);
3188+ }
28293189 }
28303190
28313191 /* load all referenced DLLs */
@@ -2849,9 +3209,13 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 17 unmodified lines
28493209 }
28503210 ret = 0;
28513211 the_end:
3212+ free_def_need (n_def_need, def_need);
28523213 tcc_free(dynstr);
28533214 tcc_free(dynsym);
28543215 tcc_free(dynamic);
3216+ tcc_free(verdef);
3217+ tcc_free(verneed);
3218+ tcc_free(versym);
28553219 tcc_free(shdr);
28563220 return ret;
28573221 }

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