aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libtcc.c23
-rw-r--r--tccelf.c90
2 files changed, 100 insertions, 13 deletions
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;i<level;i++) {
/* XXX: check address validity with program info */
if (fp <= 0x1000)
@@ -1868,7 +1876,9 @@ TCCState *tcc_new(void)
tcc_define_symbol(s, "__STDC__", NULL);
tcc_define_symbol(s, "__STDC_VERSION__", "199901L");
#if defined(TCC_TARGET_I386)
- tcc_define_symbol(s, "__i386__", NULL);
+ tcc_define_symbol(s, "__i386__", "1");
+ tcc_define_symbol(s, "__i386", "1");
+ tcc_define_symbol(s, "i386", "1");
#endif
#if defined(TCC_TARGET_X86_64)
tcc_define_symbol(s, "__x86_64__", NULL);
@@ -1889,8 +1899,15 @@ TCCState *tcc_new(void)
tcc_define_symbol(s, "_WIN64", NULL);
#endif
#else
- tcc_define_symbol(s, "__unix__", NULL);
- tcc_define_symbol(s, "__unix", NULL);
+ tcc_define_symbol(s, "__unix__", "1");
+ tcc_define_symbol(s, "__unix", "1");
+ tcc_define_symbol(s, "unix", "1");
+#if defined(__FreeBSD__)
+#define str(s) #s
+ tcc_define_symbol(s, "__FreeBSD__", str( __FreeBSD__));
+ tcc_define_symbol(s, "__INTEL_COMPILER", "1");
+#undef str
+#endif
#if defined(__linux)
tcc_define_symbol(s, "__linux__", NULL);
tcc_define_symbol(s, "__linux", NULL);
diff --git a/tccelf.c b/tccelf.c
index 3b881b0..dc0c948 100644
--- a/tccelf.c
+++ b/tccelf.c
@@ -1302,7 +1302,7 @@ static void tcc_add_linker_symbols(TCCState *s1)
/* name of ELF interpreter */
#if defined __FreeBSD__
-static const char elf_interp[] = "/usr/libexec/ld-elf.so.1";
+static const char elf_interp[] = "/libexec/ld-elf.so.1";
#elif defined TCC_ARM_EABI
static const char elf_interp[] = "/lib/ld-linux.so.3";
#elif defined(TCC_TARGET_X86_64)
@@ -1335,6 +1335,31 @@ static void tcc_output_binary(TCCState *s1, FILE *f,
}
}
+#if defined(__FreeBSD__)
+#define HAVE_PHDR 1
+#define EXTRA_RELITEMS 14
+
+/* move the relocation value from .dynsym to .got */
+void patch_dynsym_undef(TCCState *s1, Section *s)
+{
+ uint32_t *gotd = (void *)s1->got->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;
@@ -1844,10 +1901,19 @@ int elf_output_file(TCCState *s1, const char *filename)
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);
put_dt(dynamic, DT_NULL, 0);
@@ -1979,6 +2045,10 @@ int elf_output_file(TCCState *s1, const char *filename)
for(i=1;i<s1->nb_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++;