Currently tcc does not use lazy binding. It puts all relocations in the RELX section and solve them all at startup. This was not working on bsd. tcc.h: - New RELPLT_SECTION_FMT for plt relocations - New entry relocplt in struct Section tccelf.c: - put_elf_reloca: put R_JMP_SLOT in relocplt section - build_got_entries*: Use two passes because R_JMP_SLOT and R_GLOB_DAT can not be intermixed on some targets (arm, arm64) - layout_sections: Calculate correct size relocplt section for DT_ values. Make sure relocplt is last - fill_dynamic: Add DT_ values when got is filled move DT_VERSYM because dynamic linker cannot handle it standone - Add note section for NetBSD arm-link.c/arm64-link.c/i386-link.c/riscv64-link.c/x86_64-link.c: - fill got table with pointer to plt section or symbol value in case of TCC_OUTPUT_MEMORY arm-link.c/arm64-link.c: - fix offset first plt entry i386-link.c/x86_64-link.c: - use correct reloc entry - use relofs - sizeof (ElfW_Rel) because the reloc is already done lib/bcheck.c: - no __libc_freeres on FreeBSD and NetBSD tests/Makefile: - Add -fno-stack-protector for OpenBSD tests/tests2/Makefile: - disable 106_pthread/114_bound_signal
Unified · Split
| @@ -145,7 +145,7 @@ ST_FUNC void relocate_plt(TCCState *s1) · 144 unmodified lines | |||
| 145 | 145 | ||
| 146 | if (p < p_end) { | 146 | if (p < p_end) { |
| 147 | int x = s1->got->sh_addr - s1->plt->sh_addr - 12; | 147 | int x = s1->got->sh_addr - s1->plt->sh_addr - 12; |
| 148 | write32le(s1->plt->data + 16, x - 16); | 148 | write32le(s1->plt->data + 16, x - 4); |
| 149 | p += 20; | 149 | p += 20; |
| 150 | while (p < p_end) { | 150 | while (p < p_end) { |
| 151 | unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4; | 151 | unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4; |
| @@ -157,6 +157,18 @@ ST_FUNC void relocate_plt(TCCState *s1) · 5 unmodified lines | |||
| 157 | p += 12; | 157 | p += 12; |
| 158 | } | 158 | } |
| 159 | } | 159 | } |
| 160 | |||
| 161 | if (s1->got->relocplt) { | ||
| 162 | int mem = s1->output_type == TCC_OUTPUT_MEMORY; | ||
| 163 | ElfW_Rel *rel; | ||
| 164 | |||
| 165 | p = s1->got->data; | ||
| 166 | for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) { | ||
| 167 | int sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 168 | ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 169 | write32le(p + rel->r_offset, mem ? sym->st_value : s1->plt->sh_addr); | ||
| 170 | } | ||
| 171 | } | ||
| 160 | } | 172 | } |
| 161 | #endif | 173 | #endif |
| 162 | 174 | ||
| @@ -113,7 +113,7 @@ ST_FUNC void relocate_plt(TCCState *s1) · 112 unmodified lines | |||
| 113 | 113 | ||
| 114 | if (p < p_end) { | 114 | if (p < p_end) { |
| 115 | uint64_t plt = s1->plt->sh_addr; | 115 | uint64_t plt = s1->plt->sh_addr; |
| 116 | uint64_t got = s1->got->sh_addr; | 116 | uint64_t got = s1->got->sh_addr + 16; |
| 117 | uint64_t off = (got >> 12) - (plt >> 12); | 117 | uint64_t off = (got >> 12) - (plt >> 12); |
| 118 | if ((off + ((uint32_t)1 << 20)) >> 21) | 118 | if ((off + ((uint32_t)1 << 20)) >> 21) |
| 119 | tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt); | 119 | tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt); |
| @@ -129,6 +129,7 @@ ST_FUNC void relocate_plt(TCCState *s1) · 9 unmodified lines | |||
| 129 | write32le(p + 24, 0xd503201f); // nop | 129 | write32le(p + 24, 0xd503201f); // nop |
| 130 | write32le(p + 28, 0xd503201f); // nop | 130 | write32le(p + 28, 0xd503201f); // nop |
| 131 | p += 32; | 131 | p += 32; |
| 132 | got = s1->got->sh_addr; | ||
| 132 | while (p < p_end) { | 133 | while (p < p_end) { |
| 133 | uint64_t pc = plt + (p - s1->plt->data); | 134 | uint64_t pc = plt + (p - s1->plt->data); |
| 134 | uint64_t addr = got + read64le(p); | 135 | uint64_t addr = got + read64le(p); |
| @@ -145,6 +146,18 @@ ST_FUNC void relocate_plt(TCCState *s1) · 10 unmodified lines | |||
| 145 | p += 16; | 146 | p += 16; |
| 146 | } | 147 | } |
| 147 | } | 148 | } |
| 149 | |||
| 150 | if (s1->got->relocplt) { | ||
| 151 | int mem = s1->output_type == TCC_OUTPUT_MEMORY; | ||
| 152 | ElfW_Rel *rel; | ||
| 153 | |||
| 154 | p = s1->got->data; | ||
| 155 | for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) { | ||
| 156 | int sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 157 | ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 158 | write64le(p + rel->r_offset, mem ? sym->st_value : s1->plt->sh_addr); | ||
| 159 | } | ||
| 160 | } | ||
| 148 | } | 161 | } |
| 149 | 162 | ||
| 150 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) | 163 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | |||
| 16 | #define ELF_PAGE_SIZE 0x1000 | 16 | #define ELF_PAGE_SIZE 0x1000 |
| 17 | 17 | ||
| 18 | #define PCRELATIVE_DLLPLT 0 | 18 | #define PCRELATIVE_DLLPLT 0 |
| 19 | #define RELOCATE_DLLPLT 0 | 19 | #define RELOCATE_DLLPLT 1 |
| 20 | 20 | ||
| 21 | #else /* !TARGET_DEFS_ONLY */ | 21 | #else /* !TARGET_DEFS_ONLY */ |
| 22 | 22 | ||
| @@ -121,7 +121,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_ · 98 unmodified lines | |||
| 121 | /* The PLT slot refers to the relocation entry it needs via offset. | 121 | /* The PLT slot refers to the relocation entry it needs via offset. |
| 122 | The reloc entry is created below, so its offset is the current | 122 | The reloc entry is created below, so its offset is the current |
| 123 | data_offset */ | 123 | data_offset */ |
| 124 | relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; | 124 | relofs = s1->got->relocplt ? s1->got->relocplt->data_offset : 0; |
| 125 | 125 | ||
| 126 | /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ | 126 | /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ |
| 127 | p = section_ptr_add(plt, 16); | 127 | p = section_ptr_add(plt, 16); |
| @@ -129,7 +129,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_ · 1 unmodified line | |||
| 129 | p[1] = modrm; | 129 | p[1] = modrm; |
| 130 | write32le(p + 2, got_offset); | 130 | write32le(p + 2, got_offset); |
| 131 | p[6] = 0x68; /* push $xxx */ | 131 | p[6] = 0x68; /* push $xxx */ |
| 132 | write32le(p + 7, relofs); | 132 | write32le(p + 7, relofs - sizeof (ElfW_Rel)); |
| 133 | p[11] = 0xe9; /* jmp plt_start */ | 133 | p[11] = 0xe9; /* jmp plt_start */ |
| 134 | write32le(p + 12, -(plt->data_offset)); | 134 | write32le(p + 12, -(plt->data_offset)); |
| 135 | return plt_offset; | 135 | return plt_offset; |
| @@ -147,7 +147,7 @@ ST_FUNC void relocate_plt(TCCState *s1) · 11 unmodified lines | |||
| 147 | p = s1->plt->data; | 147 | p = s1->plt->data; |
| 148 | p_end = p + s1->plt->data_offset; | 148 | p_end = p + s1->plt->data_offset; |
| 149 | 149 | ||
| 150 | if (p < p_end) { | 150 | if (s1->output_type != TCC_OUTPUT_DLL && p < p_end) { |
| 151 | add32le(p + 2, s1->got->sh_addr); | 151 | add32le(p + 2, s1->got->sh_addr); |
| 152 | add32le(p + 8, s1->got->sh_addr); | 152 | add32le(p + 8, s1->got->sh_addr); |
| 153 | p += 16; | 153 | p += 16; |
| @@ -156,6 +156,20 @@ ST_FUNC void relocate_plt(TCCState *s1) · 2 unmodified lines | |||
| 156 | p += 16; | 156 | p += 16; |
| 157 | } | 157 | } |
| 158 | } | 158 | } |
| 159 | |||
| 160 | if (s1->got->relocplt) { | ||
| 161 | int mem = s1->output_type == TCC_OUTPUT_MEMORY; | ||
| 162 | ElfW_Rel *rel; | ||
| 163 | int x = s1->plt->sh_addr + 16 + 6; | ||
| 164 | |||
| 165 | p = s1->got->data; | ||
| 166 | for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) { | ||
| 167 | int sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 168 | ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 169 | write32le(p + rel->r_offset, mem ? sym->st_value : x); | ||
| 170 | x += 16; | ||
| 171 | } | ||
| 172 | } | ||
| 159 | } | 173 | } |
| 160 | #endif | 174 | #endif |
| 161 | 175 | ||
| @@ -1153,7 +1153,8 @@ void __attribute__((destructor)) __bound_exit(void) · 1152 unmodified lines | |||
| 1153 | dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__); | 1153 | dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__); |
| 1154 | 1154 | ||
| 1155 | if (inited) { | 1155 | if (inited) { |
| 1156 | #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OpenBSD__) && !defined TCC_MUSL | 1156 | #if !defined(_WIN32) && !defined(__APPLE__) && !defined TCC_MUSL && \ |
| 1157 | !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__) | ||
| 1157 | if (print_heap) { | 1158 | if (print_heap) { |
| 1158 | extern void __libc_freeres (void); | 1159 | extern void __libc_freeres (void); |
| 1159 | __libc_freeres (); | 1160 | __libc_freeres (); |
| @@ -153,6 +153,18 @@ ST_FUNC void relocate_plt(TCCState *s1) · 152 unmodified lines | |||
| 153 | p += 16; | 153 | p += 16; |
| 154 | } | 154 | } |
| 155 | } | 155 | } |
| 156 | |||
| 157 | if (s1->got->relocplt) { | ||
| 158 | int mem = s1->output_type == TCC_OUTPUT_MEMORY; | ||
| 159 | ElfW_Rel *rel; | ||
| 160 | |||
| 161 | p = s1->got->data; | ||
| 162 | for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) { | ||
| 163 | int sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 164 | ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 165 | write64le(p + rel->r_offset, mem ? sym->st_value + rel->r_addend : s1->plt->sh_addr); | ||
| 166 | } | ||
| 167 | } | ||
| 156 | } | 168 | } |
| 157 | 169 | ||
| 158 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, | 170 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, |
| @@ -397,6 +397,7 @@ extern long double strtold (const char *__nptr, char **__endptr); · 396 unmodified lines | |||
| 397 | # define ElfW_Rel ElfW(Rela) | 397 | # define ElfW_Rel ElfW(Rela) |
| 398 | # define SHT_RELX SHT_RELA | 398 | # define SHT_RELX SHT_RELA |
| 399 | # define REL_SECTION_FMT ".rela%s" | 399 | # define REL_SECTION_FMT ".rela%s" |
| 400 | # define RELPLT_SECTION_FMT ".rel.plt" | ||
| 400 | #else | 401 | #else |
| 401 | # define ELFCLASSW ELFCLASS32 | 402 | # define ELFCLASSW ELFCLASS32 |
| 402 | # define ElfW(type) Elf##32##_##type | 403 | # define ElfW(type) Elf##32##_##type |
| @@ -404,6 +405,7 @@ extern long double strtold (const char *__nptr, char **__endptr); · 1 unmodified line | |||
| 404 | # define ElfW_Rel ElfW(Rel) | 405 | # define ElfW_Rel ElfW(Rel) |
| 405 | # define SHT_RELX SHT_REL | 406 | # define SHT_RELX SHT_REL |
| 406 | # define REL_SECTION_FMT ".rel%s" | 407 | # define REL_SECTION_FMT ".rel%s" |
| 408 | # define RELPLT_SECTION_FMT ".rel.plt" | ||
| 407 | #endif | 409 | #endif |
| 408 | /* target address type */ | 410 | /* target address type */ |
| 409 | #define addr_t ElfW(Addr) | 411 | #define addr_t ElfW(Addr) |
| @@ -565,6 +567,7 @@ typedef struct Section { · 155 unmodified lines | |||
| 565 | struct Section *reloc; /* corresponding section for relocation, if any */ | 567 | struct Section *reloc; /* corresponding section for relocation, if any */ |
| 566 | struct Section *hash; /* hash table for symbols */ | 568 | struct Section *hash; /* hash table for symbols */ |
| 567 | struct Section *prev; /* previous section on section stack */ | 569 | struct Section *prev; /* previous section on section stack */ |
| 570 | struct Section *relocplt;/* reloc with JMP_SLOTs */ | ||
| 568 | char name[1]; /* section name */ | 571 | char name[1]; /* section name */ |
| 569 | } Section; | 572 | } Section; |
| 570 | 573 | ||
| @@ -735,18 +735,25 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset, · 734 unmodified lines | |||
| 735 | char buf[256]; | 735 | char buf[256]; |
| 736 | Section *sr; | 736 | Section *sr; |
| 737 | ElfW_Rel *rel; | 737 | ElfW_Rel *rel; |
| 738 | int jmp_slot = type == R_JMP_SLOT; | ||
| 738 | 739 | ||
| 739 | sr = s->reloc; | 740 | sr = jmp_slot ? s->relocplt : s->reloc; |
| 740 | if (!sr) { | 741 | if (!sr) { |
| 741 | /* if no relocation section, create it */ | 742 | /* if no relocation section, create it */ |
| 742 | snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); | 743 | if (jmp_slot) |
| 744 | snprintf(buf, sizeof(buf), RELPLT_SECTION_FMT); | ||
| 745 | else | ||
| 746 | snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); | ||
| 743 | /* if the symtab is allocated, then we consider the relocation | 747 | /* if the symtab is allocated, then we consider the relocation |
| 744 | are also */ | 748 | are also */ |
| 745 | sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags); | 749 | sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags); |
| 746 | sr->sh_entsize = sizeof(ElfW_Rel); | 750 | sr->sh_entsize = sizeof(ElfW_Rel); |
| 747 | sr->link = symtab; | 751 | sr->link = symtab; |
| 748 | sr->sh_info = s->sh_num; | 752 | sr->sh_info = s->sh_num; |
| 749 | s->reloc = sr; | 753 | if (jmp_slot) |
| 754 | s->relocplt = sr; | ||
| 755 | else | ||
| 756 | s->reloc = sr; | ||
| 750 | } | 757 | } |
| 751 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); | 758 | rel = section_ptr_add(sr, sizeof(ElfW_Rel)); |
| 752 | rel->r_offset = offset; | 759 | rel->r_offset = offset; |
| @@ -1164,7 +1171,7 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type, · 411 unmodified lines | |||
| 1164 | } | 1171 | } |
| 1165 | 1172 | ||
| 1166 | /* build GOT and PLT entries */ | 1173 | /* build GOT and PLT entries */ |
| 1167 | ST_FUNC void build_got_entries(TCCState *s1) | 1174 | static void build_got_entries_pass(TCCState *s1, int pass) |
| 1168 | { | 1175 | { |
| 1169 | Section *s; | 1176 | Section *s; |
| 1170 | ElfW_Rel *rel; | 1177 | ElfW_Rel *rel; |
| @@ -1235,6 +1242,8 @@ ST_FUNC void build_got_entries(TCCState *s1) · 64 unmodified lines | |||
| 1235 | (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || | 1242 | (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || |
| 1236 | ELFW(ST_BIND)(sym->st_info) == STB_LOCAL || | 1243 | ELFW(ST_BIND)(sym->st_info) == STB_LOCAL || |
| 1237 | s1->output_type == TCC_OUTPUT_EXE)) { | 1244 | s1->output_type == TCC_OUTPUT_EXE)) { |
| 1245 | if (pass == 0) | ||
| 1246 | continue; | ||
| 1238 | rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); | 1247 | rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); |
| 1239 | continue; | 1248 | continue; |
| 1240 | } | 1249 | } |
| @@ -1248,6 +1257,11 @@ ST_FUNC void build_got_entries(TCCState *s1) · 7 unmodified lines | |||
| 1248 | } else | 1257 | } else |
| 1249 | reloc_type = R_GLOB_DAT; | 1258 | reloc_type = R_GLOB_DAT; |
| 1250 | 1259 | ||
| 1260 | |||
| 1261 | if ((pass == 0 && reloc_type == R_GLOB_DAT) || | ||
| 1262 | (pass == 1 && reloc_type == R_JMP_SLOT)) | ||
| 1263 | continue; | ||
| 1264 | |||
| 1251 | if (!s1->got) | 1265 | if (!s1->got) |
| 1252 | build_got(s1); | 1266 | build_got(s1); |
| 1253 | 1267 | ||
| @@ -1261,6 +1275,16 @@ ST_FUNC void build_got_entries(TCCState *s1) · 7 unmodified lines | |||
| 1261 | } | 1275 | } |
| 1262 | } | 1276 | } |
| 1263 | } | 1277 | } |
| 1278 | |||
| 1279 | ST_FUNC void build_got_entries(TCCState *s1) | ||
| 1280 | { | ||
| 1281 | int i; | ||
| 1282 | |||
| 1283 | /* Two passes because R_JMP_SLOT should become first. | ||
| 1284 | Some targets (arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */ | ||
| 1285 | for (i = 0; i < 2; i++) | ||
| 1286 | build_got_entries_pass(s1, i); | ||
| 1287 | } | ||
| 1264 | #endif | 1288 | #endif |
| 1265 | 1289 | ||
| 1266 | ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs) | 1290 | ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs) |
| @@ -1801,7 +1825,7 @@ struct dyn_inf { · 534 unmodified lines | |||
| 1801 | unsigned long data_offset; | 1825 | unsigned long data_offset; |
| 1802 | addr_t rel_addr; | 1826 | addr_t rel_addr; |
| 1803 | addr_t rel_size; | 1827 | addr_t rel_size; |
| 1804 | #if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel | 1828 | #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel) |
| 1805 | addr_t bss_addr; | 1829 | addr_t bss_addr; |
| 1806 | addr_t bss_size; | 1830 | addr_t bss_size; |
| 1807 | #endif | 1831 | #endif |
| @@ -1861,11 +1885,13 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 53 unmodified lines | |||
| 1861 | 1885 | ||
| 1862 | /* dynamic relocation table information, for .dynamic section */ | 1886 | /* dynamic relocation table information, for .dynamic section */ |
| 1863 | dyninf->rel_addr = dyninf->rel_size = 0; | 1887 | dyninf->rel_addr = dyninf->rel_size = 0; |
| 1864 | #if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel | 1888 | #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel) |
| 1865 | dyninf->bss_addr = dyninf->bss_size = 0; | 1889 | dyninf->bss_addr = dyninf->bss_size = 0; |
| 1866 | #endif | 1890 | #endif |
| 1867 | 1891 | ||
| 1868 | for(j = 0; j < (phnum == 6 ? 3 : 2); j++) { | 1892 | for(j = 0; j < (phnum == 6 ? 3 : 2); j++) { |
| 1893 | Section *relocplt = s1->got ? s1->got->relocplt : NULL; | ||
| 1894 | |||
| 1869 | ph->p_type = j == 2 ? PT_TLS : PT_LOAD; | 1895 | ph->p_type = j == 2 ? PT_TLS : PT_LOAD; |
| 1870 | if (j == 0) | 1896 | if (j == 0) |
| 1871 | ph->p_flags = PF_R | PF_X; | 1897 | ph->p_flags = PF_R | PF_X; |
| @@ -1878,7 +1904,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 6 unmodified lines | |||
| 1878 | info about the layout. We do the following ordering: interp, | 1904 | info about the layout. We do the following ordering: interp, |
| 1879 | symbol tables, relocations, progbits, nobits */ | 1905 | symbol tables, relocations, progbits, nobits */ |
| 1880 | /* XXX: do faster and simpler sorting */ | 1906 | /* XXX: do faster and simpler sorting */ |
| 1881 | for(k = 0; k < 5; k++) { | 1907 | for(k = 0; k < 6; k++) { |
| 1882 | for(i = 1; i < s1->nb_sections; i++) { | 1908 | for(i = 1; i < s1->nb_sections; i++) { |
| 1883 | s = s1->sections[i]; | 1909 | s = s1->sections[i]; |
| 1884 | /* compute if section should be included */ | 1910 | /* compute if section should be included */ |
| @@ -1905,13 +1931,15 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 20 unmodified lines | |||
| 1905 | if (k != 1) | 1931 | if (k != 1) |
| 1906 | continue; | 1932 | continue; |
| 1907 | } else if (s->sh_type == SHT_RELX) { | 1933 | } else if (s->sh_type == SHT_RELX) { |
| 1908 | if (k != 2) | 1934 | if (k != 2 && s != relocplt) |
| 1935 | continue; | ||
| 1936 | else if (k != 3 && s == relocplt) | ||
| 1909 | continue; | 1937 | continue; |
| 1910 | } else if (s->sh_type == SHT_NOBITS) { | 1938 | } else if (s->sh_type == SHT_NOBITS) { |
| 1911 | if (k != 4) | 1939 | if (k != 5) |
| 1912 | continue; | 1940 | continue; |
| 1913 | } else { | 1941 | } else { |
| 1914 | if (k != 3) | 1942 | if (k != 4) |
| 1915 | continue; | 1943 | continue; |
| 1916 | } | 1944 | } |
| 1917 | sec_order[sh_order_index++] = i; | 1945 | sec_order[sh_order_index++] = i; |
| @@ -1931,8 +1959,8 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum, · 13 unmodified lines | |||
| 1931 | ph->p_paddr = ph->p_vaddr; | 1959 | ph->p_paddr = ph->p_vaddr; |
| 1932 | } | 1960 | } |
| 1933 | /* update dynamic relocation infos */ | 1961 | /* update dynamic relocation infos */ |
| 1934 | if (s->sh_type == SHT_RELX) { | 1962 | if (s->sh_type == SHT_RELX && s != relocplt) { |
| 1935 | #if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel | 1963 | #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel) |
| 1936 | if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { | 1964 | if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { |
| 1937 | dyninf->rel_addr = addr; | 1965 | dyninf->rel_addr = addr; |
| 1938 | dyninf->rel_size += s->sh_size; /* XXX only first rel. */ | 1966 | dyninf->rel_size += s->sh_size; /* XXX only first rel. */ |
| @@ -2079,16 +2107,17 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 140 unmodified lines | |||
| 2079 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); | 2107 | put_dt(dynamic, DT_RELA, dyninf->rel_addr); |
| 2080 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); | 2108 | put_dt(dynamic, DT_RELASZ, dyninf->rel_size); |
| 2081 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); | 2109 | put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); |
| 2082 | #if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD | 2110 | if (s1->got && s1->got->relocplt) { |
| 2083 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); | 2111 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); |
| 2084 | put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); | 2112 | put_dt(dynamic, DT_PLTRELSZ, s1->got->relocplt->data_offset); |
| 2085 | put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); | 2113 | put_dt(dynamic, DT_JMPREL, s1->got->relocplt->sh_addr); |
| 2086 | put_dt(dynamic, DT_PLTREL, DT_RELA); | 2114 | put_dt(dynamic, DT_PLTREL, DT_RELA); |
| 2087 | put_dt(dynamic, DT_BIND_NOW, 1); /* Dirty hack */ | 2115 | } |
| 2088 | #endif | 2116 | put_dt(dynamic, DT_RELACOUNT, 0); |
| 2089 | #else | 2117 | #else |
| 2090 | #if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel | 2118 | #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel) |
| 2091 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); | 2119 | if (s1->got) |
| 2120 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); | ||
| 2092 | put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); | 2121 | put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); |
| 2093 | put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); | 2122 | put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); |
| 2094 | put_dt(dynamic, DT_PLTREL, DT_REL); | 2123 | put_dt(dynamic, DT_PLTREL, DT_REL); |
| @@ -2098,11 +2127,18 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf) · 3 unmodified lines | |||
| 2098 | put_dt(dynamic, DT_REL, dyninf->rel_addr); | 2127 | put_dt(dynamic, DT_REL, dyninf->rel_addr); |
| 2099 | put_dt(dynamic, DT_RELSZ, dyninf->rel_size); | 2128 | put_dt(dynamic, DT_RELSZ, dyninf->rel_size); |
| 2100 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); | 2129 | put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); |
| 2130 | if (s1->got && s1->got->relocplt) { | ||
| 2131 | put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); | ||
| 2132 | put_dt(dynamic, DT_PLTRELSZ, s1->got->relocplt->data_offset); | ||
| 2133 | put_dt(dynamic, DT_JMPREL, s1->got->relocplt->sh_addr); | ||
| 2134 | put_dt(dynamic, DT_PLTREL, DT_REL); | ||
| 2135 | } | ||
| 2136 | put_dt(dynamic, DT_RELCOUNT, 0); | ||
| 2101 | #endif | 2137 | #endif |
| 2102 | #endif | 2138 | #endif |
| 2103 | if (versym_section) | 2139 | if (versym_section && verneed_section) { |
| 2140 | /* The dynamic linker can not handle VERSYM without VERNEED */ | ||
| 2104 | put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); | 2141 | put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); |
| 2105 | if (verneed_section) { | ||
| 2106 | put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); | 2142 | put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); |
| 2107 | put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); | 2143 | put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); |
| 2108 | } | 2144 | } |
| @@ -2406,10 +2442,12 @@ static void create_arm_attribute_section(TCCState *s1) · 297 unmodified lines | |||
| 2406 | } | 2442 | } |
| 2407 | #endif | 2443 | #endif |
| 2408 | 2444 | ||
| 2409 | #if TARGETOS_OpenBSD | 2445 | #if TARGETOS_OpenBSD || TARGETOS_NetBSD |
| 2410 | static Section *create_openbsd_note_section(TCCState *s1) | 2446 | static Section *create_bsd_note_section(TCCState *s1, |
| 2447 | const char *name, | ||
| 2448 | const char *value) | ||
| 2411 | { | 2449 | { |
| 2412 | Section *s = find_section (s1, ".note.openbsd.ident"); | 2450 | Section *s = find_section (s1, name); |
| 2413 | 2451 | ||
| 2414 | if (s->data_offset == 0) { | 2452 | if (s->data_offset == 0) { |
| 2415 | unsigned char *ptr = section_ptr_add(s, sizeof(ElfW(Nhdr)) + 8 + 4); | 2453 | unsigned char *ptr = section_ptr_add(s, sizeof(ElfW(Nhdr)) + 8 + 4); |
| @@ -2419,7 +2457,7 @@ static Section *create_openbsd_note_section(TCCState *s1) · 3 unmodified lines | |||
| 2419 | note->n_namesz = 8; | 2457 | note->n_namesz = 8; |
| 2420 | note->n_descsz = 4; | 2458 | note->n_descsz = 4; |
| 2421 | note->n_type = ELF_NOTE_OS_GNU; | 2459 | note->n_type = ELF_NOTE_OS_GNU; |
| 2422 | strcpy (ptr + sizeof(ElfW(Nhdr)), "OpenBSD"); | 2460 | strcpy (ptr + sizeof(ElfW(Nhdr)), value); |
| 2423 | } | 2461 | } |
| 2424 | return s; | 2462 | return s; |
| 2425 | } | 2463 | } |
| @@ -2441,7 +2479,11 @@ static int elf_output_file(TCCState *s1, const char *filename) · 15 unmodified lines | |||
| 2441 | #endif | 2479 | #endif |
| 2442 | #if TARGETOS_OpenBSD | 2480 | #if TARGETOS_OpenBSD |
| 2443 | if (file_type != TCC_OUTPUT_OBJ) | 2481 | if (file_type != TCC_OUTPUT_OBJ) |
| 2444 | note = create_openbsd_note_section (s1); | 2482 | note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD"); |
| 2483 | #endif | ||
| 2484 | #if TARGETOS_NetBSD | ||
| 2485 | if (file_type != TCC_OUTPUT_OBJ) | ||
| 2486 | note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD"); | ||
| 2445 | #endif | 2487 | #endif |
| 2446 | 2488 | ||
| 2447 | s1->nb_errors = 0; | 2489 | s1->nb_errors = 0; |
| @@ -2814,8 +2856,13 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, · 366 unmodified lines | |||
| 2814 | sm_table[i].new_section = 1; | 2856 | sm_table[i].new_section = 1; |
| 2815 | found: | 2857 | found: |
| 2816 | if (sh->sh_type != s->sh_type) { | 2858 | if (sh->sh_type != s->sh_type) { |
| 2817 | tcc_error_noabort("invalid section type"); | 2859 | #if TARGETOS_OpenBSD |
| 2818 | goto fail; | 2860 | if (strcmp (s->name, ".eh_frame") || sh->sh_type != SHT_PROGBITS) |
| 2861 | #endif | ||
| 2862 | { | ||
| 2863 | tcc_error_noabort("invalid section type"); | ||
| 2864 | goto fail; | ||
| 2865 | } | ||
| 2819 | } | 2866 | } |
| 2820 | /* align start of section */ | 2867 | /* align start of section */ |
| 2821 | s->data_offset += -s->data_offset & (sh->sh_addralign - 1); | 2868 | s->data_offset += -s->data_offset & (sh->sh_addralign - 1); |
| @@ -61,6 +61,9 @@ endif · 60 unmodified lines | |||
| 61 | ifeq ($(CC_NAME),msvc) | 61 | ifeq ($(CC_NAME),msvc) |
| 62 | test.ref abitest : CC = gcc | 62 | test.ref abitest : CC = gcc |
| 63 | endif | 63 | endif |
| 64 | ifeq ($(TARGETOS),OpenBSD) | ||
| 65 | dlltest: CFLAGS+=-fno-stack-protector | ||
| 66 | endif | ||
| 64 | 67 | ||
| 65 | RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) | 68 | RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) |
| 66 | DISAS = objdump -d | 69 | DISAS = objdump -d |
| @@ -48,6 +48,10 @@ ifeq (-$(CONFIG_WIN32)-,-yes-) · 47 unmodified lines | |||
| 48 | SKIP += 106_pthread.test # No pthread support | 48 | SKIP += 106_pthread.test # No pthread support |
| 49 | SKIP += 114_bound_signal.test # No pthread support | 49 | SKIP += 114_bound_signal.test # No pthread support |
| 50 | endif | 50 | endif |
| 51 | ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS))) | ||
| 52 | SKIP += 106_pthread.test # no pthread_condattr_setpshared | ||
| 53 | SKIP += 114_bound_signal.test # libc problem signal/fork | ||
| 54 | endif | ||
| 51 | 55 | ||
| 52 | # Some tests might need arguments | 56 | # Some tests might need arguments |
| 53 | ARGS = | 57 | ARGS = |
| @@ -131,7 +131,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_ · 130 unmodified lines | |||
| 131 | /* The PLT slot refers to the relocation entry it needs via offset. | 131 | /* The PLT slot refers to the relocation entry it needs via offset. |
| 132 | The reloc entry is created below, so its offset is the current | 132 | The reloc entry is created below, so its offset is the current |
| 133 | data_offset */ | 133 | data_offset */ |
| 134 | relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; | 134 | relofs = s1->got->relocplt ? s1->got->relocplt->data_offset : 0; |
| 135 | 135 | ||
| 136 | /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ | 136 | /* Jump to GOT entry where ld.so initially put the address of ip + 4 */ |
| 137 | p = section_ptr_add(plt, 16); | 137 | p = section_ptr_add(plt, 16); |
| @@ -140,7 +140,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_ · 2 unmodified lines | |||
| 140 | write32le(p + 2, got_offset); | 140 | write32le(p + 2, got_offset); |
| 141 | p[6] = 0x68; /* push $xxx */ | 141 | p[6] = 0x68; /* push $xxx */ |
| 142 | /* On x86-64, the relocation is referred to by _index_ */ | 142 | /* On x86-64, the relocation is referred to by _index_ */ |
| 143 | write32le(p + 7, relofs / sizeof (ElfW_Rel)); | 143 | write32le(p + 7, relofs / sizeof (ElfW_Rel) - 1); |
| 144 | p[11] = 0xe9; /* jmp plt_start */ | 144 | p[11] = 0xe9; /* jmp plt_start */ |
| 145 | write32le(p + 12, -(plt->data_offset)); | 145 | write32le(p + 12, -(plt->data_offset)); |
| 146 | return plt_offset; | 146 | return plt_offset; |
| @@ -168,6 +168,20 @@ ST_FUNC void relocate_plt(TCCState *s1) · 21 unmodified lines | |||
| 168 | p += 16; | 168 | p += 16; |
| 169 | } | 169 | } |
| 170 | } | 170 | } |
| 171 | |||
| 172 | if (s1->got->relocplt) { | ||
| 173 | int mem = s1->output_type == TCC_OUTPUT_MEMORY; | ||
| 174 | ElfW_Rel *rel; | ||
| 175 | int x = s1->plt->sh_addr + 16 + 6; | ||
| 176 | |||
| 177 | p = s1->got->data; | ||
| 178 | for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) { | ||
| 179 | int sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 180 | ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 181 | write64le(p + rel->r_offset, mem ? sym->st_value : x); | ||
| 182 | x += 16; | ||
| 183 | } | ||
| 184 | } | ||
| 171 | } | 185 | } |
| 172 | #endif | 186 | #endif |
| 173 | #endif | 187 | #endif |