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
42/* debug sections */42/* debug sections */
43ST_DATA Section *stab_section, *stabstr_section;43ST_DATA Section *stab_section, *stabstr_section;
44 44
45/* elf version information */
46ST_DATA int nb_version_sym;
47struct sym_info_struct {
48 char *name;
49 ElfW(Sym) esym;
50};
51ST_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;
57ST_DATA int nb_need;
58ST_DATA int dt_verneednum;
59ST_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;
69ST_DATA ElfW(Half) next_version = 1;
70ST_DATA Section *versym_section;
71ST_DATA Section *verneed_section;
72
45/* XXX: avoid static variable */73/* XXX: avoid static variable */
46static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */74static int new_undef_sym = 0; /* Is there a new undefined sym since last new_undef_sym() */
47 75
@@ -61,6 +89,10 @@ ST_FUNC void tccelf_new(TCCState *s) · 13 unmodified lines
61 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);89 text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
62 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);90 data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
63 bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);91 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;
64 common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);96 common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
65 common_section->sh_num = SHN_COMMON;97 common_section->sh_num = SHN_COMMON;
66 98
@@ -198,13 +230,18 @@ ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh · 131 unmodified lines
198 sec->sh_type = sh_type;230 sec->sh_type = sh_type;
199 sec->sh_flags = sh_flags;231 sec->sh_flags = sh_flags;
200 switch(sh_type) {232 switch(sh_type) {
233 case SHT_GNU_versym:
234 sec->sh_addralign = 2;
235 break;
201 case SHT_HASH:236 case SHT_HASH:
202 case SHT_REL:237 case SHT_REL:
203 case SHT_RELA:238 case SHT_RELA:
204 case SHT_DYNSYM:239 case SHT_DYNSYM:
205 case SHT_SYMTAB:240 case SHT_SYMTAB:
206 case SHT_DYNAMIC:241 case SHT_DYNAMIC:
207 sec->sh_addralign = 4;242 case SHT_GNU_verneed:
243 case SHT_GNU_verdef:
244 sec->sh_addralign = PTR_SIZE;
208 break;245 break;
209 case SHT_STRTAB:246 case SHT_STRTAB:
210 sec->sh_addralign = 1;247 sec->sh_addralign = 1;
@@ -516,6 +553,220 @@ ST_FUNC void* tcc_get_symbol_err(TCCState *s, const char *name) · 305 unmodified lines
516}553}
517#endif554#endif
518 555
556ST_FUNC void
557save_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
579ST_FUNC void
580free_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
591ST_FUNC void
592add_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
641static void
642add_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
694static void
695version_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
519/* add an elf symbol : check if it is already defined and patch770/* add an elf symbol : check if it is already defined and patch
520 it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */771 it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
521ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,772ST_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
1855 put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));2106 put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
1856#endif2107#endif
1857#endif2108#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);
1858 if (s1->do_debug)2112 if (s1->do_debug)
1859 put_dt(dynamic, DT_DEBUG, 0);2113 put_dt(dynamic, DT_DEBUG, 0);
1860 put_dt(dynamic, DT_NULL, 0);2114 put_dt(dynamic, DT_NULL, 0);
@@ -2137,6 +2391,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 276 unmodified lines
2137 ".dynstr",2391 ".dynstr",
2138 ".hash", SHF_ALLOC);2392 ".hash", SHF_ALLOC);
2139 dynstr = s1->dynsym->link;2393 dynstr = s1->dynsym->link;
2394 versym_section->link = s1->dynsym;
2395 verneed_section->link = dynstr;
2140 2396
2141 /* add dynamic section */2397 /* add dynamic section */
2142 dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,2398 dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
@@ -2157,6 +2413,7 @@ static int elf_output_file(TCCState *s1, const char *filename) · 14 unmodified lines
2157 }2413 }
2158 }2414 }
2159 build_got_entries(s1);2415 build_got_entries(s1);
2416 version_add (s1);
2160 }2417 }
2161 2418
2162 /* we add a section for symbols */2419 /* 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
2752 int i, j, nb_syms, nb_dts, sym_bind, ret;3009 int i, j, nb_syms, nb_dts, sym_bind, ret;
2753 ElfW(Sym) *sym, *dynsym;3010 ElfW(Sym) *sym, *dynsym;
2754 ElfW(Dyn) *dt, *dynamic;3011 ElfW(Dyn) *dt, *dynamic;
3012 int nb_versyms;
3013 ElfW(Verdef) *verdef, *vdef;
3014 ElfW(Verneed) *verneed, *vneed;
3015 ElfW(Half) *versym, *vsym;
2755 unsigned char *dynstr;3016 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;
2756 const char *name, *soname;3022 const char *name, *soname;
2757 DLLReference *dllref;3023 DLLReference *dllref;
2758 3024
@@ -2774,6 +3040,10 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 15 unmodified lines
2774 dynamic = NULL;3040 dynamic = NULL;
2775 dynsym = NULL; /* avoid warning */3041 dynsym = NULL; /* avoid warning */
2776 dynstr = NULL; /* avoid warning */3042 dynstr = NULL; /* avoid warning */
3043 nb_versyms = 0;
3044 verdef = NULL;
3045 verneed = NULL;
3046 versym = NULL;
2777 for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {3047 for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
2778 switch(sh->sh_type) {3048 switch(sh->sh_type) {
2779 case SHT_DYNAMIC:3049 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
2786 sh1 = &shdr[sh->sh_link];3056 sh1 = &shdr[sh->sh_link];
2787 dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);3057 dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
2788 break;3058 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;
2789 default:3069 default:
2790 break;3070 break;
2791 }3071 }
@@ -2812,6 +3092,81 @@ ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level) · 20 unmodified lines
2812 }3092 }
2813 }3093 }
2814 3094
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
2815 /* add the dll and its level */3170 /* add the dll and its level */
2816 dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));3171 dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
2817 dllref->level = level;3172 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
2819 dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);3174 dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
2820 3175
2821 /* add dynamic symbols in dynsym_section */3176 /* 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++) {
2823 sym_bind = ELFW(ST_BIND)(sym->st_info);3178 sym_bind = ELFW(ST_BIND)(sym->st_info);
2824 if (sym_bind == STB_LOCAL)3179 if (sym_bind == STB_LOCAL)
2825 continue;3180 continue;
2826 name = (char *) dynstr + sym->st_name;3181 name = (char *) dynstr + sym->st_name;
2827 set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,3182 sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
2828 sym->st_info, sym->st_other, sym->st_shndx, name);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 }
2829 }3189 }
2830 3190
2831 /* load all referenced DLLs */3191 /* 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
2849 }3209 }
2850 ret = 0;3210 ret = 0;
2851 the_end:3211 the_end:
3212 free_def_need (n_def_need, def_need);
2852 tcc_free(dynstr);3213 tcc_free(dynstr);
2853 tcc_free(dynsym);3214 tcc_free(dynsym);
2854 tcc_free(dynamic);3215 tcc_free(dynamic);
3216 tcc_free(verdef);
3217 tcc_free(verneed);
3218 tcc_free(versym);
2855 tcc_free(shdr);3219 tcc_free(shdr);
2856 return ret;3220 return ret;
2857}3221}

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