mirror of
https://github.com/frida/tinycc
synced 2025-02-03 00:45:42 +03:00
solve tccelf problem on FreeBSD
On Sun, Nov 22, 2009 at 05:43:14PM +0100, Luigi Rizzo wrote: > Hi, > there is a well known problem with tcc and FreeBSD in the generation > of elf objects -- see > http://lists.gnu.org/archive/html/tinycc-devel/2005-07/msg00070.html > > Apparently Sergey Lyubka has tried a partial fix to the problem. > I was wondering if Sergey or someone can post some more detail on > what needs to be done so we can try to help fixing this issue I think i have managed to solve the problem and produce almost valid elf files on FreeBSD. The two patches attached address a few problems (trying to explain to the best of my knowledge; i am not very familiar with ELF and the FreeBSD ELF conventions): 1. ELF file format tcc produces an ELF executable which is good for linux but not for FreeBSD. It misses the PHDR section which is almost mandatory for shared executables, puts in the .dynsym section some relocation info that FreeBSD expects to be in .got, and expect the relocation sections to be contiguous. patch-tccelf.c tries to address the above problem using conditional sections (so hopefully can be imported upstream) and also adds the ability to override the name of the dynamic loader through an environment variable (this is important to debug tcc). 2. predefined macros patch-libtcc.c adds/fixes some predefined macros when compiling on FreeBSD: these are __FreeBSD__ and the usual set of __i386__ and __unix__ variants. It also sets __INTEL_COMPILER so we can grab the __aligned macro from cdefs.h , otherwise many programs would fail The resulting elf file is still not 100% correct -- if you strip it, the program will not run (presumably there is some dangling reference). Other than that, program do seem to run correctly. It would be nice to integrate these patches in the main repository. The FreeBSD specific code is in #ifdef so it should not harm linux users cheers luigi
This commit is contained in:
parent
720a32ede4
commit
55cb2170cd
23
libtcc.c
23
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);
|
||||
|
90
tccelf.c
90
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;
|
||||
@ -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;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++;
|
||||
|
Loading…
x
Reference in New Issue
Block a user