Initial support for shared libraries on x86-64.
Unified · Split
| @@ -802,9 +802,18 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 801 unmodified lines | ||
| 802 | 802 | #elif defined(TCC_TARGET_X86_64) |
| 803 | 803 | case R_X86_64_64: |
| 804 | 804 | if (s1->output_type == TCC_OUTPUT_DLL) { |
| 805 | − qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | |
| 806 | − qrel->r_addend = *(long long *)ptr + val; | |
| 807 | − qrel++; | |
| 805 | + esym_index = s1->symtab_to_dynsym[sym_index]; | |
| 806 | + qrel->r_offset = rel->r_offset; | |
| 807 | + if (esym_index) { | |
| 808 | + qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_64); | |
| 809 | + qrel->r_addend = rel->r_addend; | |
| 810 | + qrel++; | |
| 811 | + break; | |
| 812 | + } else { | |
| 813 | + qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | |
| 814 | + qrel->r_addend = *(long long *)ptr + val; | |
| 815 | + qrel++; | |
| 816 | + } | |
| 808 | 817 | } |
| 809 | 818 | *(long long *)ptr += val; |
| 810 | 819 | break; |
| @@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1, · 202 unmodified lines | ||
| 1013 | 1022 | ElfW(Sym) *sym; |
| 1014 | 1023 | unsigned long offset; |
| 1015 | 1024 | int *ptr; |
| 1025 | + struct sym_attr *symattr; | |
| 1016 | 1026 | |
| 1017 | 1027 | if (!s1->got) |
| 1018 | 1028 | build_got(s1); |
| @@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1, · 18 unmodified lines | ||
| 1037 | 1047 | got_entry_present = 1; |
| 1038 | 1048 | } |
| 1039 | 1049 | |
| 1040 | − alloc_sym_attr(s1, sym_index)->got_offset = s1->got->data_offset; | |
| 1050 | + symattr = alloc_sym_attr(s1, sym_index); | |
| 1051 | + /* Only store the GOT offset if it's not generated for the PLT entry. */ | |
| 1052 | + if (!need_plt_entry) | |
| 1053 | + symattr->got_offset = s1->got->data_offset; | |
| 1041 | 1054 | |
| 1042 | 1055 | if (s1->dynsym) { |
| 1043 | 1056 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| @@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1, · 4 unmodified lines | ||
| 1048 | 1061 | Section *plt; |
| 1049 | 1062 | uint8_t *p; |
| 1050 | 1063 | int modrm; |
| 1064 | + unsigned long relofs; | |
| 1051 | 1065 | |
| 1052 | 1066 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) |
| 1053 | 1067 | modrm = 0x25; |
| @@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1, · 18 unmodified lines | ||
| 1072 | 1086 | put32(p + 8, PTR_SIZE * 2); |
| 1073 | 1087 | } |
| 1074 | 1088 | |
| 1089 | + /* The PLT slot refers to the relocation entry it needs | |
| 1090 | + via offset. The reloc entry is created below, so its | |
| 1091 | + offset is the current data_offset. */ | |
| 1092 | + relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; | |
| 1075 | 1093 | p = section_ptr_add(plt, 16); |
| 1076 | 1094 | p[0] = 0xff; /* jmp *(got + x) */ |
| 1077 | 1095 | p[1] = modrm; |
| 1078 | 1096 | put32(p + 2, s1->got->data_offset); |
| 1079 | 1097 | p[6] = 0x68; /* push $xxx */ |
| 1080 | − put32(p + 7, (plt->data_offset - 32) >> 1); | |
| 1098 | +#ifdef TCC_TARGET_X86_64 | |
| 1099 | + /* On x86-64, the relocation is referred to by _index_. */ | |
| 1100 | + put32(p + 7, relofs / sizeof (ElfW_Rel)); | |
| 1101 | +#else | |
| 1102 | + put32(p + 7, relofs); | |
| 1103 | +#endif | |
| 1081 | 1104 | p[11] = 0xe9; /* jmp plt_start */ |
| 1082 | 1105 | put32(p + 12, -(plt->data_offset)); |
| 1083 | 1106 | |
| @@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1, · 3 unmodified lines | ||
| 1087 | 1110 | if (s1->output_type == TCC_OUTPUT_EXE) |
| 1088 | 1111 | #endif |
| 1089 | 1112 | offset = plt->data_offset - 16; |
| 1090 | − s1->sym_attrs[sym_index].has_plt_entry = 1; | |
| 1113 | + symattr->has_plt_entry = 1; | |
| 1091 | 1114 | } |
| 1092 | 1115 | #elif defined(TCC_TARGET_ARM) |
| 1093 | 1116 | if (need_plt_entry) { |
| @@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1, · 15 unmodified lines | ||
| 1109 | 1132 | put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ |
| 1110 | 1133 | } |
| 1111 | 1134 | |
| 1112 | − if (s1->sym_attrs[sym_index].plt_thumb_stub) { | |
| 1135 | + if (symattr->plt_thumb_stub) { | |
| 1113 | 1136 | p = section_ptr_add(plt, 20); |
| 1114 | 1137 | put32(p, 0x4778); /* bx pc */ |
| 1115 | 1138 | put32(p+2, 0x46c0); /* nop */ |
| @@ -1125,27 +1148,23 @@ static void put_got_entry(TCCState *s1, · 9 unmodified lines | ||
| 1125 | 1148 | the PLT */ |
| 1126 | 1149 | if (s1->output_type == TCC_OUTPUT_EXE) |
| 1127 | 1150 | offset = plt->data_offset - 16; |
| 1128 | − s1->sym_attrs[sym_index].has_plt_entry = 1; | |
| 1151 | + symattr->has_plt_entry = 1; | |
| 1129 | 1152 | } |
| 1130 | 1153 | #elif defined(TCC_TARGET_C67) |
| 1131 | 1154 | tcc_error("C67 got not implemented"); |
| 1132 | 1155 | #else |
| 1133 | 1156 | #error unsupported CPU |
| 1134 | 1157 | #endif |
| 1158 | + /* XXX This might generate multiple syms for name. */ | |
| 1135 | 1159 | index = put_elf_sym(s1->dynsym, offset, |
| 1136 | 1160 | size, info, 0, sym->st_shndx, name); |
| 1137 | − if (got_entry_present) { | |
| 1138 | − put_elf_reloc(s1->dynsym, s1->got, | |
| 1139 | − s1->sym_attrs[sym_index].got_offset, | |
| 1140 | − reloc_type, index); | |
| 1141 | − return; | |
| 1142 | − } | |
| 1143 | − | |
| 1144 | − /* put a got entry */ | |
| 1161 | + /* Create the relocation (it's against the GOT for PLT | |
| 1162 | + and GOT relocs). */ | |
| 1145 | 1163 | put_elf_reloc(s1->dynsym, s1->got, |
| 1146 | 1164 | s1->got->data_offset, |
| 1147 | 1165 | reloc_type, index); |
| 1148 | 1166 | } |
| 1167 | + /* And now create the GOT slot itself. */ | |
| 1149 | 1168 | ptr = section_ptr_add(s1->got, PTR_SIZE); |
| 1150 | 1169 | *ptr = 0; |
| 1151 | 1170 | } |
| @@ -1697,26 +1716,11 @@ static void export_global_syms(TCCState *s1) · 545 unmodified lines | ||
| 1697 | 1716 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
| 1698 | 1717 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
| 1699 | 1718 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
| 1700 | −#if defined(TCC_OUTPUT_DLL_WITH_PLT) | |
| 1701 | − int type = ELFW(ST_TYPE)(sym->st_info); | |
| 1702 | − if ((type == STT_FUNC || type == STT_GNU_IFUNC) | |
| 1703 | − && sym->st_shndx == SHN_UNDEF) { | |
| 1704 | − int visibility = ELFW(ST_BIND)(sym->st_info); | |
| 1705 | − put_got_entry(s1, R_JMP_SLOT, sym->st_size, | |
| 1706 | − ELFW(ST_INFO)(visibility, STT_FUNC), | |
| 1707 | − sym - (ElfW(Sym) *) symtab_section->data); | |
| 1708 | − } else if (type == STT_OBJECT) { | |
| 1709 | − put_got_entry(s1, R_X86_64_GLOB_DAT, sym->st_size, sym->st_info, | |
| 1710 | − sym - (ElfW(Sym) *) symtab_section->data); | |
| 1711 | − } else | |
| 1712 | −#endif | |
| 1713 | − { | |
| 1714 | − name = (char *) symtab_section->link->data + sym->st_name; | |
| 1715 | − dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | |
| 1716 | − sym->st_info, 0, sym->st_shndx, name); | |
| 1717 | − index = sym - (ElfW(Sym) *) symtab_section->data; | |
| 1718 | − s1->symtab_to_dynsym[index] = dynindex; | |
| 1719 | − } | |
| 1719 | + name = (char *) symtab_section->link->data + sym->st_name; | |
| 1720 | + dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, | |
| 1721 | + sym->st_info, 0, sym->st_shndx, name); | |
| 1722 | + index = sym - (ElfW(Sym) *) symtab_section->data; | |
| 1723 | + s1->symtab_to_dynsym[index] = dynindex; | |
| 1720 | 1724 | } |
| 1721 | 1725 | } |
| 1722 | 1726 | } |
| @@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp) · 603 unmodified lines | ||
| 604 | 604 | if (vtop->r & VT_SYM) { |
| 605 | 605 | /* relocation case */ |
| 606 | 606 | greloc(cur_text_section, vtop->sym, |
| 607 | − ind + 1, R_X86_64_PC32); | |
| 607 | + ind + 1, R_X86_64_PLT32); | |
| 608 | 608 | } else { |
| 609 | 609 | /* put an empty PC32 relocation */ |
| 610 | 610 | put_elf_reloc(symtab_section, cur_text_section, |