view release on metacpan or search on metacpan
src/Changelog view on Meta::CPAN
- Asm labels for variables and functions (Thomas Preud'homme)
- STT_GNU_IFUNC (Indirect functions as externals) (Thomas Preud'homme)
- More tests (tests2) (Milutin Jovanovic)
version 0.9.25:
- first support for x86-64 target (Shinichiro Hamaji)
- support µClibc
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
- improved preprocess output with linenumbers and spaces preserved
- tcc_relocate now copies code into user buffer
- fix bitfields with non-int types and in unions
- improve ARM cross-compiling (Daniel Glöckner)
- link stabstr sections from multiple objects
- better (still limited) support for multiple TCCStates
version 0.9.24:
- added verbosity levels -v, -vv, -vvv
- Accept standard input as an inputstream (Hanzac Chen)
- Support c89 compilers other than gcc (Hanzac Chen)
src/Changelog view on Meta::CPAN
441: Fix LL left shift in libtcc1.c:__shldi3 (grischka)
440: Pass structures and function ptrs through ?: (grischka)
439: Keep rvalue in bit assignment (bit2 = bit1 = x) (grischka)
438: Degrade nonportable pointer assignment to warning (grischka)
437: Call 'saveregs()' before jumping with logical and/or/not (grischka)
435: Put local static variables into global memory (grischka)
432/434: Cast double and ptr to bool (grischka)
420: Zero pad x87 tenbyte long doubles (Felix Nawothnig)
417: Make 'sizeof' unsigned (Rob Landley)
397: Fix save_reg for longlongs (Daniel Glöckner)
396: Fix "invalid relocation entry" problem on ubuntu - (Bernhard Fischer)
- ignore AS_NEEDED ld command
- mark executable sections as executable when running in memory
- added support for win32 wchar_t (Filip Navara)
- segment override prefix support (Filip Navara)
- normalized slashes in paths (Filip Navara)
- windows style fastcall (Filip Navara)
- support for empty input register section in asm (Filip Navara)
- anonymous union/struct support (Filip Navara)
- fixed parsing of function parameters
src/Changelog view on Meta::CPAN
error position display.
version 0.9.12:
- more fixes for || and && handling.
- improved '? :' type handling.
- fixed bound checking generation with structures
- force '#endif' to be in same file as matching '#if'
- #include file optimization with '#ifndef #endif' construct detection
- macro handling optimization
- added tcc_relocate() and tcc_get_symbol() in libtcc.
version 0.9.11:
- stdarg.h fix for double type (thanks to Philippe Ribet).
- correct white space characters and added MSDOS newline support.
- fixed invalid implicit function call type declaration.
- special macros such as __LINE__ are defined if tested with defined().
- fixed '!' operator with relocated address.
- added symbol + offset relocation (fixes some static variable initializers)
- '-l' option can be specified anywhere. '-c' option yields default
output name. added '-r' option for relocatable output.
- fixed '\nnn' octal parsing.
- fixed local extern variables declarations.
version 0.9.10:
- fixed lvalue type when saved in local stack.
- fixed '#include' syntax when using macros.
- fixed '#line' bug.
- removed size limit on strings. Unified string constants handling
with variable declarations.
- added correct support for '\xX' in wchar_t strings.
- added support for bound checking in generated executables
- fixed -I include order.
- fixed incorrect function displayed in runtime error.
version 0.9.9:
- fixed preprocessor expression parsing for #if/#elif.
- relocated debug info (.stab section).
- relocated bounds info (.bounds section).
- fixed cast to char of char constants ('\377' is -1 instead of 255)
- fixed implicit cast for unary plus.
- strings and '__func__' have now 'char[]' type instead of 'char *'
(fixes sizeof() return value).
- added __start_xxx and __stop_xxx symbols in linker.
- better DLL creation support (option -shared begins to work).
- ELF sections and hash tables are resized dynamically.
- executables and DLLs are stripped by default.
version 0.9.8:
src/Changelog view on Meta::CPAN
- added ELF file output (only usable for debugging now)
- added debug symbol generation (STAB format).
- added integrated runtime error analysis ('-g' option: print clear
run time error messages instead of "Segmentation fault").
- added first version of tiny memory and bound checker ('-b' option).
version 0.9.2:
- even faster parsing.
- various syntax parsing fixes.
- fixed external relocation handling for variables or functions pointers.
- better function pointers type handling.
- can compile multiple files (-i option).
- ANSI C bit fields are supported.
- beginning of float/double/long double support.
- beginning of long long support.
version 0.9.1:
- full ISOC99 initializers handling.
- compound literals.
src/arm-gen.c view on Meta::CPAN
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
#define CHAR_IS_UNSIGNED
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_ARM
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_ARM_ABS32
#define R_DATA_PTR R_ARM_ABS32
#define R_JMP_SLOT R_ARM_JUMP_SLOT
#define R_COPY R_ARM_COPY
#define ELF_START_ADDR 0x00008000
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
src/arm-gen.c view on Meta::CPAN
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
uint32_t x;
/* constant case */
x=encbranch(ind,ind+vtop->c.ul,0);
if(x) {
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym, ind, R_ARM_PC24);
} else
put_elf_reloc(symtab_section, cur_text_section, ind, R_ARM_PC24, 0);
o(x|(is_jmp?0xE0000000:0xE1000000));
} else {
if(!is_jmp)
o(0xE28FE004); // add lr,pc,#4
o(0xE51FF004); // ldr pc,[pc,#-4]
if (vtop->r & VT_SYM)
greloc(cur_text_section, vtop->sym, ind, R_ARM_ABS32);
src/c67-gen.c view on Meta::CPAN
#define LDOUBLE_SIZE 12
#define LDOUBLE_ALIGN 4
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 8
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_C60
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_C60_32
#define R_DATA_PTR R_C60_32
#define R_JMP_SLOT R_C60_JMP_SLOT
#define R_COPY R_C60_COPY
#define ELF_START_ADDR 0x00000400
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
src/c67-gen.c view on Meta::CPAN
int n, *ptr;
while (t) {
ptr = (int *) (cur_text_section->data + t);
{
Sym *sym;
// extract 32 bit address from MVKH/MVKL
n = ((*ptr >> 7) & 0xffff);
n |= ((*(ptr + 1) >> 7) & 0xffff) << 16;
// define a label that will be relocated
sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
greloc(cur_text_section, sym, t, R_C60LO16);
greloc(cur_text_section, sym, t + 4, R_C60HI16);
// clear out where the pointer was
*ptr &= ~(0xffff << 7);
*(ptr + 1) &= ~(0xffff << 7);
}
src/c67-gen.c view on Meta::CPAN
(0 << 0)); //parallel
} else
ALWAYS_ASSERT(FALSE);
#ifdef ASSEMBLY_LISTING_C67
fprintf(f, " %s %d %d %d\n", s, a, b, c);
#endif
}
//r=reg to load, fr=from reg, symbol for relocation, constant
void C67_MVKL(int r, int fc)
{
C67_asm("MVKL.", fc, r, 0);
}
void C67_MVKH(int r, int fc)
{
C67_asm("MVKH.", fc, r, 0);
}
src/c67-gen.c view on Meta::CPAN
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
Sym *sym;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
// get add into A0, then start the jump B3
greloc(cur_text_section, vtop->sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, vtop->sym, ind + 4, R_C60HI16);
C67_MVKL(C67_A0, 0); //r=reg to load, constant
C67_MVKH(C67_A0, 0); //r=reg to load, constant
C67_IREG_B_REG(0, C67_CREG_ZERO, C67_A0); // B.S2x A0
src/c67-gen.c view on Meta::CPAN
// Call, must load return address into B3 during delay slots
sym = get_sym_ref(&char_pointer_type, cur_text_section, ind + 12, 0); // symbol for return address
greloc(cur_text_section, sym, ind, R_C60LO16); // rem the inst need to be patched
greloc(cur_text_section, sym, ind + 4, R_C60HI16);
C67_MVKL(C67_B3, 0); //r=reg to load, constant
C67_MVKH(C67_B3, 0); //r=reg to load, constant
C67_NOP(3); // put remaining NOPs
}
} else {
/* put an empty PC32 relocation */
ALWAYS_ASSERT(FALSE);
}
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
C67_IREG_B_REG(0, C67_CREG_ZERO, r); // B.S2x r
if (is_jmp) {
C67_NOP(5); // simple jump, just put NOP
} else {
src/c67-gen.c view on Meta::CPAN
}
/* generate a jump to a fixed address */
void gjmp_addr(int a)
{
Sym *sym;
// I guess this routine is used for relative short
// local jumps, for now just handle it as the general
// case
// define a label that will be relocated
sym = get_sym_ref(&char_pointer_type, cur_text_section, a, 0);
greloc(cur_text_section, sym, ind, R_C60LO16);
greloc(cur_text_section, sym, ind + 4, R_C60HI16);
gjmp(0); // place a zero there later the symbol will be added to it
}
/* generate a test. set 'inv' to invert test. Stack entry is popped */
int gtst(int inv, int t)
long f_symptr; /* file pointer to symtab */
long f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
unsigned short f_TargetID; /* for C6x = 0x0099 */
};
/*------------------------------------------------------------------------*/
/* File header flags */
/*------------------------------------------------------------------------*/
#define F_RELFLG 0x01 /* relocation info stripped from file */
#define F_EXEC 0x02 /* file is executable (no unresolved refs) */
#define F_LNNO 0x04 /* line nunbers stripped from file */
#define F_LSYMS 0x08 /* local symbols stripped from file */
#define F_GSP10 0x10 /* 34010 version */
#define F_GSP20 0x20 /* 34020 version */
#define F_SWABD 0x40 /* bytes swabbed (in names) */
#define F_AR16WR 0x80 /* byte ordering of an AR16WR (PDP-11) */
#define F_LITTLE 0x100 /* byte ordering of an AR32WR (vax) */
#define F_BIG 0x200 /* byte ordering of an AR32W (3B, maxi) */
#define F_PATCH 0x400 /* contains "patch" list in optional header */
/*------------------------------------------------------------------------*/
/* SECTION HEADER */
/*------------------------------------------------------------------------*/
struct scnhdr {
char s_name[8]; /* section name */
long s_paddr; /* physical address */
long s_vaddr; /* virtual address */
long s_size; /* section size */
long s_scnptr; /* file ptr to raw data for section */
long s_relptr; /* file ptr to relocation */
long s_lnnoptr; /* file ptr to line numbers */
unsigned int s_nreloc; /* number of relocation entries */
unsigned int s_nlnno; /* number of line number entries */
unsigned int s_flags; /* flags */
unsigned short s_reserved; /* reserved byte */
unsigned short s_page; /* memory page id */
};
#define SCNHDR struct scnhdr
#define SCNHSZ sizeof(SCNHDR)
/*------------------------------------------------------------------------*/
/*------------------------------------------------------------------------*/
/* #define _TEXT ".text" */
#define _DATA ".data"
#define _BSS ".bss"
#define _CINIT ".cinit"
#define _TV ".tv"
/*------------------------------------------------------------------------*/
/* The low 4 bits of s_flags is used as a section "type" */
/*------------------------------------------------------------------------*/
#define STYP_REG 0x00 /* "regular" : allocated, relocated, loaded */
#define STYP_DSECT 0x01 /* "dummy" : not allocated, relocated, not loaded */
#define STYP_NOLOAD 0x02 /* "noload" : allocated, relocated, not loaded */
#define STYP_GROUP 0x04 /* "grouped" : formed of input sections */
#define STYP_PAD 0x08 /* "padding" : not allocated, not relocated, loaded */
#define STYP_COPY 0x10 /* "copy" : used for C init tables -
not allocated, relocated,
loaded; reloc & lineno
entries processed normally */
#define STYP_TEXT 0x20 /* section contains text only */
#define STYP_DATA 0x40 /* section contains data only */
#define STYP_BSS 0x80 /* section contains bss only */
#define STYP_ALIGN 0x100 /* align flag passed by old version assemblers */
#define ALIGN_MASK 0x0F00 /* part of s_flags that is used for align vals */
#define ALIGNSIZE(x) (1 << ((x & ALIGN_MASK) >> 8))
/*------------------------------------------------------------------------*/
/* RELOCATION ENTRIES */
/*------------------------------------------------------------------------*/
struct reloc
{
long r_vaddr; /* (virtual) address of reference */
short r_symndx; /* index into symbol table */
unsigned short r_disp; /* additional bits for address calculation */
unsigned short r_type; /* relocation type */
};
#define RELOC struct reloc
#define RELSZ 10 /* sizeof(RELOC) */
/*--------------------------------------------------------------------------*/
/* define all relocation types */
/*--------------------------------------------------------------------------*/
#define R_ABS 0 /* absolute address - no relocation */
#define R_DIR16 01 /* UNUSED */
#define R_REL16 02 /* UNUSED */
#define R_DIR24 04 /* UNUSED */
#define R_REL24 05 /* 24 bits, direct */
#define R_DIR32 06 /* UNUSED */
#define R_RELBYTE 017 /* 8 bits, direct */
#define R_RELWORD 020 /* 16 bits, direct */
#define R_RELLONG 021 /* 32 bits, direct */
#define R_PCRBYTE 022 /* 8 bits, PC-relative */
#define R_PCRWORD 023 /* 16 bits, PC-relative */
} x_fcnary;
unsigned short x_regcount; /* number of registers used by func */
} x_sym;
struct
{
char x_fname[FILNMLEN];
} x_file;
struct
{
long x_scnlen; /* section length */
unsigned short x_nreloc; /* number of relocation entries */
unsigned short x_nlinno; /* number of line numbers */
} x_scn;
};
#define SYMENT struct syment
#define SYMESZ 18 /* sizeof(SYMENT) */
#define AUXENT union auxent
#define AUXESZ 18 /* sizeof(AUXENT) */
#define DT_SONAME 14 /* Name of shared object */
#define DT_RPATH 15 /* Library search path */
#define DT_SYMBOLIC 16 /* Start symbol search here */
#define DT_REL 17 /* Address of Rel relocs */
#define DT_RELSZ 18 /* Total size of Rel relocs */
#define DT_RELENT 19 /* Size of one Rel reloc */
#define DT_PLTREL 20 /* Type of reloc in PLT */
#define DT_DEBUG 21 /* For debugging; unspecified */
#define DT_TEXTREL 22 /* Reloc might modify .text */
#define DT_JMPREL 23 /* Address of PLT relocs */
#define DT_BIND_NOW 24 /* Process relocations of object */
#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
#define DT_NUM 29 /* Number used */
#define DT_LOOS 0x60000000 /* Start of OS-specific */
#define DT_HIOS 0x6fffffff /* End of OS-specific */
#define DT_LOPROC 0x70000000 /* Start of processor-specific */
#define DT_HIPROC 0x7fffffff /* End of processor-specific */
#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
#define R_SPARC_REGISTER 53 /* Global register usage */
#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
/* Keep this the last entry. */
#define R_SPARC_NUM 56
/* AMD x86-64 relocations. */
#define R_X86_64_NONE 0 /* No reloc */
#define R_X86_64_64 1 /* Direct 64 bit */
#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
#define R_X86_64_PLT32 4 /* 32 bit PLT address */
#define R_X86_64_COPY 5 /* Copy symbol at runtime */
#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
#define R_X86_64_RELATIVE 8 /* Adjust by program base */
#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
DT_MIPS_DELTA_CLASS. */
#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
DT_MIPS_DELTA_INSTANCE. */
#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
DT_MIPS_DELTA_RELOC. */
#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
relocations refer to. */
#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
DT_MIPS_DELTA_SYM. */
#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
class declaration. */
#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
DT_MIPS_DELTA_CLASSSYM. */
#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
#define DT_MIPS_PIXIE_INIT 0x70000023
#define DT_MIPS_SYMBOL_LIB 0x70000024
#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
/* Legal values for sh_type field of Elf32_Shdr. */
#define SHT_PARISC_GOT 0x70000000 /* GOT for external data. */
#define SHT_PARISC_ARCH 0x70000001 /* Architecture extensions. */
#define SHT_PARISC_GLOBAL 0x70000002 /* Definition of $global$. */
#define SHT_PARISC_MILLI 0x70000003 /* Millicode routines. */
#define SHT_PARISC_UNWIND 0x70000004 /* Unwind information. */
#define SHT_PARISC_PLT 0x70000005 /* Procedure linkage table. */
#define SHT_PARISC_SDATA 0x70000006 /* Short initialized data. */
#define SHT_PARISC_SBSS 0x70000007 /* Short uninitialized data. */
#define SHT_PARISC_SYMEXTN 0x70000008 /* Argument/relocation info. */
#define SHT_PARISC_STUBS 0x70000009 /* Linker stubs. */
/* Legal values for sh_flags field of Elf32_Shdr. */
#define SHF_PARISC_GLOBAL 0x10000000 /* Section defines dp. */
#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
/* Legal values for ST_TYPE subfield of st_info (symbol type). */
#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
/* Keep this the last entry. */
#define R_ALPHA_NUM 28
/* PowerPC specific declarations */
/* PowerPC relocations defined by the ABIs */
#define R_PPC_NONE 0
#define R_PPC_ADDR32 1 /* 32bit absolute address */
#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
#define R_PPC_ADDR16 3 /* 16bit absolute address */
#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
#define R_PPC_ADDR14_BRTAKEN 8
#define R_PPC_ADDR14_BRNTAKEN 9
#define R_PPC_EMB_SDA2REL 108
#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
#define R_PPC_EMB_MRKREF 110
#define R_PPC_EMB_RELSEC16 111
#define R_PPC_EMB_RELST_LO 112
#define R_PPC_EMB_RELST_HI 113
#define R_PPC_EMB_RELST_HA 114
#define R_PPC_EMB_BIT_FLD 115
#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
/* Diab tool relocations. */
#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
/* This is a phony reloc to handle any old fashioned TOC16 references
that may still be in object files. */
#define R_PPC_TOC16 255
src/i386-asm.c view on Meta::CPAN
}
#endif
/* XXX: unify with C code output ? */
static void gen_disp32(ExprValue *pe)
{
Sym *sym = pe->sym;
if (sym && sym->r == cur_text_section->sh_num) {
/* same section: we can output an absolute value. Note
that the TCC compiler behaves differently here because
it always outputs a relocation to ease (future) code
elimination in the linker */
gen_le32(pe->v + sym->jnext - ind - 4);
} else {
if (sym && sym->type.t == VT_VOID) {
sym->type.t = VT_FUNC;
sym->type.ref = NULL;
}
gen_addrpc32(VT_SYM, sym, pe->v);
}
}
src/i386-asm.c view on Meta::CPAN
gen_le16(pe->v);
}
static void gen_disp16(ExprValue *pe)
{
Sym *sym;
sym = pe->sym;
if (sym) {
if (sym->r == cur_text_section->sh_num) {
/* same section: we can output an absolute value. Note
that the TCC compiler behaves differently here because
it always outputs a relocation to ease (future) code
elimination in the linker */
gen_le16(pe->v + sym->jnext - ind - 2);
} else {
greloc(cur_text_section, sym, ind, R_386_PC16);
gen_le16(pe->v - 2);
}
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,
ind, R_386_PC16, 0);
gen_le16(pe->v - 2);
}
}
#endif
/* generate the modrm operand */
static inline void asm_modrm(int reg, Operand *op)
{
src/i386-asm.c view on Meta::CPAN
#ifndef TCC_TARGET_X86_64
if (pa->opcode == 0x9a || pa->opcode == 0xea) {
/* ljmp or lcall kludge */
#ifdef I386_ASM_16
if (s1->seg_size == 16 && o32 == 0)
gen_expr16(&ops[1].e);
else
#endif
gen_expr32(&ops[1].e);
if (ops[0].e.sym)
tcc_error("cannot relocate");
gen_le16(ops[0].e.v);
return;
}
#endif
for(i = 0;i < nb_ops; i++) {
v = op_type[i];
if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) {
/* if multiple sizes are given it means we must look
at the op size */
if ((v | OP_IM8 | OP_IM64) == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64)) {
src/i386-asm.c view on Meta::CPAN
v = OP_IM8;
else if (s == 1)
v = OP_IM16;
else if (s == 2 || (v & OP_IM64) == 0)
v = OP_IM32;
else
v = OP_IM64;
}
if (v & (OP_IM8 | OP_IM8S)) {
if (ops[i].e.sym)
goto error_relocate;
g(ops[i].e.v);
} else if (v & OP_IM16) {
#ifdef I386_ASM_16
if (s1->seg_size == 16)
gen_expr16(&ops[i].e);
else
#endif
if (ops[i].e.sym)
error_relocate:
tcc_error("cannot relocate");
else
gen_le16(ops[i].e.v);
} else {
if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
if (is_short_jmp)
g(ops[i].e.v);
#ifdef I386_ASM_16
else if (s1->seg_size == 16)
gen_disp16(&ops[i].e);
#endif
src/i386-gen.c view on Meta::CPAN
#define MAX_ALIGN 8
#define psym oad
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_386
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_386_32
#define R_DATA_PTR R_386_32
#define R_JMP_SLOT R_386_JMP_SLOT
#define R_COPY R_386_COPY
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
src/i386-gen.c view on Meta::CPAN
o(c);
ind1 = ind + 4;
if (ind1 > cur_text_section->data_allocated)
section_realloc(cur_text_section, ind1);
*(int *)(cur_text_section->data + ind) = s;
s = ind;
ind = ind1;
return s;
}
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_386_32);
gen_le32(c);
}
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
src/i386-gen.c view on Meta::CPAN
greloc(cur_text_section, sym, ind-4, R_386_PC32);
}
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym,
ind + 1, R_386_PC32);
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,
ind + 1, R_386_PC32, 0);
}
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
} else {
/* otherwise, indirect call */
r = gv(RC_INT);
o(0xff); /* call/jmp *r */
o(0xd0 + r + (is_jmp << 4));
}
src/i386-gen.c view on Meta::CPAN
case 4: func = TOK___bound_ptr_indir4; break;
case 8: func = TOK___bound_ptr_indir8; break;
case 12: func = TOK___bound_ptr_indir12; break;
case 16: func = TOK___bound_ptr_indir16; break;
default:
tcc_error("unhandled size when dereferencing bounded pointer");
func = 0;
break;
}
/* patch relocation */
/* XXX: find a better solution ? */
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.ul);
sym = external_global_sym(func, &func_old_type, 0);
if (!sym->c)
put_extern_sym(sym, NULL, 0, 0);
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
}
#endif
/* Save the stack pointer onto the stack */
src/il-gen.c view on Meta::CPAN
goto no_var;
}
if (varstr) {
pstrcat(buf, buf_size, " ");
pstrcat(buf, buf_size, varstr);
}
no_var: ;
}
/* patch relocation entry with value 'val' */
void greloc_patch1(Reloc *p, int val)
{
}
/* output a symbol and patch all calls to it */
void gsym_addr(t, a)
{
}
/* output jump and return symbol */
src/libtcc.c view on Meta::CPAN
esym->st_shndx = sh_num;
}
}
ST_FUNC void put_extern_sym(Sym *sym, Section *section,
addr_t value, unsigned long size)
{
put_extern_sym2(sym, section, value, size, 1);
}
/* add a new relocation entry to symbol 'sym' in section 's' */
ST_FUNC void greloc(Section *s, Sym *sym, unsigned long offset, int type)
{
int c = 0;
if (sym) {
if (0 == sym->c)
put_extern_sym(sym, NULL, 0, 0);
c = sym->c;
}
/* now we can add ELF relocation info */
put_elf_reloc(symtab_section, s, offset, type, c);
}
/********************************************************/
static void strcat_vprintf(char *buf, int buf_size, const char *fmt, va_list ap)
{
int len;
len = strlen(buf);
vsnprintf(buf + len, buf_size - len, fmt, ap);
src/libtcc.h view on Meta::CPAN
/* equivalent to -Lpath option */
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);
/* the library name is the same as the argument of the '-l' option */
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);
/* add a symbol to the compiled program */
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val);
/* output an executable, library or object file. DO NOT call
tcc_relocate() before. */
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);
/* link and run main() function and return its value. DO NOT call
tcc_relocate() before. */
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()) */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* possible values for 'ptr':
- TCC_RELOCATE_AUTO : Allocate and manage memory internally
- NULL : return required memory size for the step below
- memory address : copy code to memory passed by the caller
returns -1 if error. */
#define TCC_RELOCATE_AUTO (void*)1
/* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);
src/tcc-doc.texi view on Meta::CPAN
Currently, MMX opcodes are supported but not SSE ones.
@node linker
@chapter TinyCC Linker
@cindex linker
@section ELF file generation
@cindex ELF
TCC can directly output relocatable ELF files (object files),
executable ELF files and dynamic ELF libraries without relying on an
external linker.
Dynamic ELF libraries can be output but the C compiler does not generate
position independent code (PIC). It means that the dynamic library
code generated by TCC cannot be factorized among processes yet.
TCC linker eliminates unreferenced object code in libraries. A single pass is
done on the object and library list, so the order in which object files and
libraries are specified is important (same constraint as GNU ld). No grouping
" -bench show compilation statistics\n"
"Preprocessor options:\n"
" -E preprocess only\n"
" -Idir add include path 'dir'\n"
" -Dsym[=val] define 'sym' with value 'val'\n"
" -Usym undefine 'sym'\n"
"Linker options:\n"
" -Ldir add library path 'dir'\n"
" -llib link with dynamic or static library 'lib'\n"
" -pthread link with -lpthread and -D_REENTRANT (POSIX Linux)\n"
" -r generate (relocatable) object file\n"
" -rdynamic export all global symbols to dynamic linker\n"
" -shared generate a shared library\n"
" -soname set name for shared library to be used at runtime\n"
" -static static linking\n"
" -Wl,-opt[=val] set linker option (see manual)\n"
"Debugger options:\n"
" -g generate runtime debug info\n"
#ifdef CONFIG_TCC_BCHECK
" -b compile with built-in memory and bounds checker (implies -g)\n"
#endif
unsigned char *data; /* section data */
unsigned long data_allocated; /* used for realloc() handling */
int sh_name; /* elf section name (only used during output) */
int sh_num; /* elf section number */
int sh_type; /* elf section type */
int sh_flags; /* elf section flags */
int sh_info; /* elf section info */
int sh_addralign; /* elf section alignment */
int sh_entsize; /* elf entry size */
unsigned long sh_size; /* section size (only used during output) */
addr_t sh_addr; /* address at which the section is relocated */
unsigned long sh_offset; /* file offset */
int nb_hashed_syms; /* used to resize the hash table */
struct Section *link; /* link to another section */
struct Section *reloc; /* corresponding section for relocation, if any */
struct Section *hash; /* hash table for symbols */
struct Section *next;
char name[1]; /* section name */
} Section;
typedef struct DLLReference {
int level;
void *handle;
char name[1];
} DLLReference;
unsigned pe_stack_size;
# ifdef TCC_TARGET_X86_64
Section *uw_pdata;
int uw_sym;
unsigned uw_offs;
# endif
#endif
#ifdef TCC_IS_NATIVE
const char *runtime_main;
/* for tcc_relocate */
void *runtime_mem;
# ifdef HAVE_SELINUX
void *write_mem;
unsigned long mem_size;
# endif
# if !defined TCC_TARGET_PE && (defined TCC_TARGET_X86_64 || defined TCC_TARGET_ARM)
/* write PLT and GOT here */
char *runtime_plt_and_got;
unsigned runtime_plt_and_got_offset;
# define TCC_HAS_RUNTIME_PLTGOT
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int shndx, const char *name);
ST_FUNC int add_elf_sym(Section *s, addr_t value, unsigned long size, int info, int other, int sh_num, const char *name);
ST_FUNC int find_elf_sym(Section *s, const char *name);
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, int type, int symbol);
ST_FUNC void put_stabs(const char *str, int type, int other, int desc, unsigned long value);
ST_FUNC void put_stabs_r(const char *str, int type, int other, int desc, unsigned long value, Section *sec, int sym_index);
ST_FUNC void put_stabn(int type, int other, int desc, int value);
ST_FUNC void put_stabd(int type, int other, int desc);
ST_FUNC void relocate_common_syms(void);
ST_FUNC void relocate_syms(TCCState *s1, int do_resolve);
ST_FUNC void relocate_section(TCCState *s1, Section *s);
ST_FUNC void tcc_add_linker_symbols(TCCState *s1);
ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
ST_FUNC int tcc_load_archive(TCCState *s1, int fd);
ST_FUNC void tcc_add_bcheck(TCCState *s1);
ST_FUNC void build_got_entries(TCCState *s1);
ST_FUNC void tcc_add_runtime(TCCState *s1);
ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err);
src/tccasm.c view on Meta::CPAN
asm_expr_logic(s1, pe);
for(;;) {
op = tok;
if (op != '+' && op != '-')
break;
next();
asm_expr_logic(s1, &e2);
if (op == '+') {
if (pe->sym != NULL && e2.sym != NULL)
goto cannot_relocate;
pe->v += e2.v;
if (pe->sym == NULL && e2.sym != NULL)
pe->sym = e2.sym;
} else {
pe->v -= e2.v;
/* NOTE: we are less powerful than gas in that case
because we store only one symbol in the expression */
if (!pe->sym && !e2.sym) {
/* OK */
} else if (pe->sym && !e2.sym) {
/* OK */
} else if (pe->sym && e2.sym) {
if (pe->sym == e2.sym) {
/* OK */
} else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
/* we also accept defined symbols in the same section */
pe->v += pe->sym->jnext - e2.sym->jnext;
} else {
goto cannot_relocate;
}
pe->sym = NULL; /* same symbols can be substracted to NULL */
} else {
cannot_relocate:
tcc_error("invalid operation with label");
}
}
}
}
ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe)
{
asm_expr_sum(s1, pe);
}
src/tcccoff.c view on Meta::CPAN
if (CoffTextSectionNo == -1 && tcc_sect == stext)
CoffTextSectionNo = NSectionsToOutput; // rem which coff sect number the .text sect is
strcpy(coff_sec->s_name, tcc_sect->name); /* section name */
coff_sec->s_paddr = tcc_sect->sh_addr; /* physical address */
coff_sec->s_vaddr = tcc_sect->sh_addr; /* virtual address */
coff_sec->s_size = tcc_sect->data_offset; /* section size */
coff_sec->s_scnptr = 0; /* file ptr to raw data for section */
coff_sec->s_relptr = 0; /* file ptr to relocation */
coff_sec->s_lnnoptr = 0; /* file ptr to line numbers */
coff_sec->s_nreloc = 0; /* number of relocation entries */
coff_sec->s_flags = GetCoffFlags(coff_sec->s_name); /* flags */
coff_sec->s_reserved = 0; /* reserved byte */
coff_sec->s_page = 0; /* memory page id */
file_pointer += sizeof(SCNHDR);
}
}
file_hdr.f_nscns = NSectionsToOutput; /* number of sections */
src/tcccoff.c view on Meta::CPAN
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
// put raw data
coff_sec->s_scnptr = file_pointer; /* file ptr to raw data for section */
file_pointer += coff_sec->s_size;
}
}
// now loop through and determine file pointer locations
// for the relocation data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = §ion_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
// put relocations data
if (coff_sec->s_nreloc > 0) {
coff_sec->s_relptr = file_pointer; /* file ptr to relocation */
file_pointer += coff_sec->s_nreloc * sizeof(struct reloc);
}
}
}
// now loop through and determine file pointer locations
// for the line number data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = §ion_header[i];
src/tcccoff.c view on Meta::CPAN
// write raw data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = §ion_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
fwrite(tcc_sect->data, tcc_sect->data_offset, 1, f);
}
}
// write relocation data
for (i = 1; i < s1->nb_sections; i++) {
coff_sec = §ion_header[i];
tcc_sect = s1->sections[i];
if (OutputTheSection(tcc_sect)) {
// put relocations data
if (coff_sec->s_nreloc > 0) {
fwrite(tcc_sect->reloc,
coff_sec->s_nreloc * sizeof(struct reloc), 1, f);
}
}
}
// group the symbols in order of filename, func1, func2, etc
// finally global symbols
src/tccelf.c view on Meta::CPAN
}
} else {
do_def:
sym_index = put_elf_sym(s, value, size,
ELFW(ST_INFO)(sym_bind, sym_type), other,
sh_num, name);
}
return sym_index;
}
/* put relocation */
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
int type, int symbol)
{
char buf[256];
Section *sr;
ElfW_Rel *rel;
sr = s->reloc;
if (!sr) {
/* if no relocation section, create it */
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
/* if the symtab is allocated, then we consider the relocation
are also */
sr = new_section(tcc_state, buf, SHT_RELX, symtab->sh_flags);
sr->sh_entsize = sizeof(ElfW_Rel);
sr->link = symtab;
sr->sh_info = s->sh_num;
s->reloc = sr;
}
rel = section_ptr_add(sr, sizeof(ElfW_Rel));
rel->r_offset = offset;
rel->r_info = ELFW(R_INFO)(symbol, type);
src/tccelf.c view on Meta::CPAN
put_stabs(NULL, type, other, desc, value);
}
ST_FUNC void put_stabd(int type, int other, int desc)
{
put_stabs(NULL, type, other, desc, 0);
}
/* In an ELF file symbol table, the local symbols must appear below
the global and weak ones. Since TCC cannot sort it while generating
the code, we must do it after. All the relocation tables are also
modified to take into account the symbol table sorting */
static void sort_syms(TCCState *s1, Section *s)
{
int *old_to_new_syms;
ElfW(Sym) *new_syms;
int nb_syms, i;
ElfW(Sym) *p, *q;
ElfW_Rel *rel, *rel_end;
Section *sr;
int type, sym_index;
src/tccelf.c view on Meta::CPAN
old_to_new_syms[i] = q - new_syms;
*q++ = *p;
}
p++;
}
/* we copy the new symbols to the old */
memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym)));
tcc_free(new_syms);
/* now we modify all the relocations */
for(i = 1; i < s1->nb_sections; i++) {
sr = s1->sections[i];
if (sr->sh_type == SHT_RELX && sr->link == s) {
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
for(rel = (ElfW_Rel *)sr->data;
rel < rel_end;
rel++) {
sym_index = ELFW(R_SYM)(rel->r_info);
type = ELFW(R_TYPE)(rel->r_info);
sym_index = old_to_new_syms[sym_index];
rel->r_info = ELFW(R_INFO)(sym_index, type);
}
}
}
tcc_free(old_to_new_syms);
}
/* relocate common symbols in the .bss section */
ST_FUNC void relocate_common_syms(void)
{
ElfW(Sym) *sym, *sym_end;
unsigned long offset, align;
sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
for(sym = (ElfW(Sym) *)symtab_section->data + 1;
sym < sym_end;
sym++) {
if (sym->st_shndx == SHN_COMMON) {
/* align symbol */
src/tccelf.c view on Meta::CPAN
offset = bss_section->data_offset;
offset = (offset + align - 1) & -align;
sym->st_value = offset;
sym->st_shndx = bss_section->sh_num;
offset += sym->st_size;
bss_section->data_offset = offset;
}
}
}
/* relocate symbol table, resolve undefined symbols if do_resolve is
true and output error if undefined symbol. */
ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
{
ElfW(Sym) *sym, *esym, *sym_end;
int sym_bind, sh_num, sym_index;
const char *name;
sym_end = (ElfW(Sym) *)(symtab_section->data + symtab_section->data_offset);
for(sym = (ElfW(Sym) *)symtab_section->data + 1;
sym < sym_end;
sym++) {
sh_num = sym->st_shndx;
src/tccelf.c view on Meta::CPAN
uint32_t *p = (uint32_t *)(s1->runtime_plt_and_got + s1->runtime_plt_and_got_offset);
s1->runtime_plt_and_got_offset += JMP_TABLE_ENTRY_SIZE;
/* ldr pc, [pc, #-4] */
p[0] = 0xE51FF004;
p[1] = val;
return (addr_t)p;
}
#endif
#endif /* def TCC_HAS_RUNTIME_PLTGOT */
/* relocate a given section (CPU dependent) */
ST_FUNC void relocate_section(TCCState *s1, Section *s)
{
Section *sr;
ElfW_Rel *rel, *rel_end, *qrel;
ElfW(Sym) *sym;
int type, sym_index;
unsigned char *ptr;
addr_t val, addr;
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
int esym_index;
#endif
src/tccelf.c view on Meta::CPAN
break;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_386_RELATIVE);
qrel++;
}
}
*(int *)ptr += val;
break;
case R_386_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
esym_index = s1->symtab_to_dynsym[sym_index];
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_386_PC32);
qrel++;
break;
}
}
*(int *)ptr += val - addr;
break;
src/tccelf.c view on Meta::CPAN
if (s1->output_type == TCC_OUTPUT_MEMORY) {
if ((x & 3) || x >= 0x2000000 || x < -0x2000000)
if (!(x & 3) || !blx_avail || !is_call) {
x += add_jmp_table(s1, val) - val; /* add veneer */
is_thumb = 0; /* Veneer uses ARM instructions */
}
}
#endif
if ((x & 3) || x >= 0x2000000 || x < -0x2000000)
if (!(x & 3) || !blx_avail || !is_call)
tcc_error("can't relocate value at %x",addr);
x >>= 2;
x &= 0xffffff;
/* Only reached if blx is avail and it is a call */
if (is_thumb) {
x |= h << 24;
(*(int *)ptr) = 0xfa << 24; /* bl -> blx */
}
(*(int *)ptr) |= x;
}
break;
/* Since these relocations only concern Thumb-2 and blx instruction was
introduced before Thumb-2, we can assume blx is available and not
guard its use */
case R_ARM_THM_CALL:
case R_ARM_THM_JUMP24:
{
int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11;
int to_thumb, is_call, to_plt, blx_bit = 1 << 12;
Section *plt;
/* weak reference */
src/tccelf.c view on Meta::CPAN
/* Compute final offset */
if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */
x -= 4;
x += val - addr;
if (!to_thumb && is_call) {
blx_bit = 0; /* bl -> blx */
x = (x + 3) & -4; /* Compute offset from aligned PC */
}
/* Check that relocation is possible
* offset must not be out of range
* if target is to be entered in arm mode:
- bit 1 must not set
- instruction must be a call (bl) or a jump to PLT */
if (!to_thumb || x >= 0x1000000 || x < -0x1000000)
if (to_thumb || (val & 2) || (!is_call && !to_plt))
tcc_error("can't relocate value at %x",addr);
/* Compute and store final offset */
s = (x >> 24) & 1;
i1 = (x >> 23) & 1;
i2 = (x >> 22) & 1;
j1 = s ^ (i1 ^ 1);
j2 = s ^ (i2 ^ 1);
imm10 = (x >> 12) & 0x3ff;
imm11 = (x >> 1) & 0x7ff;
(*(uint16_t *)ptr) = (uint16_t) ((hi & 0xf800) |
src/tccelf.c view on Meta::CPAN
}
break;
case R_ARM_PREL31:
{
int x;
x = (*(int *)ptr) & 0x7fffffff;
(*(int *)ptr) &= 0x80000000;
x = (x * 2) / 2;
x += val - addr;
if((x^(x>>1))&0x40000000)
tcc_error("can't relocate value at %x",addr);
(*(int *)ptr) |= x & 0x7fffffff;
}
case R_ARM_ABS32:
*(int *)ptr += val;
break;
case R_ARM_REL32:
*(int *)ptr += val - addr;
break;
case R_ARM_BASE_PREL:
*(int *)ptr += s1->got->sh_addr - addr;
src/tccelf.c view on Meta::CPAN
now TCC uses R_X86_64_32 even for a 64bit pointer */
qrel->r_info = ELFW(R_INFO)(0, R_X86_64_RELATIVE);
qrel->r_addend = *(int *)ptr + val;
qrel++;
}
*(int *)ptr += val;
break;
case R_X86_64_PC32:
if (s1->output_type == TCC_OUTPUT_DLL) {
/* DLL relocation */
esym_index = s1->symtab_to_dynsym[sym_index];
if (esym_index) {
qrel->r_offset = rel->r_offset;
qrel->r_info = ELFW(R_INFO)(esym_index, R_X86_64_PC32);
qrel->r_addend = *(int *)ptr;
qrel++;
break;
}
}
/* fall through */
src/tccelf.c view on Meta::CPAN
if (diff <= -2147483647 || diff > 2147483647) {
#ifdef TCC_HAS_RUNTIME_PLTGOT
/* XXX: naive support for over 32bit jump */
if (s1->output_type == TCC_OUTPUT_MEMORY) {
val = (add_jmp_table(s1, val - rel->r_addend) +
rel->r_addend);
diff = val - addr;
}
#endif
if (diff <= -2147483647 || diff > 2147483647) {
tcc_error("internal error: relocation failed");
}
}
*(int *)ptr += diff;
}
break;
case R_X86_64_GLOB_DAT:
case R_X86_64_JUMP_SLOT:
/* They don't need addend */
*(int *)ptr = val - rel->r_addend;
break;
src/tccelf.c view on Meta::CPAN
break;
case R_X86_64_GOT32:
/* we load the got offset */
*(int *)ptr += s1->sym_attrs[sym_index].got_offset;
break;
#else
#error unsupported processor
#endif
}
}
/* if the relocation is allocated, we change its symbol table */
if (sr->sh_flags & SHF_ALLOC)
sr->link = s1->dynsym;
}
/* relocate relocation table in 'sr' */
static void relocate_rel(TCCState *s1, Section *sr)
{
Section *s;
ElfW_Rel *rel, *rel_end;
s = s1->sections[sr->sh_info];
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
for(rel = (ElfW_Rel *)sr->data;
rel < rel_end;
rel++) {
rel->r_offset += s->sh_addr;
}
}
/* count the number of dynamic relocations so that we can reserve
their space */
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
{
ElfW_Rel *rel, *rel_end;
int sym_index, esym_index, type, count;
count = 0;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
sym_index = ELFW(R_SYM)(rel->r_info);
src/tccelf.c view on Meta::CPAN
p = section_ptr_add(plt, 16);
p[0] = 0xff; /* jmp *(got + x) */
p[1] = modrm;
put32(p + 2, s1->got->data_offset);
p[6] = 0x68; /* push $xxx */
put32(p + 7, (plt->data_offset - 32) >> 1);
p[11] = 0xe9; /* jmp plt_start */
put32(p + 12, -(plt->data_offset));
/* the symbol is modified so that it will be relocated to
the PLT */
#if !defined(TCC_OUTPUT_DLL_WITH_PLT)
if (s1->output_type == TCC_OUTPUT_EXE)
#endif
offset = plt->data_offset - 16;
}
#elif defined(TCC_TARGET_ARM)
if (reloc_type == R_ARM_JUMP_SLOT) {
Section *plt;
uint8_t *p;
src/tccelf.c view on Meta::CPAN
put32(p , 0x4778); // bx pc
put32(p+2, 0x46c0); // nop
p += 4;
} else
p = section_ptr_add(plt, 16);
put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT
put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset
put32(p+8, 0xe59cf000); // ldr pc, [ip] // load absolute address or load offset
put32(p+12, s1->got->data_offset);
/* the symbol is modified so that it will be relocated to
the PLT */
if (s1->output_type == TCC_OUTPUT_EXE)
offset = plt->data_offset - 16;
}
#elif defined(TCC_TARGET_C67)
tcc_error("C67 got not implemented");
#else
#error unsupported CPU
#endif
index = put_elf_sym(s1->dynsym, offset,
src/tccelf.c view on Meta::CPAN
{
Section *s;
ElfW_Rel *rel, *rel_end;
ElfW(Sym) *sym;
int i, type, reloc_type, sym_index;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_type != SHT_RELX)
continue;
/* no need to handle got relocations */
if (s->link != symtab_section)
continue;
rel_end = (ElfW_Rel *)(s->data + s->data_offset);
for(rel = (ElfW_Rel *)s->data;
rel < rel_end;
rel++) {
type = ELFW(R_TYPE)(rel->r_info);
switch(type) {
#if defined(TCC_TARGET_I386)
case R_386_GOT32:
src/tccelf.c view on Meta::CPAN
fwrite(s->data, 1, size, f);
offset += size;
}
}
}
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
#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
src/tccelf.c view on Meta::CPAN
ST_FUNC void fill_got(TCCState *s1)
{
Section *s;
ElfW_Rel *rel, *rel_end;
int i;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_type != SHT_RELX)
continue;
/* no need to handle got relocations */
if (s->link != symtab_section)
continue;
rel_end = (ElfW_Rel *) (s->data + s->data_offset);
for(rel = (ElfW_Rel *) s->data; rel < rel_end; rel++) {
switch (ELFW(R_TYPE) (rel->r_info)) {
case R_X86_64_GOT32:
case R_X86_64_GOTPCREL:
case R_X86_64_PLT32:
fill_got_entry(s1, rel);
break;
src/tccelf.c view on Meta::CPAN
}
phdr = NULL;
section_order = NULL;
interp = NULL;
dynamic = NULL;
dynstr = NULL; /* avoid warning */
saved_dynamic_data_offset = 0; /* avoid warning */
if (file_type != TCC_OUTPUT_OBJ) {
relocate_common_syms();
tcc_add_linker_symbols(s1);
if (!s1->static_link) {
const char *name;
int sym_index, index;
ElfW(Sym) *esym, *sym_end;
if (file_type == TCC_OUTPUT_EXE) {
char *ptr;
src/tccelf.c view on Meta::CPAN
s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
SHF_ALLOC | SHF_EXECINSTR);
s1->plt->sh_entsize = 4;
build_got(s1);
/* scan for undefined symbols and see if they are in the
dynamic symbols. If a symbol STT_FUNC or STT_GNU_IFUNC
is found, then we add it in the PLT. If a symbol
STT_OBJECT is found, we add it in the .bss section with
a suitable relocation */
sym_end = (ElfW(Sym) *)(symtab_section->data +
symtab_section->data_offset);
if (file_type == TCC_OUTPUT_EXE) {
for(sym = (ElfW(Sym) *)symtab_section->data + 1;
sym < sym_end;
sym++) {
if (sym->st_shndx == SHN_UNDEF) {
name = symtab_section->link->data + sym->st_name;
sym_index = find_elf_sym(s1->dynsymtab_section, name);
if (sym_index) {
src/tccelf.c view on Meta::CPAN
for(i = 0; i < s1->nb_loaded_dlls; i++) {
DLLReference *dllref = s1->loaded_dlls[i];
if (dllref->level == 0)
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
}
if (s1->rpath)
put_dt(dynamic, DT_RPATH, put_elf_str(dynstr, s1->rpath));
/* XXX: currently, since we do not handle PIC code, we
must relocate the readonly segments */
if (file_type == TCC_OUTPUT_DLL) {
if (s1->soname)
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
put_dt(dynamic, DT_TEXTREL, 0);
}
if (s1->symbolic)
put_dt(dynamic, DT_SYMBOLIC, 0);
/* add necessary space for other entries */
src/tccelf.c view on Meta::CPAN
s->sh_name = put_elf_str(strsec, s->name);
#if 0 /* gr */
printf("section: f=%08x t=%08x i=%08x %s %s\n",
s->sh_flags,
s->sh_type,
s->sh_info,
s->name,
s->reloc ? s->reloc->name : "n"
);
#endif
/* when generating a DLL, we include relocations but we may
patch them */
if (file_type == TCC_OUTPUT_DLL &&
s->sh_type == SHT_RELX &&
!(s->sh_flags & SHF_ALLOC)) {
/* //gr: avoid bogus relocs for empty (debug) sections */
if (s1->sections[s->sh_info]->sh_flags & SHF_ALLOC)
prepare_dynamic_rel(s1, s);
else if (s1->do_debug)
s->sh_size = s->data_offset;
} else if (s1->do_debug ||
src/tccelf.c view on Meta::CPAN
file_offset += (a_offset - p_offset);
} else {
if (file_type == TCC_OUTPUT_DLL)
addr = 0;
else
addr = ELF_START_ADDR;
/* compute address after headers */
addr += (file_offset & (s1->section_align - 1));
}
/* dynamic relocation table information, for .dynamic section */
rel_size = 0;
rel_addr = 0;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
bss_addr = bss_size = 0;
#endif
/* leave one program header for the program interpreter */
ph = &phdr[0];
if (interp)
ph += 1 + HAVE_PHDR;
for(j = 0; j < 2; j++) {
ph->p_type = PT_LOAD;
if (j == 0)
ph->p_flags = PF_R | PF_X;
else
ph->p_flags = PF_R | PF_W;
ph->p_align = s1->section_align;
/* we do the following ordering: interp, symbol tables,
relocations, progbits, nobits */
/* XXX: do faster and simpler sorting */
for(k = 0; k < 5; k++) {
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
/* compute if section should be included */
if (j == 0) {
if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE)) !=
SHF_ALLOC)
continue;
} else {
src/tccelf.c view on Meta::CPAN
file_offset += (int) ( addr - tmp );
s->sh_offset = file_offset;
s->sh_addr = addr;
/* update program header infos */
if (ph->p_offset == 0) {
ph->p_offset = file_offset;
ph->p_vaddr = addr;
ph->p_paddr = ph->p_vaddr;
}
/* update dynamic relocation infos */
if (s->sh_type == SHT_RELX) {
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
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.
}
src/tccelf.c view on Meta::CPAN
ph->p_vaddr = dynamic->sh_addr;
ph->p_paddr = ph->p_vaddr;
ph->p_filesz = dynamic->sh_size;
ph->p_memsz = dynamic->sh_size;
ph->p_flags = PF_R | PF_W;
ph->p_align = dynamic->sh_addralign;
/* put GOT dynamic section address */
put32(s1->got->data, dynamic->sh_addr);
/* relocate the PLT */
if (file_type == TCC_OUTPUT_EXE
#if defined(TCC_OUTPUT_DLL_WITH_PLT)
|| file_type == TCC_OUTPUT_DLL
#endif
) {
uint8_t *p, *p_end;
p = s1->plt->data;
p_end = p + s1->plt->data_offset;
if (p < p_end) {
src/tccelf.c view on Meta::CPAN
p += 16;
}
#elif defined(TCC_TARGET_C67)
/* XXX: TODO */
#else
#error unsupported CPU
#endif
}
}
/* relocate symbols in .dynsym */
sym_end = (ElfW(Sym) *)(s1->dynsym->data + s1->dynsym->data_offset);
for(sym = (ElfW(Sym) *)s1->dynsym->data + 1;
sym < sym_end;
sym++) {
if (sym->st_shndx == SHN_UNDEF) {
/* relocate to the PLT if the symbol corresponds
to a PLT entry */
if (sym->st_value)
sym->st_value += s1->plt->sh_addr;
} else if (sym->st_shndx < SHN_LORESERVE) {
/* do symbol relocation */
sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
}
}
/* put dynamic section entries */
dynamic->data_offset = saved_dynamic_data_offset;
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
put_dt(dynamic, DT_STRTAB, dynstr->sh_addr);
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
put_dt(dynamic, DT_STRSZ, dynstr->data_offset);
src/tccelf.c view on Meta::CPAN
continue;
section_order[sh_order_index++] = i;
file_offset = (file_offset + s->sh_addralign - 1) &
~(s->sh_addralign - 1);
s->sh_offset = file_offset;
if (s->sh_type != SHT_NOBITS)
file_offset += s->sh_size;
}
/* if building executable or DLL, then relocate each section
except the GOT which is already relocated */
if (file_type != TCC_OUTPUT_OBJ) {
relocate_syms(s1, 0);
if (s1->nb_errors != 0) {
fail:
ret = -1;
goto the_end;
}
/* relocate sections */
/* XXX: ignore sections with allocated relocations ? */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->reloc && s != s1->got)
relocate_section(s1, s);
}
/* relocate relocation entries if the relocation tables are
allocated in the executable */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if ((s->sh_flags & SHF_ALLOC) &&
s->sh_type == SHT_RELX) {
relocate_rel(s1, s);
}
}
/* get entry point address */
if (file_type == TCC_OUTPUT_EXE)
ehdr.e_entry = get_elf_sym_addr(s1, "_start", 1);
else
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
}
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
src/tccelf.c view on Meta::CPAN
unsigned char *ptr;
lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
ptr = section_ptr_add(s, size);
read(fd, ptr, size);
} else {
s->data_offset += size;
}
next: ;
}
/* //gr relocate stab strings */
if (stab_index && stabstr_index) {
Stab_Sym *a, *b;
unsigned o;
s = sm_table[stab_index].s;
a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
b = (Stab_Sym *)(s->data + s->data_offset);
o = sm_table[stabstr_index].offset;
while (a < b)
a->n_strx += o, a++;
}
src/tccelf.c view on Meta::CPAN
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
sym = symtab + 1;
for(i = 1; i < nb_syms; i++, sym++) {
if (sym->st_shndx != SHN_UNDEF &&
sym->st_shndx < SHN_LORESERVE) {
sm = &sm_table[sym->st_shndx];
if (sm->link_once) {
/* if a symbol is in a link once section, we use the
already defined symbol. It is very important to get
correct relocations */
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
name = strtab + sym->st_name;
sym_index = find_elf_sym(symtab_section, name);
if (sym_index)
old_to_new_syms[i] = sym_index;
}
continue;
}
/* if no corresponding section added, no need to add symbol */
if (!sm->s)
src/tccelf.c view on Meta::CPAN
sym->st_value += sm->offset;
}
/* add symbol */
name = strtab + sym->st_name;
sym_index = add_elf_sym(symtab_section, sym->st_value, sym->st_size,
sym->st_info, sym->st_other,
sym->st_shndx, name);
old_to_new_syms[i] = sym_index;
}
/* third pass to patch relocation entries */
for(i = 1; i < ehdr.e_shnum; i++) {
s = sm_table[i].s;
if (!s)
continue;
sh = &shdr[i];
offset = sm_table[i].offset;
switch(s->sh_type) {
case SHT_RELX:
/* take relocation offset information */
offseti = sm_table[sh->sh_info].offset;
rel_end = (ElfW_Rel *)(s->data + s->data_offset);
for(rel = (ElfW_Rel *)(s->data + offset);
rel < rel_end;
rel++) {
int type;
unsigned sym_index;
/* convert symbol index */
type = ELFW(R_TYPE)(rel->r_info);
sym_index = ELFW(R_SYM)(rel->r_info);
src/tccelf.c view on Meta::CPAN
if (sym_index >= nb_syms)
goto invalid_reloc;
sym_index = old_to_new_syms[sym_index];
/* ignore link_once in rel section. */
if (!sym_index && !sm->link_once
#ifdef TCC_TARGET_ARM
&& type != R_ARM_V4BX
#endif
) {
invalid_reloc:
tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x",
i, strsec + sh->sh_name, rel->r_offset);
goto fail;
}
rel->r_info = ELFW(R_INFO)(sym_index, type);
/* offset the relocation offset */
rel->r_offset += offseti;
#ifdef TCC_TARGET_ARM
/* Jumps and branches from a Thumb code to a PLT entry need
special handling since PLT entries are ARM code.
Unconditional bl instructions referencing PLT entries are
handled by converting these instructions into blx
instructions. Other case of instructions referencing a PLT
entry require to add a Thumb stub before the PLT entry to
switch to ARM mode. We set bit 0 of the got offset of a
symbol to indicate such a case. */
src/tccgen.c view on Meta::CPAN
sv.c.ul += 4;
store(p->r2, &sv);
}
#endif
l = loc;
saved = 1;
}
/* mark that stack entry as being saved on the stack */
if (p->r & VT_LVAL) {
/* also clear the bounded flag because the
relocation address of the function was stored in
p->c.ul */
p->r = (p->r & ~(VT_VALMASK | VT_BOUNDED)) | VT_LLOCAL;
} else {
p->r = lvalue_type(p->type.t) | VT_LOCAL;
}
p->r2 = VT_CONST;
p->c.ul = l;
}
}
}
src/tccgen.c view on Meta::CPAN
case EXPR_ANY:
expr_eq();
break;
}
dtype = *type;
dtype.t &= ~VT_CONSTANT; /* need to do that to avoid false warning */
if (sec) {
/* XXX: not portable */
/* XXX: generate error if incorrect relocation */
gen_assign_cast(&dtype);
bt = type->t & VT_BTYPE;
/* we'll write at most 12 bytes */
if (c + 12 > sec->data_allocated) {
section_realloc(sec, c + 12);
}
ptr = sec->data + c;
/* XXX: make code faster ? */
if (!(type->t & VT_BITFIELD)) {
bit_pos = 0;
src/tccgen.c view on Meta::CPAN
sym = get_sym_ref(type, sec, addr, size);
cval.ul = 0;
vsetc(type, VT_CONST | VT_SYM, &cval);
vtop->sym = sym;
}
/* patch symbol weakness */
if (type->t & VT_WEAK)
weaken_symbol(sym);
#ifdef CONFIG_TCC_BCHECK
/* handles bounds now because the symbol must be defined
before for the relocation */
if (tcc_state->do_bounds_check) {
unsigned long *bounds_ptr;
greloc(bounds_section, sym, bounds_section->data_offset, R_DATA_PTR);
/* then add global bound info */
bounds_ptr = section_ptr_add(bounds_section, 2 * sizeof(long));
bounds_ptr[0] = 0; /* relocated */
bounds_ptr[1] = size;
}
#endif
}
if (has_init || (type->t & VT_VLA)) {
decl_initializer(type, sec, addr, 1, 0);
/* restore parse state if needed */
if (init_str.str) {
tok_str_free(init_str.str);
restore_parse_state(&saved_parse_state);
src/tccpe.c view on Meta::CPAN
WORD e_cp; /* Pages in file */
WORD e_crlc; /* Relocations */
WORD e_cparhdr; /* Size of header in paragraphs */
WORD e_minalloc; /* Minimum extra paragraphs needed */
WORD e_maxalloc; /* Maximum extra paragraphs needed */
WORD e_ss; /* Initial (relative) SS value */
WORD e_sp; /* Initial SP value */
WORD e_csum; /* Checksum */
WORD e_ip; /* Initial IP value */
WORD e_cs; /* Initial (relative) CS value */
WORD e_lfarlc; /* File address of relocation table */
WORD e_ovno; /* Overlay number */
WORD e_res[4]; /* Reserved words */
WORD e_oemid; /* OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* OEM information; e_oemid specific */
WORD e_res2[10]; /* Reserved words */
DWORD e_lfanew; /* File address of new exe header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
#define SIZE_OF_NT_SIGNATURE 4
src/tccpe.c view on Meta::CPAN
0x0004, /*WORD e_cparhdr; Size of header in paragraphs */
0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */
0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */
0x0000, /*WORD e_ss; Initial (relative) SS value */
0x00B8, /*WORD e_sp; Initial SP value */
0x0000, /*WORD e_csum; Checksum */
0x0000, /*WORD e_ip; Initial IP value */
0x0000, /*WORD e_cs; Initial (relative) CS value */
0x0040, /*WORD e_lfarlc; File address of relocation table */
0x0000, /*WORD e_ovno; Overlay number */
{0,0,0,0}, /*WORD e_res[4]; Reserved words */
0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */
0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */
{0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */
0x00000080 /*DWORD e_lfanew; File address of new exe header */
},{
/* BYTE dosstub[0x40] */
/* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */
0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
src/tccpe.c view on Meta::CPAN
} else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose)
printf("<- %s (%d symbols)\n", buf, sym_count);
}
#endif
for (ord = 0; ord < sym_count; ++ord)
{
p = sorted[ord], sym_index = p->index, name = p->name;
/* insert actual address later in pe_relocate_rva */
put_elf_reloc(symtab_section, pe->thunk,
func_o, R_XXX_RELATIVE, sym_index);
*(DWORD*)(pe->thunk->data + name_o)
= pe->thunk->data_offset + rva_base;
*(WORD*)(pe->thunk->data + ord_o)
= ord;
put_elf_str(pe->thunk, name);
func_o += sizeof (DWORD);
name_o += sizeof (DWORD);
ord_o += sizeof (WORD);
src/tccpe.c view on Meta::CPAN
);
}
pe->s1->verbose = 2;
#endif
tcc_free(section_order);
return 0;
}
/* ------------------------------------------------------------- */
static void pe_relocate_rva (struct pe_info *pe, Section *s)
{
Section *sr = s->reloc;
ElfW_Rel *rel, *rel_end;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) {
int sym_index = ELFW(R_SYM)(rel->r_info);
DWORD addr = s->sh_addr;
if (sym_index) {
ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
src/tccpe.c view on Meta::CPAN
d = pe_add_uwwind_info(s1);
pd = s1->uw_pdata;
o = pd->data_offset;
p = section_ptr_add(pd, sizeof *p);
/* record this function */
p->BeginAddress = start;
p->EndAddress = end;
p->UnwindData = d;
/* put relocations on it */
for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress)
put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym);
}
#endif
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n
#else
#define PE_STDSYM(n,s) "_" n s
#endif
src/tccpe.c view on Meta::CPAN
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{
const char *start_symbol;
int pe_type = 0;
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
pe_type = PE_GUI;
else
if (TCC_OUTPUT_DLL == s1->output_type) {
pe_type = PE_DLL;
/* need this for 'tccelf.c:relocate_section()' */
s1->output_type = TCC_OUTPUT_EXE;
}
else
pe_type = PE_EXE;
start_symbol =
TCC_OUTPUT_MEMORY == s1->output_type
? PE_GUI == pe_type ? "__runwinmain" : "_main"
: PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
: PE_GUI == pe_type ? "__winstart" : "__start"
src/tccpe.c view on Meta::CPAN
int ret;
struct pe_info pe;
int i;
memset(&pe, 0, sizeof pe);
pe.filename = filename;
pe.s1 = s1;
tcc_add_bcheck(s1);
pe_add_runtime(s1, &pe);
relocate_common_syms(); /* assign bss adresses */
tcc_add_linker_symbols(s1);
ret = pe_check_symbols(&pe);
if (ret)
;
else if (filename) {
if (PE_DLL == pe.type) {
pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
/* XXX: check if is correct for arm-pe target */
pe.imagebase = 0x10000000;
src/tccpe.c view on Meta::CPAN
if (s1->pe_file_align != 0)
pe.file_align = s1->pe_file_align;
if ((pe.subsystem >= 10) && (pe.subsystem <= 12))
pe.imagebase = 0;
if (s1->has_text_addr)
pe.imagebase = s1->text_addr;
pe_assign_addresses(&pe);
relocate_syms(s1, 0);
for (i = 1; i < s1->nb_sections; ++i) {
Section *s = s1->sections[i];
if (s->reloc) {
relocate_section(s1, s);
pe_relocate_rva(&pe, s);
}
}
if (s1->nb_errors)
ret = -1;
else
ret = pe_write(&pe);
tcc_free(pe.sec_info);
} else {
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;
src/tccrun.c view on Meta::CPAN
#endif
#ifdef _WIN32
#define ucontext_t CONTEXT
#endif
static void set_pages_executable(void *ptr, unsigned long length);
static void set_exception_handler(void);
static int rt_get_caller_pc(addr_t *paddr, ucontext_t *uc, int level);
static void rt_error(ucontext_t *uc, const char *fmt, ...);
static int tcc_relocate_ex(TCCState *s1, void *ptr);
#ifdef _WIN64
static void win64_add_function_table(TCCState *s1);
#endif
/* ------------------------------------------------------------- */
/* Do all relocations (needed before using tcc_get_symbol())
Returns -1 on error. */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr)
{
int ret;
if (TCC_RELOCATE_AUTO != ptr)
return tcc_relocate_ex(s1, ptr);
ret = tcc_relocate_ex(s1, NULL);
if (ret < 0)
return ret;
#ifdef HAVE_SELINUX
{ /* Use mmap instead of malloc for Selinux. Ref:
http://www.gnu.org/s/libc/manual/html_node/File-Size.html */
char tmpfname[] = "/tmp/.tccrunXXXXXX";
int fd = mkstemp (tmpfname);
src/tccrun.c view on Meta::CPAN
s1->write_mem = mmap (NULL, ret, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
if (s1->write_mem == MAP_FAILED)
tcc_error("/tmp not writeable");
s1->runtime_mem = mmap (NULL, ret, PROT_READ|PROT_EXEC,
MAP_SHARED, fd, 0);
if (s1->runtime_mem == MAP_FAILED)
tcc_error("/tmp not executable");
ret = tcc_relocate_ex(s1, s1->write_mem);
}
#else
s1->runtime_mem = tcc_malloc(ret);
ret = tcc_relocate_ex(s1, s1->runtime_mem);
#endif
return ret;
}
/* launch the compiled program with the given arguments */
LIBTCCAPI int tcc_run(TCCState *s1, int argc, char **argv)
{
int (*prog_main)(int, char **);
int ret;
if (tcc_relocate(s1, TCC_RELOCATE_AUTO) < 0)
return -1;
prog_main = tcc_get_symbol_err(s1, s1->runtime_main);
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_debug) {
set_exception_handler();
rt_prog_main = prog_main;
}
#endif
src/tccrun.c view on Meta::CPAN
bound_exit = tcc_get_symbol_err(s1, "__bound_exit");
bound_init();
ret = (*prog_main)(argc, argv);
bound_exit();
} else
#endif
ret = (*prog_main)(argc, argv);
return ret;
}
/* relocate code. Return -1 on error, required size if ptr is NULL,
otherwise copy code into buffer passed by the caller */
static int tcc_relocate_ex(TCCState *s1, void *ptr)
{
Section *s;
unsigned long offset, length;
addr_t mem;
int i;
if (NULL == ptr) {
s1->nb_errors = 0;
#ifdef TCC_TARGET_PE
pe_output_file(s1, NULL);
#else
tcc_add_runtime(s1);
relocate_common_syms();
tcc_add_linker_symbols(s1);
build_got_entries(s1);
#endif
if (s1->nb_errors)
return -1;
}
offset = 0, mem = (addr_t)ptr;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
s->sh_addr = mem ? (mem + offset + 15) & ~15 : 0;
offset = (offset + length + 15) & ~15;
}
offset += 16;
/* relocate symbols */
relocate_syms(s1, 1);
if (s1->nb_errors)
return -1;
#ifdef TCC_HAS_RUNTIME_PLTGOT
s1->runtime_plt_and_got_offset = 0;
s1->runtime_plt_and_got = (char *)(mem + offset);
/* double the size of the buffer for got and plt entries
XXX: calculate exact size for them? */
offset *= 2;
#endif
if (0 == mem)
return offset;
/* relocate each section */
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->reloc)
relocate_section(s1, s);
}
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
// printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
ptr = (void*)s->sh_addr;
if (NULL == s->data || s->sh_type == SHT_NOBITS)
src/x86_64-gen.c view on Meta::CPAN
#define LDOUBLE_SIZE 16
#define LDOUBLE_ALIGN 16
/* maximum alignment (for aligned attribute support) */
#define MAX_ALIGN 16
/******************************************************/
/* ELF defines */
#define EM_TCC_TARGET EM_X86_64
/* relocation type for 32 bit data relocation */
#define R_DATA_32 R_X86_64_32
#define R_DATA_PTR R_X86_64_64
#define R_JMP_SLOT R_X86_64_JUMP_SLOT
#define R_COPY R_X86_64_COPY
#define ELF_START_ADDR 0x08048000
#define ELF_PAGE_SIZE 0x1000
/******************************************************/
#else /* ! TARGET_DEFS_ONLY */
src/x86_64-gen.c view on Meta::CPAN
return s;
}
ST_FUNC void gen_addr32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_X86_64_32);
gen_le32(c);
}
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addr64(int r, Sym *sym, int64_t c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_X86_64_64);
gen_le64(c);
}
/* output constant with relocation if 'r & VT_SYM' is true */
ST_FUNC void gen_addrpc32(int r, Sym *sym, int c)
{
if (r & VT_SYM)
greloc(cur_text_section, sym, ind, R_X86_64_PC32);
gen_le32(c-4);
}
/* output got address with relocation */
static void gen_gotpcrel(int r, Sym *sym, int c)
{
#ifndef TCC_TARGET_PE
Section *sr;
ElfW(Rela) *rel;
greloc(cur_text_section, sym, ind, R_X86_64_GOTPCREL);
sr = cur_text_section->reloc;
rel = (ElfW(Rela) *)(sr->data + sr->data_offset - sizeof(ElfW(Rela)));
rel->r_addend = -4;
#else
src/x86_64-gen.c view on Meta::CPAN
}
}
/* 'is_jmp' is '1' if it is a jump */
static void gcall_or_jmp(int is_jmp)
{
int r;
if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
/* constant case */
if (vtop->r & VT_SYM) {
/* relocation case */
greloc(cur_text_section, vtop->sym,
ind + 1, R_X86_64_PC32);
} else {
/* put an empty PC32 relocation */
put_elf_reloc(symtab_section, cur_text_section,
ind + 1, R_X86_64_PC32, 0);
}
oad(0xe8 + is_jmp, vtop->c.ul - 4); /* call/jmp im */
} else {
/* otherwise, indirect call */
r = TREG_R11;
load(r, vtop);
o(0x41); /* REX */
o(0xff); /* call/jmp *r */