From ebaa5c81f43fc7963ee50fbb01729290e2349aa5 Mon Sep 17 00:00:00 2001 From: grischka Date: Sat, 28 May 2022 21:00:40 +0200 Subject: [PATCH] dynamic executables (PIE) Allows to create dynamic executables, using the code path for TCC_OUTPUT_DLL but add an .interp header (plus a FLAGS_1 entry in the dynamic section to make 'readelf' say "PIE") Introduces TCC_OUTPUT_DYN as alias for TCC_OUTPUT_DLL. There is no runtime option, only one to configure: ./configure --config-pie 100 insertions(+), 76 deletions(-) --- Makefile | 3 +- arm-gen.c | 2 +- arm-link.c | 2 +- arm64-link.c | 4 +- elf.h | 1 + i386-link.c | 6 +-- libtcc.c | 18 +++++--- libtcc.h | 8 ++-- riscv64-link.c | 4 +- tcc.h | 5 +++ tccdbg.c | 4 +- tccelf.c | 115 +++++++++++++++++++++++++++---------------------- x86_64-link.c | 4 +- 13 files changed, 100 insertions(+), 76 deletions(-) diff --git a/Makefile b/Makefile index 16065df5..e492d350 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,7 @@ NATIVE_DEFINES_$(CONFIG_arm64) += -DTCC_TARGET_ARM64 NATIVE_DEFINES_$(CONFIG_riscv64) += -DTCC_TARGET_RISCV64 NATIVE_DEFINES_$(CONFIG_BSD) += -DTARGETOS_$(TARGETOS) NATIVE_DEFINES_$(CONFIG_pie) += -DCONFIG_TCC_PIE +NATIVE_DEFINES_$(CONFIG_pic) += -DCONFIG_TCC_PIC NATIVE_DEFINES_no_$(CONFIG_bcheck) += -DCONFIG_TCC_BCHECK=0 NATIVE_DEFINES_no_$(CONFIG_backtrace) += -DCONFIG_TCC_BACKTRACE=0 NATIVE_DEFINES += $(NATIVE_DEFINES_yes) $(NATIVE_DEFINES_no_no) @@ -275,7 +276,7 @@ libtcc.a: $(LIBTCC_OBJ) # dynamic libtcc library libtcc.so: $(LIBTCC_OBJ) - $S$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LDFLAGS) + $S$(CC) -shared -Wl,-soname,$@ -o $@ $^ $(LIBS) $(LDFLAGS) libtcc.so: CFLAGS+=-fPIC libtcc.so: LDFLAGS+=-fPIC diff --git a/arm-gen.c b/arm-gen.c index e0d98d01..5eea781b 100644 --- a/arm-gen.c +++ b/arm-gen.c @@ -543,7 +543,7 @@ static void load_value(SValue *sv, int r) { o(0xE59F0000|(intr(r)<<12)); /* ldr r, [pc] */ o(0xEA000000); /* b $+4 */ -#ifndef CONFIG_TCC_PIE +#ifndef CONFIG_TCC_PIC if(sv->r & VT_SYM) greloc(cur_text_section, sv->sym, ind, R_ARM_ABS32); o(sv->c.i); diff --git a/arm-link.c b/arm-link.c index 18fc428c..d58e620c 100644 --- a/arm-link.c +++ b/arm-link.c @@ -380,7 +380,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t return; case R_ARM_ABS32: case R_ARM_TARGET1: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; qrel->r_offset = rel->r_offset; if (esym_index) { diff --git a/arm64-link.c b/arm64-link.c index baf13fed..8c345b29 100644 --- a/arm64-link.c +++ b/arm64-link.c @@ -177,7 +177,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t switch(type) { case R_AARCH64_ABS64: - if (s1->output_type == TCC_OUTPUT_DLL) { + if ((s1->output_type & TCC_OUTPUT_DYN)) { esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; qrel->r_offset = rel->r_offset; if (esym_index) { @@ -194,7 +194,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t add64le(ptr, val); return; case R_AARCH64_ABS32: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { /* XXX: this logic may depend on TCC's codegen now TCC uses R_AARCH64_RELATIVE even for a 64bit pointer */ qrel->r_offset = rel->r_offset; diff --git a/elf.h b/elf.h index 19271e57..14cfdcff 100644 --- a/elf.h +++ b/elf.h @@ -825,6 +825,7 @@ typedef struct #define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */ #define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */ #define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */ +#define DF_1_PIE 0x08000000 /* Flags for the feature selection in DT_FEATURE_1. */ #define DTF_1_PARINIT 0x00000001 diff --git a/i386-link.c b/i386-link.c index 11581f56..ee344b93 100644 --- a/i386-link.c +++ b/i386-link.c @@ -100,7 +100,7 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_ unsigned plt_offset, relofs; /* on i386 if we build a DLL, we add a %ebx offset */ - if (s1->output_type == TCC_OUTPUT_DLL) + if (s1->output_type & TCC_OUTPUT_DYN) modrm = 0xa3; else modrm = 0x25; @@ -148,7 +148,7 @@ ST_FUNC void relocate_plt(TCCState *s1) p = s1->plt->data; p_end = p + s1->plt->data_offset; - if (s1->output_type != TCC_OUTPUT_DLL && p < p_end) { + if (!(s1->output_type & TCC_OUTPUT_DYN) && p < p_end) { add32le(p + 2, s1->got->sh_addr); add32le(p + 8, s1->got->sh_addr); p += 16; @@ -179,7 +179,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t switch (type) { case R_386_32: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; qrel->r_offset = rel->r_offset; if (esym_index) { diff --git a/libtcc.c b/libtcc.c index ca575586..652f5129 100644 --- a/libtcc.c +++ b/libtcc.c @@ -862,6 +862,10 @@ LIBTCCAPI void tcc_delete(TCCState *s1) LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) { +#ifdef CONFIG_TCC_PIE + if (output_type == TCC_OUTPUT_EXE) + output_type |= TCC_OUTPUT_DYN; +#endif s->output_type = output_type; if (!s->nostdinc) { @@ -869,6 +873,10 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) /* -isystem paths have already been handled */ tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS); } + + if (output_type == TCC_OUTPUT_PREPROCESS) + return 0; + #ifdef CONFIG_TCC_BCHECK if (s->do_bounds_check) { /* if bound checking, then add corresponding sections */ @@ -905,13 +913,13 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) #else /* paths for crt objects */ tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); + /* add libc crt1/crti objects */ - if ((output_type == TCC_OUTPUT_EXE || output_type == TCC_OUTPUT_DLL) && - !s->nostdlib) { + if (output_type != TCC_OUTPUT_MEMORY && !s->nostdlib) { #if TARGETOS_OpenBSD if (output_type != TCC_OUTPUT_DLL) tcc_add_crt(s, "crt0.o"); - if (output_type == TCC_OUTPUT_DLL) + if (output_type & TCC_OUTPUT_DYN) tcc_add_crt(s, "crtbeginS.o"); else tcc_add_crt(s, "crtbegin.o"); @@ -921,7 +929,7 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) tcc_add_crt(s, "crti.o"); if (s->static_link) tcc_add_crt(s, "crtbeginT.o"); - else if (output_type == TCC_OUTPUT_DLL) + else if (output_type & TCC_OUTPUT_DYN) tcc_add_crt(s, "crtbeginS.o"); else tcc_add_crt(s, "crtbegin.o"); @@ -931,7 +939,7 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) tcc_add_crt(s, "crti.o"); if (s->static_link) tcc_add_crt(s, "crtbeginT.o"); - else if (output_type == TCC_OUTPUT_DLL) + else if (output_type & TCC_OUTPUT_DYN) tcc_add_crt(s, "crtbeginS.o"); else tcc_add_crt(s, "crtbegin.o"); diff --git a/libtcc.h b/libtcc.h index 25d247a7..5ddfda9d 100644 --- a/libtcc.h +++ b/libtcc.h @@ -65,11 +65,11 @@ LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf); /* set output type. MUST BE CALLED before any compilation */ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type); -#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory (default) */ +#define TCC_OUTPUT_MEMORY 1 /* output will be run in memory */ #define TCC_OUTPUT_EXE 2 /* executable file */ -#define TCC_OUTPUT_DLL 3 /* dynamic library */ -#define TCC_OUTPUT_OBJ 4 /* object file */ -#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess (used internally) */ +#define TCC_OUTPUT_DLL 4 /* dynamic library */ +#define TCC_OUTPUT_OBJ 3 /* object file */ +#define TCC_OUTPUT_PREPROCESS 5 /* only preprocess */ /* equivalent to -Lpath option */ LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname); diff --git a/riscv64-link.c b/riscv64-link.c index 2aeefefb..ba608c63 100644 --- a/riscv64-link.c +++ b/riscv64-link.c @@ -284,7 +284,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, return; case R_RISCV_32: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { /* XXX: this logic may depend on TCC's codegen now TCC uses R_RISCV_RELATIVE even for a 64bit pointer */ qrel->r_offset = rel->r_offset; @@ -296,7 +296,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, add32le(ptr, val); return; case R_RISCV_64: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; qrel->r_offset = rel->r_offset; if (esym_index) { diff --git a/tcc.h b/tcc.h index 40eb1f03..d30d5dac 100644 --- a/tcc.h +++ b/tcc.h @@ -236,6 +236,10 @@ extern long double strtold (const char *__nptr, char **__endptr); # define TCC_USING_DOUBLE_FOR_LDOUBLE 1 #endif +#ifdef CONFIG_TCC_PIE +# define CONFIG_TCC_PIC 1 +#endif + /* ------------ path configuration ------------ */ #ifndef CONFIG_SYSROOT @@ -1485,6 +1489,7 @@ ST_DATA int func_bound_add_epilog; #define TCC_OUTPUT_FORMAT_ELF 0 /* default output format: ELF */ #define TCC_OUTPUT_FORMAT_BINARY 1 /* binary image output */ #define TCC_OUTPUT_FORMAT_COFF 2 /* COFF */ +#define TCC_OUTPUT_DYN TCC_OUTPUT_DLL #define ARMAG "!\012" /* For COFF and a.out archives */ diff --git a/tccdbg.c b/tccdbg.c index 914ddb9a..9b2b527e 100644 --- a/tccdbg.c +++ b/tccdbg.c @@ -392,9 +392,7 @@ ST_FUNC void tcc_debug_new(TCCState *s1) #ifdef CONFIG_TCC_BACKTRACE /* include stab info with standalone backtrace support */ if (s1->do_backtrace - && (s1->output_type == TCC_OUTPUT_EXE - || s1->output_type == TCC_OUTPUT_DLL) - ) + && (s1->output_type & (TCC_OUTPUT_EXE | TCC_OUTPUT_DLL))) shf = SHF_ALLOC | SHF_WRITE; // SHF_WRITE needed for musl/SELINUX #endif if (s1->dwarf) { diff --git a/tccelf.c b/tccelf.c index 4530b1b7..ed51d68a 100644 --- a/tccelf.c +++ b/tccelf.c @@ -928,12 +928,16 @@ static void relocate_section(TCCState *s1, Section *s, Section *sr) /* if the relocation is allocated, we change its symbol table */ if (sr->sh_flags & SHF_ALLOC) { sr->link = s1->dynsym; - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { size_t r = (uint8_t*)qrel - sr->data; if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE && 0 == strcmp(s->name, ".stab")) r = 0; /* cannot apply 64bit relocation to 32bit value */ sr->data_offset = sr->sh_size = r; +#ifdef CONFIG_TCC_PIE + if (r && 0 == (s->sh_flags & SHF_WRITE)) + tcc_warning("%d relocations to ro-section %s", (unsigned)(r / sizeof *qrel), s->name); +#endif } } #endif @@ -1013,7 +1017,6 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr) case R_X86_64_PC32: { ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; - /* Hidden defined symbols can and must be resolved locally. We're misusing a PLT32 reloc for this, as that's always resolved to its address even in shared libs. */ @@ -1026,6 +1029,8 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr) #elif defined(TCC_TARGET_ARM64) case R_AARCH64_PREL32: #endif + if (s1->output_type != TCC_OUTPUT_DLL) + break; if (get_sym_attr(s1, sym_index, 0)->dyn_index) count++; break; @@ -1188,7 +1193,8 @@ redo: if (sym->st_shndx == SHN_UNDEF) { ElfW(Sym) *esym; int dynindex; - if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT) + if (!PCRELATIVE_DLLPLT + && (s1->output_type & TCC_OUTPUT_DYN)) continue; /* Relocations for UNDEF symbols would normally need to be transferred into the executable or shared object. @@ -1228,7 +1234,7 @@ redo: sym->st_shndx != SHN_UNDEF && (ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT || ELFW(ST_BIND)(sym->st_info) == STB_LOCAL || - s1->output_type == TCC_OUTPUT_EXE)) { + s1->output_type & TCC_OUTPUT_EXE)) { if (pass != 0) continue; rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); @@ -1483,7 +1489,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) #endif #ifdef CONFIG_TCC_BACKTRACE if (s1->do_backtrace) { - if (s1->output_type == TCC_OUTPUT_EXE) + if (s1->output_type & TCC_OUTPUT_EXE) tcc_add_support(s1, "bt-exe.o"); if (s1->output_type != TCC_OUTPUT_DLL) tcc_add_support(s1, "bt-log.o"); @@ -1513,7 +1519,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1) #if defined TCC_TARGET_MACHO /* nothing to do */ #elif TARGETOS_OpenBSD || TARGETOS_FreeBSD || TARGETOS_NetBSD - if (s1->output_type == TCC_OUTPUT_DLL) + if (s1->output_type & TCC_OUTPUT_DYN) tcc_add_crt(s1, "crtendS.o"); else tcc_add_crt(s1, "crtend.o"); @@ -1812,7 +1818,7 @@ static int set_sec_sizes(TCCState *s1) if (s->sh_type == SHT_RELX && !(s->sh_flags & SHF_ALLOC)) { /* when generating a DLL, we include relocations but we may patch them */ - if (file_type == TCC_OUTPUT_DLL + if ((file_type & TCC_OUTPUT_DYN) && (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)) { int count = prepare_dynamic_rel(s1, s); if (count) { @@ -1820,7 +1826,7 @@ static int set_sec_sizes(TCCState *s1) s->sh_flags |= SHF_ALLOC; s->sh_size = count * sizeof(ElfW_Rel); if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE)) - textrel = 1; + textrel += count; } } } else if ((s->sh_flags & SHF_ALLOC) @@ -1904,7 +1910,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, a_offset += s_align; file_offset += (a_offset - p_offset); } else { - if (file_type == TCC_OUTPUT_DLL) + if (file_type & TCC_OUTPUT_DYN) addr = 0; else addr = ELF_START_ADDR; @@ -1936,7 +1942,7 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, symbol tables, relocations, progbits, nobits */ /* XXX: do faster and simpler sorting */ f = -1; - for(k = 0; k < 7; k++) { + for(k = 0; k < 10; k++) { for(i = 1; i < s1->nb_sections; i++) { s = s1->sections[i]; /* compute if section should be included */ @@ -1970,9 +1976,6 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, if (k != 2) continue; } - } else if (s->sh_type == SHT_NOBITS) { - if (k != 6) - continue; } else if ((s == rodata_section #ifdef CONFIG_TCC_BCHECK || s == bounds_section @@ -1984,6 +1987,19 @@ static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, /* Align next section on page size. This is needed to remap roinf section ro. */ f = 1; + + } else if (s->sh_type == SHT_PREINIT_ARRAY) { + if (k != 6) + continue; + } else if (s->sh_type == SHT_INIT_ARRAY) { + if (k != 7) + continue; + } else if (s->sh_type == SHT_FINI_ARRAY) { + if (k != 8) + continue; + } else if (s->sh_type == SHT_NOBITS) { + if (k != 9) + continue; } else { if (k != 5) continue; @@ -2270,7 +2286,7 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, #ifdef TCC_ARM_EABI ehdr.e_ident[EI_OSABI] = 0; ehdr.e_flags = EF_ARM_EABI_VER4; - if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL) + if (file_type & (TCC_OUTPUT_EXE | TCC_OUTPUT_DLL)) ehdr.e_flags |= EF_ARM_HASENTRY; if (s1->float_abi == ARM_HARD_FLOAT) ehdr.e_flags |= EF_ARM_VFP_FLOAT; @@ -2282,26 +2298,22 @@ static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr, #elif defined TCC_TARGET_RISCV64 ehdr.e_flags = EF_RISCV_FLOAT_ABI_DOUBLE; #endif - switch(file_type) { - default: - case TCC_OUTPUT_EXE: - ehdr.e_type = ET_EXEC; - ehdr.e_entry = get_sym_addr(s1, - s1->elf_entryname ? - s1->elf_entryname : "_start", - 1, 0); - break; - case TCC_OUTPUT_DLL: - ehdr.e_type = ET_DYN; - ehdr.e_entry = s1->elf_entryname ? - get_sym_addr(s1,s1->elf_entryname,1,0) : - text_section->sh_addr; - /* XXX: is it correct ? */ - break; - case TCC_OUTPUT_OBJ: + + if (file_type == TCC_OUTPUT_OBJ) { ehdr.e_type = ET_REL; - break; + } else { + if (file_type & TCC_OUTPUT_DYN) + ehdr.e_type = ET_DYN; + else + ehdr.e_type = ET_EXEC; + if (s1->elf_entryname) + ehdr.e_entry = get_sym_addr(s1, s1->elf_entryname, 1, 0); + else + ehdr.e_entry = get_sym_addr(s1, "_start", !!(file_type & TCC_OUTPUT_EXE), 0); + if (ehdr.e_entry == (addr_t)-1) + ehdr.e_entry = text_section->sh_addr; } + ehdr.e_machine = EM_TCC_TARGET; ehdr.e_version = EV_CURRENT; ehdr.e_shoff = file_offset; @@ -2530,7 +2542,7 @@ static int elf_output_file(TCCState *s1, const char *filename) ElfW(Phdr) *phdr; Section *interp, *dynamic, *dynstr, *note; struct ro_inf *roinf_use = NULL; - int textrel, got_sym; + int textrel, got_sym, dt_flags_1; file_type = s1->output_type; s1->nb_errors = 0; @@ -2557,7 +2569,7 @@ static int elf_output_file(TCCState *s1, const char *filename) resolve_common_syms(s1); if (!s1->static_link) { - if (file_type == TCC_OUTPUT_EXE) { + if (file_type & TCC_OUTPUT_EXE) { char *ptr; /* allow override the dynamic loader */ const char *elfint = getenv("LD_SO"); @@ -2590,7 +2602,7 @@ static int elf_output_file(TCCState *s1, const char *filename) goto the_end; } build_got_entries(s1, got_sym); - if (file_type == TCC_OUTPUT_EXE) { + if (file_type & TCC_OUTPUT_EXE) { bind_libs_dynsyms(s1); } else { /* shared library case: simply export all global symbols */ @@ -2606,7 +2618,6 @@ static int elf_output_file(TCCState *s1, const char *filename) alloc_sec_names(s1, 0); if (!s1->static_link) { - int i; /* add a list of needed dlls */ for(i = 0; i < s1->nb_loaded_dlls; i++) { DLLReference *dllref = s1->loaded_dlls[i]; @@ -2618,15 +2629,19 @@ static int elf_output_file(TCCState *s1, const char *filename) put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH, put_elf_str(dynstr, s1->rpath)); - if (file_type == TCC_OUTPUT_DLL) { + dt_flags_1 = DF_1_NOW; + if (file_type & TCC_OUTPUT_DYN) { if (s1->soname) put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname)); /* XXX: currently, since we do not handle PIC code, we must relocate the readonly segments */ if (textrel) put_dt(dynamic, DT_TEXTREL, 0); + if (file_type & TCC_OUTPUT_EXE) + dt_flags_1 = DF_1_NOW | DF_1_PIE; } - + put_dt(dynamic, DT_FLAGS, DF_BIND_NOW); + put_dt(dynamic, DT_FLAGS_1, dt_flags_1); if (s1->symbolic) put_dt(dynamic, DT_SYMBOLIC, 0); @@ -2639,20 +2654,16 @@ static int elf_output_file(TCCState *s1, const char *filename) dynstr->sh_size = dynstr->data_offset; } - for (i = 1; i < s1->nb_sections && - !(s1->sections[i]->sh_flags & SHF_TLS); i++); - phfill = 2 + (i < s1->nb_sections); - /* compute number of program headers */ - if (file_type == TCC_OUTPUT_DLL) - phnum = 3; - else if (s1->static_link) - phnum = 3; - else { - phnum = 5 + (i < s1->nb_sections); - } - - phnum += note != NULL; + phfill = 2; + for (i = 1; i < s1->nb_sections; i++) + if (s1->sections[i]->sh_flags & SHF_TLS) + phfill = 3; + phnum = 3; + if (interp) + phnum += phfill; + if (note) + phnum++; #if !TARGETOS_FreeBSD && !TARGETOS_NetBSD /* GNU_RELRO */ phnum++, roinf_use = &roinf; @@ -2679,7 +2690,7 @@ static int elf_output_file(TCCState *s1, const char *filename) /* put in GOT the dynamic section address and relocate PLT */ write32le(s1->got->data, dynamic->sh_addr); if (file_type == TCC_OUTPUT_EXE - || (RELOCATE_DLLPLT && file_type == TCC_OUTPUT_DLL)) + || (RELOCATE_DLLPLT && (file_type & TCC_OUTPUT_DYN))) relocate_plt(s1); /* relocate symbols in .dynsym now that final addresses are known */ diff --git a/x86_64-link.c b/x86_64-link.c index 8a609870..fe98b0b9 100644 --- a/x86_64-link.c +++ b/x86_64-link.c @@ -194,7 +194,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t switch (type) { case R_X86_64_64: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index; qrel->r_offset = rel->r_offset; if (esym_index) { @@ -212,7 +212,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t break; case R_X86_64_32: case R_X86_64_32S: - if (s1->output_type == TCC_OUTPUT_DLL) { + if (s1->output_type & TCC_OUTPUT_DYN) { /* XXX: this logic may depend on TCC's codegen now TCC uses R_X86_64_32 even for a 64bit pointer */ qrel->r_offset = rel->r_offset;