OpenBSD: runtime fixes

After this commit we can compile and run code with some limitations.
- The dlsym function is broken so this makes -run and bound checking
  not work all the time. Make -k test does work for most code.
- You have to do:
    ln -s /usr/lib/libN.so.x.y /usr/lib/libN.so
  for all .so files in /usr/lib.
  OpenBSD uses opendir/readdir to find the correct so file. This is
  not the way other platforms do this.
  Also the .a versions do not have all symbols that are present in the .so
  files.

tcc.h:
- Use different dynamic loader

elf.h:
- Add SHT_X86_64_UNWIND

tccelf.c:
- Do not use -dl
- Add required NOTE section
- Add extra dynamic tags
- Allow SHT_X86_64_UNWIND/SHT_NOTE in tcc_load_object_file

tccrun.c:
- Uses MAP_FIXED because without the offset between exec and data section
  becomes too big for x86_64

lib/bcheck.c:
- Do not use __libc_freeres

tests/tcctest.c:
- aligned_function also disabled for __GNUC__ == 4
This commit is contained in:
herman ten brugge 2020-12-07 08:27:10 +01:00
parent 19d287aae3
commit baacb0f52a
6 changed files with 80 additions and 7 deletions

2
elf.h
View File

@ -2908,6 +2908,8 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_X86_64_NUM 43 #define R_X86_64_NUM 43
/* x86-64 sh_type values. */
#define SHT_X86_64_UNWIND 0x70000001 /* Unwind information. */
/* AM33 relocations. */ /* AM33 relocations. */
#define R_MN10300_NONE 0 /* No reloc. */ #define R_MN10300_NONE 0 /* No reloc. */

View File

@ -1147,7 +1147,7 @@ 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__) #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__OpenBSD__)
if (print_heap) { if (print_heap) {
extern void __libc_freeres (void); extern void __libc_freeres (void);
__libc_freeres (); __libc_freeres ();

6
tcc.h
View File

@ -285,7 +285,11 @@ extern char **environ;
# if defined(TCC_MUSL) # if defined(TCC_MUSL)
# define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1" # define CONFIG_TCC_ELFINTERP "/lib/ld-musl-x86_64.so.1"
# else # else
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2" # if defined(__OpenBSD__)
# define CONFIG_TCC_ELFINTERP "/usr/libexec/ld.so"
# else
# define CONFIG_TCC_ELFINTERP "/lib64/ld-linux-x86-64.so.2"
# endif
# endif # endif
# elif defined(TCC_TARGET_RISCV64) # elif defined(TCC_TARGET_RISCV64)
# define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1" # define CONFIG_TCC_ELFINTERP "/lib/ld-linux-riscv64-lp64d.so.1"

View File

@ -1413,7 +1413,9 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) { if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
tcc_add_library_err(s1, "pthread"); tcc_add_library_err(s1, "pthread");
#if !defined(__OpenBSD__)
tcc_add_library_err(s1, "dl"); tcc_add_library_err(s1, "dl");
#endif
tcc_add_support(s1, "bcheck.o"); tcc_add_support(s1, "bcheck.o");
} }
#endif #endif
@ -1992,7 +1994,7 @@ static void put_dt(Section *dynamic, int dt, addr_t val)
} }
static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp, static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
Section *dynamic) Section *dynamic, Section *note)
{ {
ElfW(Phdr) *ph; ElfW(Phdr) *ph;
@ -2019,6 +2021,19 @@ static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
ph->p_align = interp->sh_addralign; ph->p_align = interp->sh_addralign;
} }
if (note) {
ph = &phdr[phnum - 2];
ph->p_type = PT_NOTE;
ph->p_offset = note->sh_offset;
ph->p_vaddr = note->sh_addr;
ph->p_paddr = ph->p_vaddr;
ph->p_filesz = note->sh_size;
ph->p_memsz = note->sh_size;
ph->p_flags = PF_R;
ph->p_align = note->sh_addralign;
}
/* if dynamic section, then add corresponding program header */ /* if dynamic section, then add corresponding program header */
if (dynamic) { if (dynamic) {
ph = &phdr[phnum - 1]; ph = &phdr[phnum - 1];
@ -2051,6 +2066,13 @@ 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));
#ifdef __OpenBSD__
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size);
put_dt(dynamic, DT_JMPREL, dyninf->rel_addr);
put_dt(dynamic, DT_PLTREL, DT_RELA);
put_dt(dynamic, DT_BIND_NOW, 1); /* Dirty hack */
#endif
#else #else
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
@ -2372,6 +2394,25 @@ static void create_arm_attribute_section(TCCState *s1)
} }
#endif #endif
#ifdef __OpenBSD__
static Section *create_openbsd_note_section(TCCState *s1)
{
Section *s = find_section (s1, ".note.openbsd.ident");
if (s->data_offset == 0) {
unsigned char *ptr = section_ptr_add(s, sizeof(ElfW(Nhdr)) + 8 + 4);
ElfW(Nhdr) *note = (ElfW(Nhdr) *) ptr;
s->sh_type = SHT_NOTE;
note->n_namesz = 8;
note->n_descsz = 4;
note->n_type = ELF_NOTE_OS_GNU;
strcpy (ptr + sizeof(ElfW(Nhdr)), "OpenBSD");
}
return s;
}
#endif
/* Output an elf, coff or binary file */ /* Output an elf, coff or binary file */
/* XXX: suppress unneeded sections */ /* XXX: suppress unneeded sections */
static int elf_output_file(TCCState *s1, const char *filename) static int elf_output_file(TCCState *s1, const char *filename)
@ -2379,13 +2420,18 @@ static int elf_output_file(TCCState *s1, const char *filename)
int ret, phnum, shnum, file_type, file_offset, *sec_order; int ret, phnum, shnum, file_type, file_offset, *sec_order;
struct dyn_inf dyninf = {0}; struct dyn_inf dyninf = {0};
ElfW(Phdr) *phdr; ElfW(Phdr) *phdr;
Section *strsec, *interp, *dynamic, *dynstr; Section *strsec, *interp, *dynamic, *dynstr, *note = NULL;
file_type = s1->output_type;
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
create_arm_attribute_section (s1); create_arm_attribute_section (s1);
#endif #endif
#ifdef __OpenBSD__
if (file_type != TCC_OUTPUT_OBJ)
note = create_openbsd_note_section (s1);
#endif
file_type = s1->output_type;
s1->nb_errors = 0; s1->nb_errors = 0;
ret = -1; ret = -1;
phdr = NULL; phdr = NULL;
@ -2497,6 +2543,8 @@ static int elf_output_file(TCCState *s1, const char *filename)
phnum = i < s1->nb_sections ? 6 : 5; phnum = i < s1->nb_sections ? 6 : 5;
} }
phnum += note != NULL;
/* allocate program segment headers */ /* allocate program segment headers */
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
@ -2515,7 +2563,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
/* Fill remaining program header and finalize relocation related to dynamic /* Fill remaining program header and finalize relocation related to dynamic
linking. */ linking. */
if (file_type != TCC_OUTPUT_OBJ) { if (file_type != TCC_OUTPUT_OBJ) {
fill_unloadable_phdr(phdr, phnum, interp, dynamic); fill_unloadable_phdr(phdr, phnum, interp, dynamic, note);
if (dynamic) { if (dynamic) {
ElfW(Sym) *sym; ElfW(Sym) *sym;
dynamic->data_offset = dyninf.data_offset; dynamic->data_offset = dyninf.data_offset;
@ -2703,6 +2751,10 @@ ST_FUNC int tcc_load_object_file(TCCState *s1,
if (sh->sh_type != SHT_PROGBITS && if (sh->sh_type != SHT_PROGBITS &&
#ifdef TCC_ARM_EABI #ifdef TCC_ARM_EABI
sh->sh_type != SHT_ARM_EXIDX && sh->sh_type != SHT_ARM_EXIDX &&
#endif
#ifdef __OpenBSD__
sh->sh_type != SHT_X86_64_UNWIND &&
sh->sh_type != SHT_NOTE &&
#endif #endif
sh->sh_type != SHT_NOBITS && sh->sh_type != SHT_NOBITS &&
sh->sh_type != SHT_PREINIT_ARRAY && sh->sh_type != SHT_PREINIT_ARRAY &&

View File

@ -88,8 +88,23 @@ LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
unlink(tmpfname); unlink(tmpfname);
ftruncate(fd, size); ftruncate(fd, size);
#ifdef __OpenBSD__
{ /* OpenBSD uses random 64 addresses that are far apart. This does not
work for the x86_64 target.
This might be a problem in the future for other targets. */
static char *prw = (char *) 0x100000000;
char *pex = prw + 0x40000000;
ptr = mmap (prw, size, PROT_READ|PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0);
prx = mmap (pex, size, PROT_READ|PROT_EXEC, MAP_SHARED | MAP_FIXED, fd, 0);
tcc_enter_state (s1);
prw += 0x100000000;
tcc_exit_state();
}
#else
ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); prx = mmap (NULL, size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
#endif
if (ptr == MAP_FAILED || prx == MAP_FAILED) if (ptr == MAP_FAILED || prx == MAP_FAILED)
tcc_error("tccrun: could not map memory"); tcc_error("tccrun: could not map memory");
dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size); dynarray_add(&s1->runtime_mem, &s1->nb_runtime_mem, (void*)(addr_t)size);

View File

@ -2313,7 +2313,7 @@ int fib(int n)
return fib(n-1) + fib(n-2); return fib(n-1) + fib(n-2);
} }
#if __GNUC__ == 3 #if __GNUC__ == 3 || __GNUC__ == 4
# define aligned_function 0 # define aligned_function 0
#else #else
void __attribute__((aligned(16))) aligned_function(int i) {} void __attribute__((aligned(16))) aligned_function(int i) {}