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 | #elif defined(TCC_TARGET_X86_64) | 802 | #elif defined(TCC_TARGET_X86_64) |
| 803 | case R_X86_64_64: | 803 | case R_X86_64_64: |
| 804 | if (s1->output_type == TCC_OUTPUT_DLL) { | 804 | if (s1->output_type == TCC_OUTPUT_DLL) { |
| 805 | qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE); | 805 | esym_index = s1->symtab_to_dynsym[sym_index]; |
| 806 | qrel->r_addend = *(long long *)ptr + val; | 806 | qrel->r_offset = rel->r_offset; |
| 807 | qrel++; | 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 | *(long long *)ptr += val; | 818 | *(long long *)ptr += val; |
| 810 | break; | 819 | break; |
| @@ -1013,6 +1022,7 @@ static void put_got_entry(TCCState *s1, · 202 unmodified lines | |||
| 1013 | ElfW(Sym) *sym; | 1022 | ElfW(Sym) *sym; |
| 1014 | unsigned long offset; | 1023 | unsigned long offset; |
| 1015 | int *ptr; | 1024 | int *ptr; |
| 1025 | struct sym_attr *symattr; | ||
| 1016 | 1026 | ||
| 1017 | if (!s1->got) | 1027 | if (!s1->got) |
| 1018 | build_got(s1); | 1028 | build_got(s1); |
| @@ -1037,7 +1047,10 @@ static void put_got_entry(TCCState *s1, · 18 unmodified lines | |||
| 1037 | got_entry_present = 1; | 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 | if (s1->dynsym) { | 1055 | if (s1->dynsym) { |
| 1043 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | 1056 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| @@ -1048,6 +1061,7 @@ static void put_got_entry(TCCState *s1, · 4 unmodified lines | |||
| 1048 | Section *plt; | 1061 | Section *plt; |
| 1049 | uint8_t *p; | 1062 | uint8_t *p; |
| 1050 | int modrm; | 1063 | int modrm; |
| 1064 | unsigned long relofs; | ||
| 1051 | 1065 | ||
| 1052 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) | 1066 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) |
| 1053 | modrm = 0x25; | 1067 | modrm = 0x25; |
| @@ -1072,12 +1086,21 @@ static void put_got_entry(TCCState *s1, · 18 unmodified lines | |||
| 1072 | put32(p + 8, PTR_SIZE * 2); | 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 | p = section_ptr_add(plt, 16); | 1093 | p = section_ptr_add(plt, 16); |
| 1076 | p[0] = 0xff; /* jmp *(got + x) */ | 1094 | p[0] = 0xff; /* jmp *(got + x) */ |
| 1077 | p[1] = modrm; | 1095 | p[1] = modrm; |
| 1078 | put32(p + 2, s1->got->data_offset); | 1096 | put32(p + 2, s1->got->data_offset); |
| 1079 | p[6] = 0x68; /* push $xxx */ | 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 | p[11] = 0xe9; /* jmp plt_start */ | 1104 | p[11] = 0xe9; /* jmp plt_start */ |
| 1082 | put32(p + 12, -(plt->data_offset)); | 1105 | put32(p + 12, -(plt->data_offset)); |
| 1083 | 1106 | ||
| @@ -1087,7 +1110,7 @@ static void put_got_entry(TCCState *s1, · 3 unmodified lines | |||
| 1087 | if (s1->output_type == TCC_OUTPUT_EXE) | 1110 | if (s1->output_type == TCC_OUTPUT_EXE) |
| 1088 | #endif | 1111 | #endif |
| 1089 | offset = plt->data_offset - 16; | 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 | #elif defined(TCC_TARGET_ARM) | 1115 | #elif defined(TCC_TARGET_ARM) |
| 1093 | if (need_plt_entry) { | 1116 | if (need_plt_entry) { |
| @@ -1109,7 +1132,7 @@ static void put_got_entry(TCCState *s1, · 15 unmodified lines | |||
| 1109 | put32(p+12, 0xe5bef008); /* ldr pc, [lr, #8]! */ | 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 | p = section_ptr_add(plt, 20); | 1136 | p = section_ptr_add(plt, 20); |
| 1114 | put32(p, 0x4778); /* bx pc */ | 1137 | put32(p, 0x4778); /* bx pc */ |
| 1115 | put32(p+2, 0x46c0); /* nop */ | 1138 | put32(p+2, 0x46c0); /* nop */ |
| @@ -1125,27 +1148,23 @@ static void put_got_entry(TCCState *s1, · 9 unmodified lines | |||
| 1125 | the PLT */ | 1148 | the PLT */ |
| 1126 | if (s1->output_type == TCC_OUTPUT_EXE) | 1149 | if (s1->output_type == TCC_OUTPUT_EXE) |
| 1127 | offset = plt->data_offset - 16; | 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 | #elif defined(TCC_TARGET_C67) | 1153 | #elif defined(TCC_TARGET_C67) |
| 1131 | tcc_error("C67 got not implemented"); | 1154 | tcc_error("C67 got not implemented"); |
| 1132 | #else | 1155 | #else |
| 1133 | #error unsupported CPU | 1156 | #error unsupported CPU |
| 1134 | #endif | 1157 | #endif |
| 1158 | /* XXX This might generate multiple syms for name. */ | ||
| 1135 | index = put_elf_sym(s1->dynsym, offset, | 1159 | index = put_elf_sym(s1->dynsym, offset, |
| 1136 | size, info, 0, sym->st_shndx, name); | 1160 | size, info, 0, sym->st_shndx, name); |
| 1137 | if (got_entry_present) { | 1161 | /* Create the relocation (it's against the GOT for PLT |
| 1138 | put_elf_reloc(s1->dynsym, s1->got, | 1162 | and GOT relocs). */ |
| 1139 | s1->sym_attrs[sym_index].got_offset, | ||
| 1140 | reloc_type, index); | ||
| 1141 | return; | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | /* put a got entry */ | ||
| 1145 | put_elf_reloc(s1->dynsym, s1->got, | 1163 | put_elf_reloc(s1->dynsym, s1->got, |
| 1146 | s1->got->data_offset, | 1164 | s1->got->data_offset, |
| 1147 | reloc_type, index); | 1165 | reloc_type, index); |
| 1148 | } | 1166 | } |
| 1167 | /* And now create the GOT slot itself. */ | ||
| 1149 | ptr = section_ptr_add(s1->got, PTR_SIZE); | 1168 | ptr = section_ptr_add(s1->got, PTR_SIZE); |
| 1150 | *ptr = 0; | 1169 | *ptr = 0; |
| 1151 | } | 1170 | } |
| @@ -1697,26 +1716,11 @@ static void export_global_syms(TCCState *s1) · 545 unmodified lines | |||
| 1697 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); | 1716 | s1->symtab_to_dynsym = tcc_mallocz(sizeof(int) * nb_syms); |
| 1698 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { | 1717 | for_each_elem(symtab_section, 1, sym, ElfW(Sym)) { |
| 1699 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { | 1718 | if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
| 1700 | #if defined(TCC_OUTPUT_DLL_WITH_PLT) | 1719 | name = (char *) symtab_section->link->data + sym->st_name; |
| 1701 | int type = ELFW(ST_TYPE)(sym->st_info); | 1720 | dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size, |
| 1702 | if ((type == STT_FUNC || type == STT_GNU_IFUNC) | 1721 | sym->st_info, 0, sym->st_shndx, name); |
| 1703 | && sym->st_shndx == SHN_UNDEF) { | 1722 | index = sym - (ElfW(Sym) *) symtab_section->data; |
| 1704 | int visibility = ELFW(ST_BIND)(sym->st_info); | 1723 | s1->symtab_to_dynsym[index] = dynindex; |
| 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 | } | ||
| 1720 | } | 1724 | } |
| 1721 | } | 1725 | } |
| 1722 | } | 1726 | } |
| @@ -604,7 +604,7 @@ static void gcall_or_jmp(int is_jmp) · 603 unmodified lines | |||
| 604 | if (vtop->r & VT_SYM) { | 604 | if (vtop->r & VT_SYM) { |
| 605 | /* relocation case */ | 605 | /* relocation case */ |
| 606 | greloc(cur_text_section, vtop->sym, | 606 | greloc(cur_text_section, vtop->sym, |
| 607 | ind + 1, R_X86_64_PC32); | 607 | ind + 1, R_X86_64_PLT32); |
| 608 | } else { | 608 | } else { |
| 609 | /* put an empty PC32 relocation */ | 609 | /* put an empty PC32 relocation */ |
| 610 | put_elf_reloc(symtab_section, cur_text_section, | 610 | put_elf_reloc(symtab_section, cur_text_section, |