diff options
author | Dirk Meyer <dinoex@FreeBSD.org> | 2009-11-29 07:59:08 +0000 |
---|---|---|
committer | Dirk Meyer <dinoex@FreeBSD.org> | 2009-11-29 07:59:08 +0000 |
commit | a1eff5e1a4ff6dbe36f12e48ec54a8bc6dc084c5 (patch) | |
tree | a9e9f1626bca17b10512f560a99c73993e7f4ee9 /lang/tcc | |
parent | - add path for inn 2.5.0 (diff) |
- fix segfaults for linked elfs binaries
PR: 138481
Submitted by: Luigi Rizzo
Notes
Notes:
svn path=/head/; revision=244960
Diffstat (limited to 'lang/tcc')
-rw-r--r-- | lang/tcc/Makefile | 1 | ||||
-rw-r--r-- | lang/tcc/files/README.tccelf | 43 | ||||
-rw-r--r-- | lang/tcc/files/patch-libtcc.c | 34 | ||||
-rw-r--r-- | lang/tcc/files/patch-tccelf.c | 175 |
4 files changed, 251 insertions, 2 deletions
diff --git a/lang/tcc/Makefile b/lang/tcc/Makefile index 2d8adbd11a55..48ea5830efaf 100644 --- a/lang/tcc/Makefile +++ b/lang/tcc/Makefile @@ -7,6 +7,7 @@ PORTNAME= tcc PORTVERSION= 0.9.25 +PORTREVISION= 1 CATEGORIES= lang MASTER_SITES= ${MASTER_SITE_SAVANNAH} MASTER_SITE_SUBDIR= tinycc diff --git a/lang/tcc/files/README.tccelf b/lang/tcc/files/README.tccelf new file mode 100644 index 000000000000..40a75d8af23a --- /dev/null +++ b/lang/tcc/files/README.tccelf @@ -0,0 +1,43 @@ + +I think i have managed to solve the problem and produce +almost valid elf files on FreeBSD. The two patches attached +should go in ports/tcc/files (patch-libtcc.c replaces +the existing one with the same name) and bumping PORTREVISION +should complete the job. I can do the commit myself if the +maintainer has no time. + +The patches 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. + +I am going to submit the patch upstream to see if the maintainers +want to integrate it + + cheers + luigi + diff --git a/lang/tcc/files/patch-libtcc.c b/lang/tcc/files/patch-libtcc.c index 9c514b3dcfc7..2fd6d59ee674 100644 --- a/lang/tcc/files/patch-libtcc.c +++ b/lang/tcc/files/patch-libtcc.c @@ -1,5 +1,6 @@ ---- libtcc.c.orig 2009-05-18 16:27:06.000000000 +0200 -+++ libtcc.c 2009-07-03 07:51:05.000000000 +0200 +diff -ubwr ./libtcc.c ../../work.2/tcc-0.9.25/libtcc.c +--- ./libtcc.c 2009-05-18 16:27:06.000000000 +0200 ++++ ../../work.2/tcc-0.9.25/libtcc.c 2009-11-29 02:25:14.000000000 +0100 @@ -1509,10 +1509,18 @@ if (level == 0) { @@ -19,3 +20,32 @@ for(i=1;i<level;i++) { /* XXX: check address validity with program info */ if (fp <= 0x1000) +@@ -1784,7 +1792,9 @@ + 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); +@@ -1802,8 +1812,15 @@ + #ifdef TCC_TARGET_PE + tcc_define_symbol(s, "_WIN32", NULL); + #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/lang/tcc/files/patch-tccelf.c b/lang/tcc/files/patch-tccelf.c new file mode 100644 index 000000000000..a8a1d68c4fc4 --- /dev/null +++ b/lang/tcc/files/patch-tccelf.c @@ -0,0 +1,175 @@ +diff -ubwr ./tccelf.c ../../work.2/tcc-0.9.25/tccelf.c +--- ./tccelf.c 2009-05-18 16:27:06.000000000 +0200 ++++ ../../work.2/tcc-0.9.25/tccelf.c 2009-11-29 02:12:36.000000000 +0100 +@@ -1273,7 +1273,7 @@ + + /* name of ELF interpreter */ + #if defined __FreeBSD__ +-static char elf_interp[] = "/usr/libexec/ld-elf.so.1"; ++static char elf_interp[] = "/libexec/ld-elf.so.1"; + #elif defined TCC_ARM_EABI + static char elf_interp[] = "/lib/ld-linux.so.3"; + #elif defined(TCC_TARGET_X86_64) +@@ -1306,6 +1306,31 @@ + } + } + ++#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) +@@ -1324,6 +1349,7 @@ + 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; +@@ -1351,11 +1377,15 @@ + + if (file_type == TCC_OUTPUT_EXE) { + char *ptr; ++ /* allow override the dynamic loader */ ++ 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 */ +@@ -1514,7 +1544,7 @@ + + /* 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); +@@ -1543,7 +1573,7 @@ + break; + case TCC_OUTPUT_EXE: + if (!s1->static_link) +- phnum = 4; ++ phnum = 4 + HAVE_PHDR; + else + phnum = 2; + break; +@@ -1620,10 +1650,11 @@ + 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; +@@ -1685,9 +1716,20 @@ + } + /* 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) +@@ -1715,6 +1757,21 @@ + 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; +@@ -1815,10 +1872,19 @@ + 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); +@@ -1950,6 +2016,10 @@ + 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++; |