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(-)
This commit is contained in:
grischka 2022-05-28 21:00:40 +02:00
parent e460f7dbb2
commit ebaa5c81f4
13 changed files with 100 additions and 76 deletions

View File

@ -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

View File

@ -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);

View File

@ -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) {

View File

@ -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;

1
elf.h
View File

@ -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

View File

@ -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) {

View File

@ -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");

View File

@ -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);

View File

@ -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) {

5
tcc.h
View File

@ -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 "!<arch>\012" /* For COFF and a.out archives */

View File

@ -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) {

115
tccelf.c
View File

@ -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 */

View File

@ -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;