diff --git a/libtcc.c b/libtcc.c index dfb000a..54184e2 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1578,10 +1578,18 @@ static int rt_get_caller_pc(unsigned long *paddr, if (level == 0) { /* XXX: only support linux */ +#if defined(__FreeBSD__) + *paddr = uc->uc_mcontext.mc_rip; +#else *paddr = uc->uc_mcontext.gregs[REG_RIP]; +#endif return 0; } else { +#if defined(__FreeBSD__) + fp = uc->uc_mcontext.mc_rbp; +#else fp = uc->uc_mcontext.gregs[REG_RBP]; +#endif for(i=1;igot->data; + ElfW(Sym) *sym, *sym_end; + + gotd += 3; // dummy entries in .got + /* relocate symbols in .dynsym */ + sym_end = (ElfW(Sym) *)(s->data + s->data_offset); + for (sym = (ElfW(Sym) *)s->data + 1; sym < sym_end; sym++) { + if (sym->st_shndx == SHN_UNDEF) { + *gotd++ = sym->st_value + 6; // XXX 6 is magic ? + sym->st_value = 0; + } + } +} +#else +#define HAVE_PHDR 0 +#define EXTRA_RELITEMS 9 +#endif + /* output an ELF file */ /* XXX: suppress unneeded sections */ int elf_output_file(TCCState *s1, const char *filename) @@ -1353,7 +1378,8 @@ int elf_output_file(TCCState *s1, const char *filename) ElfW(Sym) *sym; int type, file_type; unsigned long rel_addr, rel_size; - + unsigned long bss_addr, bss_size; + file_type = s1->output_type; s1->nb_errors = 0; @@ -1377,16 +1403,20 @@ int elf_output_file(TCCState *s1, const char *filename) const char *name; int sym_index, index; ElfW(Sym) *esym, *sym_end; - + if (file_type == TCC_OUTPUT_EXE) { char *ptr; + /* allow override the dynamic loader */ + const char *elfint = getenv("LD_SO"); + if (elfint == NULL) + elfint = elf_interp; /* add interpreter section only if executable */ interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC); interp->sh_addralign = 1; - ptr = section_ptr_add(interp, sizeof(elf_interp)); - strcpy(ptr, elf_interp); + ptr = section_ptr_add(interp, 1+strlen(elfint)); + strcpy(ptr, elfint); } - + /* add dynamic symbol table */ s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC, ".dynstr", @@ -1543,7 +1573,7 @@ int elf_output_file(TCCState *s1, const char *filename) /* add necessary space for other entries */ saved_dynamic_data_offset = dynamic->data_offset; - dynamic->data_offset += sizeof(ElfW(Dyn)) * 9; + dynamic->data_offset += sizeof(ElfW(Dyn)) * EXTRA_RELITEMS; } else { /* still need to build got entries in case of static link */ build_got_entries(s1); @@ -1572,7 +1602,7 @@ int elf_output_file(TCCState *s1, const char *filename) break; case TCC_OUTPUT_EXE: if (!s1->static_link) - phnum = 4; + phnum = 4 + HAVE_PHDR; else phnum = 2; break; @@ -1649,10 +1679,11 @@ int elf_output_file(TCCState *s1, const char *filename) rel_size = 0; rel_addr = 0; + bss_addr = bss_size = 0; /* leave one program header for the program interpreter */ ph = &phdr[0]; if (interp) - ph++; + ph += 1 + HAVE_PHDR; for(j = 0; j < 2; j++) { ph->p_type = PT_LOAD; @@ -1714,9 +1745,20 @@ int elf_output_file(TCCState *s1, const char *filename) } /* update dynamic relocation infos */ if (s->sh_type == SHT_RELX) { +#if defined(__FreeBSD__) + if (!strcmp(strsec->data + s->sh_name, ".rel.got")) { // rel_size == 0) { + rel_addr = addr; + rel_size += s->sh_size; // XXX only first rel. + } + if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) { // rel_size == 0) { + bss_addr = addr; + bss_size = s->sh_size; // XXX only first rel. + } +#else if (rel_size == 0) rel_addr = addr; rel_size += s->sh_size; +#endif } addr += s->sh_size; if (s->sh_type != SHT_NOBITS) @@ -1743,7 +1785,22 @@ int elf_output_file(TCCState *s1, const char *filename) /* if interpreter, then add corresponing program header */ if (interp) { ph = &phdr[0]; - + +#if defined(__FreeBSD__) + { + int len = phnum * sizeof(ElfW(Phdr)); + + ph->p_type = PT_PHDR; + ph->p_offset = sizeof(ElfW(Ehdr)); + ph->p_vaddr = interp->sh_addr - len; + ph->p_paddr = ph->p_vaddr; + ph->p_filesz = ph->p_memsz = len; + ph->p_flags = PF_R | PF_X; + ph->p_align = 4; // interp->sh_addralign; + ph++; + } +#endif + ph->p_type = PT_INTERP; ph->p_offset = interp->sh_offset; ph->p_vaddr = interp->sh_addr; @@ -1843,10 +1900,19 @@ int elf_output_file(TCCState *s1, const char *filename) put_dt(dynamic, DT_RELA, rel_addr); put_dt(dynamic, DT_RELASZ, rel_size); put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel)); +#else +#if defined(__FreeBSD__) + put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr); + put_dt(dynamic, DT_PLTRELSZ, rel_size); + put_dt(dynamic, DT_JMPREL, rel_addr); + put_dt(dynamic, DT_PLTREL, DT_REL); + put_dt(dynamic, DT_REL, bss_addr); + put_dt(dynamic, DT_RELSZ, bss_size); #else put_dt(dynamic, DT_REL, rel_addr); put_dt(dynamic, DT_RELSZ, rel_size); put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel)); +#endif #endif if (s1->do_debug) put_dt(dynamic, DT_DEBUG, 0); @@ -1979,6 +2045,10 @@ int elf_output_file(TCCState *s1, const char *filename) for(i=1;inb_sections;i++) { s = s1->sections[section_order[i]]; if (s->sh_type != SHT_NOBITS) { +#if defined(__FreeBSD__) + if (s->sh_type == SHT_DYNSYM) + patch_dynsym_undef(s1, s); +#endif while (offset < s->sh_offset) { fputc(0, f); offset++;