aboutsummaryrefslogtreecommitdiffstats
path: root/lang/tcc
diff options
context:
space:
mode:
authordinoex <dinoex@FreeBSD.org>2009-11-29 15:59:08 +0800
committerdinoex <dinoex@FreeBSD.org>2009-11-29 15:59:08 +0800
commitbcb1701b4cb9aee2b21ef1c2267808f46873d400 (patch)
treeaddfa32c12886257da2b26777c85208ddd59971d /lang/tcc
parent79433605e31735635a3fed058ef882722d6a5f17 (diff)
downloadfreebsd-ports-graphics-bcb1701b4cb9aee2b21ef1c2267808f46873d400.tar.gz
freebsd-ports-graphics-bcb1701b4cb9aee2b21ef1c2267808f46873d400.tar.zst
freebsd-ports-graphics-bcb1701b4cb9aee2b21ef1c2267808f46873d400.zip
- fix segfaults for linked elfs binaries
PR: 138481 Submitted by: Luigi Rizzo
Diffstat (limited to 'lang/tcc')
-rw-r--r--lang/tcc/Makefile1
-rw-r--r--lang/tcc/files/README.tccelf43
-rw-r--r--lang/tcc/files/patch-libtcc.c34
-rw-r--r--lang/tcc/files/patch-tccelf.c175
4 files changed, 251 insertions, 2 deletions
diff --git a/lang/tcc/Makefile b/lang/tcc/Makefile
index 2d8adbd11a5..48ea5830efa 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 00000000000..40a75d8af23
--- /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 9c514b3dcfc..2fd6d59ee67 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 00000000000..a8a1d68c4fc
--- /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++;