lazy binding

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
This commit is contained in:
herman ten brugge 2020-12-18 15:24:32 +01:00
parent e2e62fcb8b
commit 50b4f320dc
10 changed files with 162 additions and 39 deletions

View File

@ -145,7 +145,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
if (p < p_end) { if (p < p_end) {
int x = s1->got->sh_addr - s1->plt->sh_addr - 12; int x = s1->got->sh_addr - s1->plt->sh_addr - 12;
write32le(s1->plt->data + 16, x - 16); write32le(s1->plt->data + 16, x - 4);
p += 20; p += 20;
while (p < p_end) { while (p < p_end) {
unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4; unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4;
@ -157,6 +157,18 @@ ST_FUNC void relocate_plt(TCCState *s1)
p += 12; p += 12;
} }
} }
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
ElfW_Rel *rel;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write32le(p + rel->r_offset, mem ? sym->st_value : s1->plt->sh_addr);
}
}
} }
#endif #endif

View File

@ -113,7 +113,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
if (p < p_end) { if (p < p_end) {
uint64_t plt = s1->plt->sh_addr; uint64_t plt = s1->plt->sh_addr;
uint64_t got = s1->got->sh_addr; uint64_t got = s1->got->sh_addr + 16;
uint64_t off = (got >> 12) - (plt >> 12); uint64_t off = (got >> 12) - (plt >> 12);
if ((off + ((uint32_t)1 << 20)) >> 21) if ((off + ((uint32_t)1 << 20)) >> 21)
tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", (long)off, (long)got, (long)plt); 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)
write32le(p + 24, 0xd503201f); // nop write32le(p + 24, 0xd503201f); // nop
write32le(p + 28, 0xd503201f); // nop write32le(p + 28, 0xd503201f); // nop
p += 32; p += 32;
got = s1->got->sh_addr;
while (p < p_end) { while (p < p_end) {
uint64_t pc = plt + (p - s1->plt->data); uint64_t pc = plt + (p - s1->plt->data);
uint64_t addr = got + read64le(p); uint64_t addr = got + read64le(p);
@ -145,6 +146,18 @@ ST_FUNC void relocate_plt(TCCState *s1)
p += 16; p += 16;
} }
} }
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
ElfW_Rel *rel;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write64le(p + rel->r_offset, mem ? sym->st_value : s1->plt->sh_addr);
}
}
} }
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val) void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)

View File

@ -16,7 +16,7 @@
#define ELF_PAGE_SIZE 0x1000 #define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 0 #define PCRELATIVE_DLLPLT 0
#define RELOCATE_DLLPLT 0 #define RELOCATE_DLLPLT 1
#else /* !TARGET_DEFS_ONLY */ #else /* !TARGET_DEFS_ONLY */
@ -121,7 +121,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
/* The PLT slot refers to the relocation entry it needs via offset. /* The PLT slot refers to the relocation entry it needs via offset.
The reloc entry is created below, so its offset is the current The reloc entry is created below, so its offset is the current
data_offset */ data_offset */
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; relofs = s1->got->relocplt ? s1->got->relocplt->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */ /* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
@ -129,7 +129,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
p[1] = modrm; p[1] = modrm;
write32le(p + 2, got_offset); write32le(p + 2, got_offset);
p[6] = 0x68; /* push $xxx */ p[6] = 0x68; /* push $xxx */
write32le(p + 7, relofs); write32le(p + 7, relofs - sizeof (ElfW_Rel));
p[11] = 0xe9; /* jmp plt_start */ p[11] = 0xe9; /* jmp plt_start */
write32le(p + 12, -(plt->data_offset)); write32le(p + 12, -(plt->data_offset));
return plt_offset; return plt_offset;
@ -147,7 +147,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
p = s1->plt->data; p = s1->plt->data;
p_end = p + s1->plt->data_offset; p_end = p + s1->plt->data_offset;
if (p < p_end) { if (s1->output_type != TCC_OUTPUT_DLL && p < p_end) {
add32le(p + 2, s1->got->sh_addr); add32le(p + 2, s1->got->sh_addr);
add32le(p + 8, s1->got->sh_addr); add32le(p + 8, s1->got->sh_addr);
p += 16; p += 16;
@ -156,6 +156,20 @@ ST_FUNC void relocate_plt(TCCState *s1)
p += 16; p += 16;
} }
} }
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
ElfW_Rel *rel;
int x = s1->plt->sh_addr + 16 + 6;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write32le(p + rel->r_offset, mem ? sym->st_value : x);
x += 16;
}
}
} }
#endif #endif

View File

@ -1153,7 +1153,8 @@ void __attribute__((destructor)) __bound_exit(void)
dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__); dprintf(stderr, "%s, %s():\n", __FILE__, __FUNCTION__);
if (inited) { if (inited) {
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OpenBSD__) && !defined TCC_MUSL #if !defined(_WIN32) && !defined(__APPLE__) && !defined TCC_MUSL && \
!defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
if (print_heap) { if (print_heap) {
extern void __libc_freeres (void); extern void __libc_freeres (void);
__libc_freeres (); __libc_freeres ();

View File

@ -153,6 +153,18 @@ ST_FUNC void relocate_plt(TCCState *s1)
p += 16; p += 16;
} }
} }
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
ElfW_Rel *rel;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write64le(p + rel->r_offset, mem ? sym->st_value + rel->r_addend : s1->plt->sh_addr);
}
}
} }
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,

3
tcc.h
View File

@ -397,6 +397,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ElfW_Rel ElfW(Rela) # define ElfW_Rel ElfW(Rela)
# define SHT_RELX SHT_RELA # define SHT_RELX SHT_RELA
# define REL_SECTION_FMT ".rela%s" # define REL_SECTION_FMT ".rela%s"
# define RELPLT_SECTION_FMT ".rel.plt"
#else #else
# define ELFCLASSW ELFCLASS32 # define ELFCLASSW ELFCLASS32
# define ElfW(type) Elf##32##_##type # define ElfW(type) Elf##32##_##type
@ -404,6 +405,7 @@ extern long double strtold (const char *__nptr, char **__endptr);
# define ElfW_Rel ElfW(Rel) # define ElfW_Rel ElfW(Rel)
# define SHT_RELX SHT_REL # define SHT_RELX SHT_REL
# define REL_SECTION_FMT ".rel%s" # define REL_SECTION_FMT ".rel%s"
# define RELPLT_SECTION_FMT ".rel.plt"
#endif #endif
/* target address type */ /* target address type */
#define addr_t ElfW(Addr) #define addr_t ElfW(Addr)
@ -565,6 +567,7 @@ typedef struct Section {
struct Section *reloc; /* corresponding section for relocation, if any */ struct Section *reloc; /* corresponding section for relocation, if any */
struct Section *hash; /* hash table for symbols */ struct Section *hash; /* hash table for symbols */
struct Section *prev; /* previous section on section stack */ struct Section *prev; /* previous section on section stack */
struct Section *relocplt;/* reloc with JMP_SLOTs */
char name[1]; /* section name */ char name[1]; /* section name */
} Section; } Section;

107
tccelf.c
View File

@ -735,18 +735,25 @@ ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
char buf[256]; char buf[256];
Section *sr; Section *sr;
ElfW_Rel *rel; ElfW_Rel *rel;
int jmp_slot = type == R_JMP_SLOT;
sr = s->reloc; sr = jmp_slot ? s->relocplt : s->reloc;
if (!sr) { if (!sr) {
/* if no relocation section, create it */ /* if no relocation section, create it */
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name); if (jmp_slot)
snprintf(buf, sizeof(buf), RELPLT_SECTION_FMT);
else
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
/* if the symtab is allocated, then we consider the relocation /* if the symtab is allocated, then we consider the relocation
are also */ are also */
sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags); sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags);
sr->sh_entsize = sizeof(ElfW_Rel); sr->sh_entsize = sizeof(ElfW_Rel);
sr->link = symtab; sr->link = symtab;
sr->sh_info = s->sh_num; sr->sh_info = s->sh_num;
s->reloc = sr; if (jmp_slot)
s->relocplt = sr;
else
s->reloc = sr;
} }
rel = section_ptr_add(sr, sizeof(ElfW_Rel)); rel = section_ptr_add(sr, sizeof(ElfW_Rel));
rel->r_offset = offset; rel->r_offset = offset;
@ -1164,7 +1171,7 @@ static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
} }
/* build GOT and PLT entries */ /* build GOT and PLT entries */
ST_FUNC void build_got_entries(TCCState *s1) static void build_got_entries_pass(TCCState *s1, int pass)
{ {
Section *s; Section *s;
ElfW_Rel *rel; ElfW_Rel *rel;
@ -1235,6 +1242,8 @@ ST_FUNC void build_got_entries(TCCState *s1)
(ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
ELFW(ST_BIND)(sym->st_info) == STB_LOCAL || ELFW(ST_BIND)(sym->st_info) == STB_LOCAL ||
s1->output_type == TCC_OUTPUT_EXE)) { s1->output_type == TCC_OUTPUT_EXE)) {
if (pass == 0)
continue;
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
continue; continue;
} }
@ -1248,6 +1257,11 @@ ST_FUNC void build_got_entries(TCCState *s1)
} else } else
reloc_type = R_GLOB_DAT; reloc_type = R_GLOB_DAT;
if ((pass == 0 && reloc_type == R_GLOB_DAT) ||
(pass == 1 && reloc_type == R_JMP_SLOT))
continue;
if (!s1->got) if (!s1->got)
build_got(s1); build_got(s1);
@ -1261,6 +1275,16 @@ ST_FUNC void build_got_entries(TCCState *s1)
} }
} }
} }
ST_FUNC void build_got_entries(TCCState *s1)
{
int i;
/* Two passes because R_JMP_SLOT should become first.
Some targets (arm, arm64) do not allow mixing R_JMP_SLOT and R_GLOB_DAT. */
for (i = 0; i < 2; i++)
build_got_entries_pass(s1, i);
}
#endif #endif
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs) ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs)
@ -1801,7 +1825,7 @@ struct dyn_inf {
unsigned long data_offset; unsigned long data_offset;
addr_t rel_addr; addr_t rel_addr;
addr_t rel_size; addr_t rel_size;
#if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel)
addr_t bss_addr; addr_t bss_addr;
addr_t bss_size; addr_t bss_size;
#endif #endif
@ -1861,11 +1885,13 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
/* dynamic relocation table information, for .dynamic section */ /* dynamic relocation table information, for .dynamic section */
dyninf->rel_addr = dyninf->rel_size = 0; dyninf->rel_addr = dyninf->rel_size = 0;
#if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel)
dyninf->bss_addr = dyninf->bss_size = 0; dyninf->bss_addr = dyninf->bss_size = 0;
#endif #endif
for(j = 0; j < (phnum == 6 ? 3 : 2); j++) { for(j = 0; j < (phnum == 6 ? 3 : 2); j++) {
Section *relocplt = s1->got ? s1->got->relocplt : NULL;
ph->p_type = j == 2 ? PT_TLS : PT_LOAD; ph->p_type = j == 2 ? PT_TLS : PT_LOAD;
if (j == 0) if (j == 0)
ph->p_flags = PF_R | PF_X; ph->p_flags = PF_R | PF_X;
@ -1878,7 +1904,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
info about the layout. We do the following ordering: interp, info about the layout. We do the following ordering: interp,
symbol tables, relocations, progbits, nobits */ symbol tables, relocations, progbits, nobits */
/* XXX: do faster and simpler sorting */ /* XXX: do faster and simpler sorting */
for(k = 0; k < 5; k++) { for(k = 0; k < 6; k++) {
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
/* compute if section should be included */ /* compute if section should be included */
@ -1905,13 +1931,15 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
if (k != 1) if (k != 1)
continue; continue;
} else if (s->sh_type == SHT_RELX) { } else if (s->sh_type == SHT_RELX) {
if (k != 2) if (k != 2 && s != relocplt)
continue;
else if (k != 3 && s == relocplt)
continue; continue;
} else if (s->sh_type == SHT_NOBITS) { } else if (s->sh_type == SHT_NOBITS) {
if (k != 4) if (k != 5)
continue; continue;
} else { } else {
if (k != 3) if (k != 4)
continue; continue;
} }
sec_order[sh_order_index++] = i; sec_order[sh_order_index++] = i;
@ -1931,8 +1959,8 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
ph->p_paddr = ph->p_vaddr; ph->p_paddr = ph->p_vaddr;
} }
/* update dynamic relocation infos */ /* update dynamic relocation infos */
if (s->sh_type == SHT_RELX) { if (s->sh_type == SHT_RELX && s != relocplt) {
#if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel)
if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { if (!strcmp(strsec->data + s->sh_name, ".rel.got")) {
dyninf->rel_addr = addr; dyninf->rel_addr = addr;
dyninf->rel_size += s->sh_size; /* XXX only first rel. */ dyninf->rel_size += s->sh_size; /* XXX only first rel. */
@ -2079,16 +2107,17 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_RELA, dyninf->rel_addr); put_dt(dynamic, DT_RELA, dyninf->rel_addr);
put_dt(dynamic, DT_RELASZ, dyninf->rel_size); put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
#if TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD if (s1->got && s1->got->relocplt) {
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); put_dt(dynamic, DT_PLTRELSZ, s1->got->relocplt->data_offset);
put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); put_dt(dynamic, DT_JMPREL, s1->got->relocplt->sh_addr);
put_dt(dynamic, DT_PLTREL, DT_RELA); put_dt(dynamic, DT_PLTREL, DT_RELA);
put_dt(dynamic, DT_BIND_NOW, 1); /* Dirty hack */ }
#endif put_dt(dynamic, DT_RELACOUNT, 0);
#else #else
#if TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel #if PTR_SIZE == 4 && (TARGETOS_FreeBSD || TARGETOS_FreeBSD_kernel)
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); if (s1->got)
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size); put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size);
put_dt(dynamic, DT_JMPREL, dyninf->rel_addr); put_dt(dynamic, DT_JMPREL, dyninf->rel_addr);
put_dt(dynamic, DT_PLTREL, DT_REL); put_dt(dynamic, DT_PLTREL, DT_REL);
@ -2098,11 +2127,18 @@ static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
put_dt(dynamic, DT_REL, dyninf->rel_addr); put_dt(dynamic, DT_REL, dyninf->rel_addr);
put_dt(dynamic, DT_RELSZ, dyninf->rel_size); put_dt(dynamic, DT_RELSZ, dyninf->rel_size);
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
if (s1->got && s1->got->relocplt) {
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, s1->got->relocplt->data_offset);
put_dt(dynamic, DT_JMPREL, s1->got->relocplt->sh_addr);
put_dt(dynamic, DT_PLTREL, DT_REL);
}
put_dt(dynamic, DT_RELCOUNT, 0);
#endif #endif
#endif #endif
if (versym_section) if (versym_section && verneed_section) {
/* The dynamic linker can not handle VERSYM without VERNEED */
put_dt(dynamic, DT_VERSYM, versym_section->sh_addr); put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
if (verneed_section) {
put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr); put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum); put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
} }
@ -2406,10 +2442,12 @@ static void create_arm_attribute_section(TCCState *s1)
} }
#endif #endif
#if TARGETOS_OpenBSD #if TARGETOS_OpenBSD || TARGETOS_NetBSD
static Section *create_openbsd_note_section(TCCState *s1) static Section *create_bsd_note_section(TCCState *s1,
const char *name,
const char *value)
{ {
Section *s = find_section (s1, ".note.openbsd.ident"); Section *s = find_section (s1, name);
if (s->data_offset == 0) { if (s->data_offset == 0) {
unsigned char *ptr = section_ptr_add(s, sizeof(ElfW(Nhdr)) + 8 + 4); unsigned char *ptr = section_ptr_add(s, sizeof(ElfW(Nhdr)) + 8 + 4);
@ -2419,7 +2457,7 @@ static Section *create_openbsd_note_section(TCCState *s1)
note->n_namesz = 8; note->n_namesz = 8;
note->n_descsz = 4; note->n_descsz = 4;
note->n_type = ELF_NOTE_OS_GNU; note->n_type = ELF_NOTE_OS_GNU;
strcpy (ptr + sizeof(ElfW(Nhdr)), "OpenBSD"); strcpy (ptr + sizeof(ElfW(Nhdr)), value);
} }
return s; return s;
} }
@ -2441,7 +2479,11 @@ static int elf_output_file(TCCState *s1, const char *filename)
#endif #endif
#if TARGETOS_OpenBSD #if TARGETOS_OpenBSD
if (file_type != TCC_OUTPUT_OBJ) if (file_type != TCC_OUTPUT_OBJ)
note = create_openbsd_note_section (s1); note = create_bsd_note_section (s1, ".note.openbsd.ident", "OpenBSD");
#endif
#if TARGETOS_NetBSD
if (file_type != TCC_OUTPUT_OBJ)
note = create_bsd_note_section (s1, ".note.netbsd.ident", "NetBSD");
#endif #endif
s1->nb_errors = 0; s1->nb_errors = 0;
@ -2814,8 +2856,13 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
sm_table[i].new_section = 1; sm_table[i].new_section = 1;
found: found:
if (sh->sh_type != s->sh_type) { if (sh->sh_type != s->sh_type) {
tcc_error_noabort("invalid section type"); #if TARGETOS_OpenBSD
goto fail; if (strcmp (s->name, ".eh_frame") || sh->sh_type != SHT_PROGBITS)
#endif
{
tcc_error_noabort("invalid section type");
goto fail;
}
} }
/* align start of section */ /* align start of section */
s->data_offset += -s->data_offset & (sh->sh_addralign - 1); s->data_offset += -s->data_offset & (sh->sh_addralign - 1);

View File

@ -61,6 +61,9 @@ endif
ifeq ($(CC_NAME),msvc) ifeq ($(CC_NAME),msvc)
test.ref abitest : CC = gcc test.ref abitest : CC = gcc
endif endif
ifeq ($(TARGETOS),OpenBSD)
dlltest: CFLAGS+=-fno-stack-protector
endif
RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS) RUN_TCC = $(NATIVE_DEFINES) -run $(TOPSRC)/tcc.c $(TCCFLAGS)
DISAS = objdump -d DISAS = objdump -d

View File

@ -48,6 +48,10 @@ ifeq (-$(CONFIG_WIN32)-,-yes-)
SKIP += 106_pthread.test # No pthread support SKIP += 106_pthread.test # No pthread support
SKIP += 114_bound_signal.test # No pthread support SKIP += 114_bound_signal.test # No pthread support
endif endif
ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
SKIP += 106_pthread.test # no pthread_condattr_setpshared
SKIP += 114_bound_signal.test # libc problem signal/fork
endif
# Some tests might need arguments # Some tests might need arguments
ARGS = ARGS =

View File

@ -131,7 +131,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
/* The PLT slot refers to the relocation entry it needs via offset. /* The PLT slot refers to the relocation entry it needs via offset.
The reloc entry is created below, so its offset is the current The reloc entry is created below, so its offset is the current
data_offset */ data_offset */
relofs = s1->got->reloc ? s1->got->reloc->data_offset : 0; relofs = s1->got->relocplt ? s1->got->relocplt->data_offset : 0;
/* Jump to GOT entry where ld.so initially put the address of ip + 4 */ /* Jump to GOT entry where ld.so initially put the address of ip + 4 */
p = section_ptr_add(plt, 16); p = section_ptr_add(plt, 16);
@ -140,7 +140,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
write32le(p + 2, got_offset); write32le(p + 2, got_offset);
p[6] = 0x68; /* push $xxx */ p[6] = 0x68; /* push $xxx */
/* On x86-64, the relocation is referred to by _index_ */ /* On x86-64, the relocation is referred to by _index_ */
write32le(p + 7, relofs / sizeof (ElfW_Rel)); write32le(p + 7, relofs / sizeof (ElfW_Rel) - 1);
p[11] = 0xe9; /* jmp plt_start */ p[11] = 0xe9; /* jmp plt_start */
write32le(p + 12, -(plt->data_offset)); write32le(p + 12, -(plt->data_offset));
return plt_offset; return plt_offset;
@ -168,6 +168,20 @@ ST_FUNC void relocate_plt(TCCState *s1)
p += 16; p += 16;
} }
} }
if (s1->got->relocplt) {
int mem = s1->output_type == TCC_OUTPUT_MEMORY;
ElfW_Rel *rel;
int x = s1->plt->sh_addr + 16 + 6;
p = s1->got->data;
for_each_elem(s1->got->relocplt, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
write64le(p + rel->r_offset, mem ? sym->st_value : x);
x += 16;
}
}
} }
#endif #endif
#endif #endif