1
0
Fork 0
tinycc/tccpe.c

2104 lines
64 KiB
C
Raw Permalink Normal View History

/*
* TCCPE.C - PE file output for the Tiny C Compiler
*
* Copyright (c) 2005-2007 grischka
2005-04-11 00:46:58 +03:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "tcc.h"
2005-04-11 00:46:58 +03:00
#define PE_MERGE_DATA 1
#define PE_PRINT_SECTIONS 0
2016-10-18 00:24:01 +03:00
#ifndef _WIN32
#define stricmp strcasecmp
#define strnicmp strncasecmp
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
#include <sys/stat.h> /* chmod() */
#endif
2009-07-06 22:35:25 +03:00
#ifdef TCC_TARGET_X86_64
# define ADDR3264 ULONGLONG
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64
2014-08-01 11:51:28 +03:00
# define REL_TYPE_DIRECT R_X86_64_64
# define R_XXX_THUNKFIX R_X86_64_PC32
# define R_XXX_RELATIVE R_X86_64_RELATIVE
# define R_XXX_FUNCCALL R_X86_64_PLT32
2014-08-01 11:51:28 +03:00
# define IMAGE_FILE_MACHINE 0x8664
# define RSRC_RELTYPE 3
#elif defined TCC_TARGET_ARM
# define ADDR3264 DWORD
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
2014-08-01 11:51:28 +03:00
# define REL_TYPE_DIRECT R_ARM_ABS32
# define R_XXX_THUNKFIX R_ARM_ABS32
# define R_XXX_RELATIVE R_ARM_RELATIVE
# define R_XXX_FUNCCALL R_ARM_PC24
# define R_XXX_FUNCCALL2 R_ARM_ABS32
2014-08-01 11:51:28 +03:00
# define IMAGE_FILE_MACHINE 0x01C0
# define RSRC_RELTYPE 7 /* ??? (not tested) */
#elif defined TCC_TARGET_I386
2009-07-06 22:35:25 +03:00
# define ADDR3264 DWORD
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW
2014-08-01 11:51:28 +03:00
# define REL_TYPE_DIRECT R_386_32
# define R_XXX_THUNKFIX R_386_32
# define R_XXX_RELATIVE R_386_RELATIVE
# define R_XXX_FUNCCALL R_386_PC32
2014-08-01 11:51:28 +03:00
# define IMAGE_FILE_MACHINE 0x014C
# define RSRC_RELTYPE 7 /* DIR32NB */
2009-07-06 22:35:25 +03:00
#endif
#ifndef IMAGE_NT_SIGNATURE
/* ----------------------------------------------------------- */
/* definitions below are from winnt.h */
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
2009-07-06 22:35:25 +03:00
typedef unsigned long long ULONGLONG;
#pragma pack(push, 1)
typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */
WORD e_magic; /* Magic number */
WORD e_cblp; /* Bytes on last page of file */
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 */
2005-04-11 00:46:58 +03:00
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
2005-04-11 00:46:58 +03:00
#define SIZE_OF_NT_SIGNATURE 4
typedef struct _IMAGE_FILE_HEADER {
WORD Machine;
WORD NumberOfSections;
DWORD TimeDateStamp;
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
WORD SizeOfOptionalHeader;
WORD Characteristics;
2005-04-11 00:46:58 +03:00
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
#define IMAGE_SIZEOF_FILE_HEADER 20
typedef struct _IMAGE_DATA_DIRECTORY {
DWORD VirtualAddress;
DWORD Size;
2005-04-11 00:46:58 +03:00
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER {
/* Standard fields. */
WORD Magic;
BYTE MajorLinkerVersion;
BYTE MinorLinkerVersion;
DWORD SizeOfCode;
DWORD SizeOfInitializedData;
DWORD SizeOfUninitializedData;
DWORD AddressOfEntryPoint;
DWORD BaseOfCode;
2009-07-06 22:35:25 +03:00
#ifndef TCC_TARGET_X86_64
DWORD BaseOfData;
2009-07-06 22:35:25 +03:00
#endif
2005-04-11 00:46:58 +03:00
/* NT additional fields. */
2009-07-06 22:35:25 +03:00
ADDR3264 ImageBase;
DWORD SectionAlignment;
DWORD FileAlignment;
WORD MajorOperatingSystemVersion;
WORD MinorOperatingSystemVersion;
WORD MajorImageVersion;
WORD MinorImageVersion;
WORD MajorSubsystemVersion;
WORD MinorSubsystemVersion;
DWORD Win32VersionValue;
DWORD SizeOfImage;
DWORD SizeOfHeaders;
DWORD CheckSum;
WORD Subsystem;
WORD DllCharacteristics;
2009-07-06 22:35:25 +03:00
ADDR3264 SizeOfStackReserve;
ADDR3264 SizeOfStackCommit;
ADDR3264 SizeOfHeapReserve;
ADDR3264 SizeOfHeapCommit;
DWORD LoaderFlags;
DWORD NumberOfRvaAndSizes;
2005-04-11 00:46:58 +03:00
IMAGE_DATA_DIRECTORY DataDirectory[16];
2009-07-06 22:35:25 +03:00
} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER;
2005-04-11 00:46:58 +03:00
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */
2005-04-11 00:46:58 +03:00
/* IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) */
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 /* Architecture Specific Data */
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* RVA of GP */
#define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */
#define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 /* Delay Load Import Descriptors */
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 /* COM Runtime descriptor */
2005-04-11 00:46:58 +03:00
/* Section header format. */
#define IMAGE_SIZEOF_SHORT_NAME 8
2005-04-11 00:46:58 +03:00
typedef struct _IMAGE_SECTION_HEADER {
BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
2005-04-11 00:46:58 +03:00
union {
DWORD PhysicalAddress;
DWORD VirtualSize;
2005-04-11 00:46:58 +03:00
} Misc;
DWORD VirtualAddress;
DWORD SizeOfRawData;
DWORD PointerToRawData;
DWORD PointerToRelocations;
DWORD PointerToLinenumbers;
WORD NumberOfRelocations;
WORD NumberOfLinenumbers;
DWORD Characteristics;
2005-04-11 00:46:58 +03:00
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
#define IMAGE_SIZEOF_SECTION_HEADER 40
2005-04-11 00:46:58 +03:00
2009-07-06 22:35:35 +03:00
typedef struct _IMAGE_EXPORT_DIRECTORY {
DWORD Characteristics;
DWORD TimeDateStamp;
WORD MajorVersion;
WORD MinorVersion;
DWORD Name;
DWORD Base;
DWORD NumberOfFunctions;
DWORD NumberOfNames;
DWORD AddressOfFunctions;
DWORD AddressOfNames;
DWORD AddressOfNameOrdinals;
} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY;
typedef struct _IMAGE_IMPORT_DESCRIPTOR {
union {
2009-07-18 23:06:54 +03:00
DWORD Characteristics;
DWORD OriginalFirstThunk;
2009-07-06 22:35:35 +03:00
};
DWORD TimeDateStamp;
DWORD ForwarderChain;
DWORD Name;
DWORD FirstThunk;
} IMAGE_IMPORT_DESCRIPTOR;
2005-04-11 00:46:58 +03:00
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress;
DWORD SizeOfBlock;
2005-04-11 00:46:58 +03:00
// WORD TypeOffset[1];
} IMAGE_BASE_RELOCATION;
#define IMAGE_SIZEOF_BASE_RELOCATION 8
2005-04-11 00:46:58 +03:00
#define IMAGE_REL_BASED_ABSOLUTE 0
#define IMAGE_REL_BASED_HIGH 1
#define IMAGE_REL_BASED_LOW 2
#define IMAGE_REL_BASED_HIGHLOW 3
#define IMAGE_REL_BASED_HIGHADJ 4
#define IMAGE_REL_BASED_MIPS_JMPADDR 5
#define IMAGE_REL_BASED_SECTION 6
#define IMAGE_REL_BASED_REL32 7
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
#define IMAGE_REL_BASED_DIR64 10
2005-04-11 00:46:58 +03:00
#define IMAGE_SCN_CNT_CODE 0x00000020
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000
#define IMAGE_SCN_MEM_SHARED 0x10000000
#define IMAGE_SCN_MEM_EXECUTE 0x20000000
#define IMAGE_SCN_MEM_READ 0x40000000
#define IMAGE_SCN_MEM_WRITE 0x80000000
#pragma pack(pop)
2005-04-11 00:46:58 +03:00
/* ----------------------------------------------------------- */
#endif /* ndef IMAGE_NT_SIGNATURE */
/* ----------------------------------------------------------- */
2005-04-11 00:46:58 +03:00
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
#ifndef IMAGE_REL_BASED_DIR64
# define IMAGE_REL_BASED_DIR64 10
#endif
#pragma pack(push, 1)
struct pe_header
{
IMAGE_DOS_HEADER doshdr;
BYTE dosstub[0x40];
DWORD nt_sig;
IMAGE_FILE_HEADER filehdr;
2009-07-06 22:35:25 +03:00
#ifdef TCC_TARGET_X86_64
IMAGE_OPTIONAL_HEADER64 opthdr;
#else
#ifdef _WIN64
IMAGE_OPTIONAL_HEADER32 opthdr;
#else
IMAGE_OPTIONAL_HEADER opthdr;
2009-07-06 22:35:25 +03:00
#endif
#endif
2005-04-11 00:46:58 +03:00
};
struct pe_reloc_header {
DWORD offset;
DWORD size;
};
struct pe_rsrc_header {
struct _IMAGE_FILE_HEADER filehdr;
struct _IMAGE_SECTION_HEADER sectionhdr;
};
struct pe_rsrc_reloc {
DWORD offset;
DWORD size;
WORD type;
};
#pragma pack(pop)
2005-04-11 00:46:58 +03:00
/* ------------------------------------------------------------- */
/* internal temporary structures */
enum {
sec_text = 0,
sec_rdata ,
sec_data ,
sec_bss ,
sec_idata ,
sec_pdata ,
sec_other ,
sec_rsrc ,
sec_debug ,
sec_reloc ,
sec_last
2005-04-11 00:46:58 +03:00
};
#if 0
static const DWORD pe_sec_flags[] = {
0x60000020, /* ".text" , */
0xC0000040, /* ".data" , */
0xC0000080, /* ".bss" , */
0x40000040, /* ".idata" , */
0x40000040, /* ".pdata" , */
0xE0000060, /* < other > , */
0x40000040, /* ".rsrc" , */
0x42000802, /* ".stab" , */
0x42000040, /* ".reloc" , */
2005-04-11 00:46:58 +03:00
};
#endif
2005-04-11 00:46:58 +03:00
struct section_info {
2020-01-17 23:58:39 +02:00
int cls;
char name[32];
ADDR3264 sh_addr;
2005-04-11 00:46:58 +03:00
DWORD sh_size;
DWORD pe_flags;
2020-01-17 23:58:39 +02:00
Section *sec;
2005-04-11 00:46:58 +03:00
DWORD data_size;
IMAGE_SECTION_HEADER ish;
2005-04-11 00:46:58 +03:00
};
struct import_symbol {
int sym_index;
int iat_index;
int thk_offset;
2005-04-11 00:46:58 +03:00
};
struct pe_import_info {
int dll_index;
int sym_count;
struct import_symbol **symbols;
};
struct pe_info {
TCCState *s1;
Section *reloc;
Section *thunk;
2005-04-11 00:46:58 +03:00
const char *filename;
int type;
2005-04-11 00:46:58 +03:00
DWORD sizeofheaders;
ADDR3264 imagebase;
const char *start_symbol;
2005-04-11 00:46:58 +03:00
DWORD start_addr;
DWORD imp_offs;
DWORD imp_size;
DWORD iat_offs;
DWORD iat_size;
DWORD exp_offs;
DWORD exp_size;
int subsystem;
DWORD section_align;
DWORD file_align;
2020-01-17 23:58:39 +02:00
struct section_info **sec_info;
2005-04-11 00:46:58 +03:00
int sec_count;
struct pe_import_info **imp_info;
int imp_count;
};
#define PE_NUL 0
#define PE_DLL 1
#define PE_GUI 2
#define PE_EXE 3
#define PE_RUN 4
2005-04-11 00:46:58 +03:00
/* --------------------------------------------*/
static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym)
{
const char *name = (char*)symtab_section->link->data + sym->st_name;
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL))
return name + 1;
return name;
}
static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
{
char buffer[200];
const char *s, *p;
int sym_index = 0, n = 0;
int a, err = 0;
do {
s = pe_export_name(s1, sym);
a = 0;
if (n) {
/* second try: */
if (sym->st_other & ST_PE_STDCALL) {
/* try w/0 stdcall deco (windows API convention) */
p = strrchr(s, '@');
if (!p || s[0] != '_')
break;
strcpy(buffer, s+1)[p-s-1] = 0;
} else if (s[0] != '_') { /* try non-ansi function */
buffer[0] = '_', strcpy(buffer + 1, s);
} else if (0 == memcmp(s, "__imp_", 6)) { /* mingw 2.0 */
strcpy(buffer, s + 6), a = 1;
} else if (0 == memcmp(s, "_imp__", 6)) { /* mingw 3.7 */
strcpy(buffer, s + 6), a = 1;
} else {
continue;
}
s = buffer;
}
sym_index = find_elf_sym(s1->dynsymtab_section, s);
// printf("find (%d) %d %s\n", n, sym_index, s);
if (sym_index
&& ELFW(ST_TYPE)(sym->st_info) == STT_OBJECT
&& 0 == (sym->st_other & ST_PE_IMPORT)
&& 0 == a
) err = -1, sym_index = 0;
} while (0 == sym_index && ++n < 2);
return n == 2 ? err : sym_index;
2005-04-11 00:46:58 +03:00
}
/*----------------------------------------------------------------------------*/
static int dynarray_assoc(void **pp, int n, int key)
2005-04-11 00:46:58 +03:00
{
int i;
for (i = 0; i < n; ++i, ++pp)
if (key == **(int **) pp)
return i;
2005-04-11 00:46:58 +03:00
return -1;
}
2020-01-17 23:58:39 +02:00
static DWORD umin(DWORD a, DWORD b)
2005-04-11 00:46:58 +03:00
{
return a < b ? a : b;
}
static DWORD umax(DWORD a, DWORD b)
2005-04-11 00:46:58 +03:00
{
return a < b ? b : a;
}
static DWORD pe_file_align(struct pe_info *pe, DWORD n)
2005-04-11 00:46:58 +03:00
{
return (n + (pe->file_align - 1)) & ~(pe->file_align - 1);
2005-04-11 00:46:58 +03:00
}
static ADDR3264 pe_virtual_align(struct pe_info *pe, ADDR3264 n)
2005-04-11 00:46:58 +03:00
{
return (n + (pe->section_align - 1)) & ~(ADDR3264)(pe->section_align - 1);
2005-04-11 00:46:58 +03:00
}
static void pe_align_section(Section *s, int a)
2005-04-11 00:46:58 +03:00
{
int i = s->data_offset & (a-1);
2005-04-11 00:46:58 +03:00
if (i)
section_ptr_add(s, a - i);
2005-04-11 00:46:58 +03:00
}
static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size)
{
2009-07-18 23:07:42 +03:00
hdr->opthdr.DataDirectory[dir].VirtualAddress = addr;
hdr->opthdr.DataDirectory[dir].Size = size;
}
2005-04-11 00:46:58 +03:00
2020-01-17 23:58:39 +02:00
struct pe_file {
FILE *op;
DWORD sum;
unsigned pos;
};
static int pe_fwrite(const void *data, int len, struct pe_file *pf)
2009-07-23 20:19:23 +03:00
{
const WORD *p = data;
2020-01-17 23:58:39 +02:00
DWORD sum;
int ret, i;
pf->pos += (ret = fwrite(data, 1, len, pf->op));
sum = pf->sum;
for (i = len; i > 0; i -= 2) {
sum += (i >= 2) ? *p++ : *(BYTE*)p;
sum = (sum + (sum >> 16)) & 0xFFFF;
2009-07-23 20:19:23 +03:00
}
2020-01-17 23:58:39 +02:00
pf->sum = sum;
return len == ret ? 0 : -1;
2009-07-23 20:19:23 +03:00
}
2020-01-17 23:58:39 +02:00
static void pe_fpad(struct pe_file *pf, DWORD new_pos)
2009-07-23 20:19:23 +03:00
{
2020-01-17 23:58:39 +02:00
char buf[256];
int n, diff = new_pos - pf->pos;
memset(buf, 0, sizeof buf);
while (diff > 0) {
diff -= n = umin(diff, sizeof buf);
fwrite(buf, n, 1, pf->op);
}
pf->pos = new_pos;
2009-07-23 20:19:23 +03:00
}
/*----------------------------------------------------------------------------*/
/* PE-DWARF/COFF support
does not work with a mingw-gdb really but works with cv2pdb
(https://github.com/rainers/cv2pdb) */
#define N_COFF_SYMS 0
static const char dwarf_secs[] =
{
".debug_info\0"
".debug_abbrev\0"
".debug_line\0"
".debug_aranges\0"
".debug_str\0"
".debug_line_str\0"
};
static const unsigned coff_strtab_size = 4 + sizeof dwarf_secs - 1;
static int pe_put_long_secname(char *secname, const char *name)
{
const char *d = dwarf_secs;
do {
if (0 == strcmp(d, name)) {
sprintf(secname, "/%d", (int)(d - dwarf_secs + 4));
return 1;
}
d = strchr(d, 0) + 1;
} while (*d);
return 0;
}
static void pe_create_pdb(TCCState *s1, const char *exename)
{
char buf[300]; int r;
snprintf(buf, sizeof buf, "cv2pdb.exe %s", exename);
r = system(buf);
strcpy(tcc_fileextension(strcpy(buf, exename)), ".pdb");
if (r) {
tcc_error_noabort("could not create '%s'\n(need working cv2pdb from https://github.com/rainers/cv2pdb)", buf);
} else if (s1->verbose) {
printf("<- %s\n", buf);
}
}
2005-04-11 00:46:58 +03:00
/*----------------------------------------------------------------------------*/
static int pe_write(struct pe_info *pe)
2005-04-11 00:46:58 +03:00
{
2009-07-18 23:07:42 +03:00
static const struct pe_header pe_template = {
{
/* IMAGE_DOS_HEADER doshdr */
0x5A4D, /*WORD e_magic; Magic number */
0x0090, /*WORD e_cblp; Bytes on last page of file */
0x0003, /*WORD e_cp; Pages in file */
0x0000, /*WORD e_crlc; Relocations */
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,
0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
},
0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
{
/* IMAGE_FILE_HEADER filehdr */
2014-08-01 11:51:28 +03:00
IMAGE_FILE_MACHINE, /*WORD Machine; */
2009-07-18 23:07:42 +03:00
0x0003, /*WORD NumberOfSections; */
0x00000000, /*DWORD TimeDateStamp; */
0x00000000, /*DWORD PointerToSymbolTable; */
0x00000000, /*DWORD NumberOfSymbols; */
2009-08-27 11:25:28 +03:00
#if defined(TCC_TARGET_X86_64)
2009-07-18 23:07:42 +03:00
0x00F0, /*WORD SizeOfOptionalHeader; */
0x022F /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x222E
2009-08-27 11:25:28 +03:00
#elif defined(TCC_TARGET_I386)
2009-07-18 23:07:42 +03:00
0x00E0, /*WORD SizeOfOptionalHeader; */
0x030F /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x230E
2009-08-27 11:25:28 +03:00
#elif defined(TCC_TARGET_ARM)
0x00E0, /*WORD SizeOfOptionalHeader; */
0x010F, /*WORD Characteristics; */
#define CHARACTERISTICS_DLL 0x230F
2009-07-18 23:07:42 +03:00
#endif
},{
/* IMAGE_OPTIONAL_HEADER opthdr */
/* Standard fields. */
#ifdef TCC_TARGET_X86_64
0x020B, /*WORD Magic; */
#else
0x010B, /*WORD Magic; */
#endif
0x06, /*BYTE MajorLinkerVersion; */
0x00, /*BYTE MinorLinkerVersion; */
0x00000000, /*DWORD SizeOfCode; */
0x00000000, /*DWORD SizeOfInitializedData; */
0x00000000, /*DWORD SizeOfUninitializedData; */
0x00000000, /*DWORD AddressOfEntryPoint; */
0x00000000, /*DWORD BaseOfCode; */
#ifndef TCC_TARGET_X86_64
0x00000000, /*DWORD BaseOfData; */
#endif
/* NT additional fields. */
2009-08-27 11:25:28 +03:00
#if defined(TCC_TARGET_ARM)
0x00100000, /*DWORD ImageBase; */
2009-08-27 11:25:28 +03:00
#else
0x00400000, /*DWORD ImageBase; */
2009-08-27 11:25:28 +03:00
#endif
2009-07-18 23:07:42 +03:00
0x00001000, /*DWORD SectionAlignment; */
0x00000200, /*DWORD FileAlignment; */
0x0004, /*WORD MajorOperatingSystemVersion; */
0x0000, /*WORD MinorOperatingSystemVersion; */
0x0000, /*WORD MajorImageVersion; */
0x0000, /*WORD MinorImageVersion; */
0x0004, /*WORD MajorSubsystemVersion; */
0x0000, /*WORD MinorSubsystemVersion; */
0x00000000, /*DWORD Win32VersionValue; */
0x00000000, /*DWORD SizeOfImage; */
0x00000200, /*DWORD SizeOfHeaders; */
0x00000000, /*DWORD CheckSum; */
0x0002, /*WORD Subsystem; */
0x0000, /*WORD DllCharacteristics; */
0x00100000, /*DWORD SizeOfStackReserve; */
0x00001000, /*DWORD SizeOfStackCommit; */
0x00100000, /*DWORD SizeOfHeapReserve; */
0x00001000, /*DWORD SizeOfHeapCommit; */
0x00000000, /*DWORD LoaderFlags; */
0x00000010, /*DWORD NumberOfRvaAndSizes; */
/* IMAGE_DATA_DIRECTORY DataDirectory[16]; */
{{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0},
{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
}};
2009-07-23 20:19:23 +03:00
struct pe_header pe_header = pe_template;
2005-04-11 00:46:58 +03:00
int i;
2020-01-17 23:58:39 +02:00
struct pe_file pf = {0};
DWORD file_offset;
2009-07-23 20:19:23 +03:00
struct section_info *si;
IMAGE_SECTION_HEADER *psh;
TCCState *s1 = pe->s1;
int need_strtab = 0;
2005-04-11 00:46:58 +03:00
2020-01-17 23:58:39 +02:00
pf.op = fopen(pe->filename, "wb");
if (NULL == pf.op)
return tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
2005-04-11 00:46:58 +03:00
pe->sizeofheaders = pe_file_align(pe,
2009-07-18 23:07:42 +03:00
sizeof (struct pe_header)
+ pe->sec_count * sizeof (IMAGE_SECTION_HEADER)
);
2005-04-11 00:46:58 +03:00
file_offset = pe->sizeofheaders;
if (2 == pe->s1->verbose)
printf("-------------------------------"
"\n virt file size section" "\n");
2005-04-11 00:46:58 +03:00
for (i = 0; i < pe->sec_count; ++i) {
DWORD addr, size;
2009-07-23 20:19:23 +03:00
const char *sh_name;
2020-01-17 23:58:39 +02:00
si = pe->sec_info[i];
2009-07-23 20:19:23 +03:00
sh_name = si->name;
addr = si->sh_addr - pe->imagebase;
size = si->sh_size;
psh = &si->ish;
if (2 == pe->s1->verbose)
printf("%6x %6x %6x %s\n",
(unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name);
switch (si->cls) {
case sec_text:
if (!pe_header.opthdr.BaseOfCode)
pe_header.opthdr.BaseOfCode = addr;
break;
case sec_data:
2009-07-06 22:35:25 +03:00
#ifndef TCC_TARGET_X86_64
if (!pe_header.opthdr.BaseOfData)
pe_header.opthdr.BaseOfData = addr;
2009-07-06 22:35:25 +03:00
#endif
break;
case sec_bss:
break;
case sec_reloc:
2009-07-18 23:07:42 +03:00
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
break;
case sec_rsrc:
2009-07-18 23:07:42 +03:00
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
break;
case sec_pdata:
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size);
break;
}
2020-01-17 23:58:39 +02:00
if (pe->imp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs, pe->imp_size);
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs, pe->iat_size);
}
if (pe->exp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs, pe->exp_size);
}
2020-01-17 23:58:39 +02:00
memcpy(psh->Name, sh_name, umin(strlen(sh_name), sizeof psh->Name));
if (si->cls == sec_debug)
need_strtab += pe_put_long_secname((char*)psh->Name, sh_name);
psh->Characteristics = si->pe_flags;
psh->VirtualAddress = addr;
psh->Misc.VirtualSize = size;
pe_header.opthdr.SizeOfImage =
umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage);
if (si->data_size) {
2009-07-23 20:19:23 +03:00
psh->PointerToRawData = file_offset;
file_offset = pe_file_align(pe, file_offset + si->data_size);
2009-07-23 20:19:23 +03:00
psh->SizeOfRawData = file_offset - psh->PointerToRawData;
if (si->cls == sec_text)
pe_header.opthdr.SizeOfCode += psh->SizeOfRawData;
else
pe_header.opthdr.SizeOfInitializedData += psh->SizeOfRawData;
}
2005-04-11 00:46:58 +03:00
}
2009-07-23 20:19:23 +03:00
//pe_header.filehdr.TimeDateStamp = time(NULL);
pe_header.filehdr.NumberOfSections = pe->sec_count;
pe_header.opthdr.AddressOfEntryPoint = pe->start_addr;
pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
pe_header.opthdr.ImageBase = pe->imagebase;
pe_header.opthdr.Subsystem = pe->subsystem;
if (pe->s1->pe_stack_size)
pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size;
if (PE_DLL == pe->type)
2009-07-06 22:35:25 +03:00
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
pe_header.filehdr.Characteristics |= pe->s1->pe_characteristics;
if (need_strtab) {
pe_header.filehdr.PointerToSymbolTable = file_offset;
pe_header.filehdr.NumberOfSymbols = N_COFF_SYMS;
}
2020-01-17 23:58:39 +02:00
pe_fwrite(&pe_header, sizeof pe_header, &pf);
for (i = 0; i < pe->sec_count; ++i)
2020-01-17 23:58:39 +02:00
pe_fwrite(&pe->sec_info[i]->ish, sizeof(IMAGE_SECTION_HEADER), &pf);
file_offset = pe->sizeofheaders;
2009-07-23 20:19:23 +03:00
for (i = 0; i < pe->sec_count; ++i) {
2020-01-17 23:58:39 +02:00
Section *s;
si = pe->sec_info[i];
if (!si->data_size)
continue;
2020-01-17 23:58:39 +02:00
for (s = si->sec; s; s = s->prev) {
pe_fpad(&pf, file_offset);
pe_fwrite(s->data, s->data_offset, &pf);
if (s->prev)
file_offset += s->prev->sh_addr - s->sh_addr;
2009-07-23 20:19:23 +03:00
}
2020-01-17 23:58:39 +02:00
file_offset = si->ish.PointerToRawData + si->ish.SizeOfRawData;
pe_fpad(&pf, file_offset);
2009-07-23 20:19:23 +03:00
}
if (need_strtab) {
/* create a tiny COFF string table with the long section names */
pe_fwrite(&coff_strtab_size, sizeof coff_strtab_size, &pf);
pe_fwrite(dwarf_secs, sizeof dwarf_secs - 1, &pf);
file_offset = pf.pos;
}
2020-01-17 23:58:39 +02:00
pf.sum += file_offset;
fseek(pf.op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pf.sum, sizeof (DWORD), &pf);
fclose (pf.op);
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
#ifndef _WIN32
chmod(pe->filename, 0777);
#endif
2005-04-11 00:46:58 +03:00
if (2 == pe->s1->verbose)
printf("-------------------------------\n");
if (pe->s1->verbose)
printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset);
2005-04-11 00:46:58 +03:00
if (s1->do_debug & 16)
pe_create_pdb(s1, pe->filename);
2005-04-11 00:46:58 +03:00
return 0;
}
/*----------------------------------------------------------------------------*/
static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
2005-04-11 00:46:58 +03:00
{
int i;
int dll_index;
struct pe_import_info *p;
struct import_symbol *s;
ElfW(Sym) *isym;
2005-04-11 00:46:58 +03:00
isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
dll_index = isym->st_size;
i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index);
2005-04-11 00:46:58 +03:00
if (-1 != i) {
p = pe->imp_info[i];
goto found_dll;
2005-04-11 00:46:58 +03:00
}
p = tcc_mallocz(sizeof *p);
2005-04-11 00:46:58 +03:00
p->dll_index = dll_index;
dynarray_add(&pe->imp_info, &pe->imp_count, p);
2005-04-11 00:46:58 +03:00
found_dll:
i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index);
2005-04-11 00:46:58 +03:00
if (-1 != i)
return p->symbols[i];
s = tcc_mallocz(sizeof *s);
dynarray_add(&p->symbols, &p->sym_count, s);
2005-04-11 00:46:58 +03:00
s->sym_index = sym_index;
return s;
2005-04-11 00:46:58 +03:00
}
void pe_free_imports(struct pe_info *pe)
{
int i;
for (i = 0; i < pe->imp_count; ++i) {
struct pe_import_info *p = pe->imp_info[i];
dynarray_reset(&p->symbols, &p->sym_count);
}
dynarray_reset(&pe->imp_info, &pe->imp_count);
}
2005-04-11 00:46:58 +03:00
/*----------------------------------------------------------------------------*/
static void pe_build_imports(struct pe_info *pe)
2005-04-11 00:46:58 +03:00
{
int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
2005-04-11 00:46:58 +03:00
int ndlls = pe->imp_count;
TCCState *s1 = pe->s1;
2005-04-11 00:46:58 +03:00
for (sym_cnt = i = 0; i < ndlls; ++i)
sym_cnt += pe->imp_info[i]->sym_count;
2005-04-11 00:46:58 +03:00
if (0 == sym_cnt)
return;
2005-04-11 00:46:58 +03:00
pe_align_section(pe->thunk, 16);
2009-07-06 22:35:35 +03:00
pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
2009-07-06 22:35:25 +03:00
pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264);
2020-01-17 23:58:39 +02:00
dll_ptr = pe->thunk->data_offset;
thk_ptr = dll_ptr + pe->imp_size;
ent_ptr = thk_ptr + pe->iat_size;
pe->imp_offs = dll_ptr + rva_base;
pe->iat_offs = thk_ptr + rva_base;
section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
2005-04-11 00:46:58 +03:00
for (i = 0; i < pe->imp_count; ++i) {
2009-07-06 22:35:35 +03:00
IMAGE_IMPORT_DESCRIPTOR *hdr;
int k, n, dllindex;
2009-07-06 22:35:25 +03:00
ADDR3264 v;
struct pe_import_info *p = pe->imp_info[i];
const char *name;
DLLReference *dllref;
dllindex = p->dll_index;
if (dllindex)
name = tcc_basename((dllref = pe->s1->loaded_dlls[dllindex-1])->name);
else
name = "", dllref = NULL;
/* put the dll name into the import header */
v = put_elf_str(pe->thunk, name);
2009-07-06 22:35:35 +03:00
hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr);
hdr->FirstThunk = thk_ptr + rva_base;
hdr->OriginalFirstThunk = ent_ptr + rva_base;
hdr->Name = v + rva_base;
for (k = 0, n = p->sym_count; k <= n; ++k) {
if (k < n) {
int iat_index = p->symbols[k]->iat_index;
int sym_index = p->symbols[k]->sym_index;
ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index;
2009-07-06 22:34:49 +03:00
ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index;
const char *name = (char*)pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
int ordinal;
org_sym->st_value = thk_ptr;
org_sym->st_shndx = pe->thunk->sh_num;
if (dllref)
v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */
else
ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */
#ifdef TCC_IS_NATIVE
if (pe->type == PE_RUN) {
if (dllref) {
if ( !dllref->handle )
dllref->handle = LoadLibraryA(dllref->name);
2016-10-18 00:24:01 +03:00
v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(char*)0+ordinal:name);
}
if (!v)
tcc_error_noabort("could not resolve symbol '%s'", name);
} else
#endif
if (ordinal) {
v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1);
} else {
v = pe->thunk->data_offset + rva_base;
section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
put_elf_str(pe->thunk, name);
}
} else {
v = 0; /* last entry is zero */
}
2009-07-06 22:35:25 +03:00
*(ADDR3264*)(pe->thunk->data+thk_ptr) =
*(ADDR3264*)(pe->thunk->data+ent_ptr) = v;
2009-07-06 22:35:25 +03:00
thk_ptr += sizeof (ADDR3264);
ent_ptr += sizeof (ADDR3264);
}
2009-07-06 22:35:35 +03:00
dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR);
2005-04-11 00:46:58 +03:00
}
}
/* ------------------------------------------------------------- */
struct pe_sort_sym
{
int index;
const char *name;
};
static int sym_cmp(const void *va, const void *vb)
2005-04-17 16:15:54 +03:00
{
const char *ca = (*(struct pe_sort_sym**)va)->name;
const char *cb = (*(struct pe_sort_sym**)vb)->name;
2005-04-17 16:15:54 +03:00
return strcmp(ca, cb);
}
static void pe_build_exports(struct pe_info *pe)
2005-04-11 00:46:58 +03:00
{
2009-07-06 22:34:49 +03:00
ElfW(Sym) *sym;
int sym_index, sym_end;
2020-01-17 23:58:39 +02:00
DWORD rva_base, base_o, func_o, name_o, ord_o, str_o;
2009-07-06 22:35:35 +03:00
IMAGE_EXPORT_DIRECTORY *hdr;
int sym_count, ord;
struct pe_sort_sym **sorted, *p;
TCCState *s1 = pe->s1;
2005-04-17 16:15:54 +03:00
FILE *op;
char buf[260];
const char *dllname;
const char *name;
2005-04-11 00:46:58 +03:00
rva_base = pe->thunk->sh_addr - pe->imagebase;
sym_count = 0, sorted = NULL, op = NULL;
2009-07-06 22:34:49 +03:00
sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
2009-07-06 22:34:49 +03:00
sym = (ElfW(Sym)*)symtab_section->data + sym_index;
name = pe_export_name(pe->s1, sym);
if (sym->st_other & ST_PE_EXPORT) {
p = tcc_malloc(sizeof *p);
p->index = sym_index;
p->name = name;
dynarray_add(&sorted, &sym_count, p);
}
#if 0
if (sym->st_other & ST_PE_EXPORT)
printf("export: %s\n", name);
if (sym->st_other & ST_PE_STDCALL)
printf("stdcall: %s\n", name);
#endif
2005-04-17 16:15:54 +03:00
}
2005-04-11 00:46:58 +03:00
if (0 == sym_count)
return;
2005-04-11 00:46:58 +03:00
qsort (sorted, sym_count, sizeof *sorted, sym_cmp);
2005-04-11 00:46:58 +03:00
pe_align_section(pe->thunk, 16);
dllname = tcc_basename(pe->filename);
2005-04-11 00:46:58 +03:00
2020-01-17 23:58:39 +02:00
base_o = pe->thunk->data_offset;
func_o = base_o + sizeof(IMAGE_EXPORT_DIRECTORY);
name_o = func_o + sym_count * sizeof (DWORD);
ord_o = name_o + sym_count * sizeof (DWORD);
str_o = ord_o + sym_count * sizeof(WORD);
hdr = section_ptr_add(pe->thunk, str_o - base_o);
hdr->Characteristics = 0;
hdr->Base = 1;
hdr->NumberOfFunctions = sym_count;
hdr->NumberOfNames = sym_count;
hdr->AddressOfFunctions = func_o + rva_base;
hdr->AddressOfNames = name_o + rva_base;
hdr->AddressOfNameOrdinals = ord_o + rva_base;
hdr->Name = str_o + rva_base;
put_elf_str(pe->thunk, dllname);
#if 1
/* automatically write exports to <output-filename>.def */
pstrcpy(buf, sizeof buf, pe->filename);
strcpy(tcc_fileextension(buf), ".def");
op = fopen(buf, "wb");
if (NULL == op) {
tcc_error_noabort("could not create '%s': %s", buf, strerror(errno));
} else {
fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
if (pe->s1->verbose)
printf("<- %s (%d symbol%s)\n", buf, sym_count, &"s"[sym_count < 2]);
}
#endif
for (ord = 0; ord < sym_count; ++ord)
2005-04-17 16:15:54 +03:00
{
p = sorted[ord], sym_index = p->index, name = p->name;
/* insert actual address later in relocate_sections() */
put_elf_reloc(symtab_section, pe->thunk,
2009-07-06 22:34:49 +03:00
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);
if (op)
fprintf(op, "%s\n", name);
2005-04-11 00:46:58 +03:00
}
2020-01-17 23:58:39 +02:00
pe->exp_offs = base_o + rva_base;
pe->exp_size = pe->thunk->data_offset - base_o;
dynarray_reset(&sorted, &sym_count);
if (op)
fclose(op);
2005-04-11 00:46:58 +03:00
}
/* ------------------------------------------------------------- */
static void pe_build_reloc (struct pe_info *pe)
2005-04-11 00:46:58 +03:00
{
2020-01-17 23:58:39 +02:00
DWORD offset, block_ptr, sh_addr, addr;
2005-04-11 00:46:58 +03:00
int count, i;
2009-07-06 22:34:49 +03:00
ElfW_Rel *rel, *rel_end;
2005-04-11 00:46:58 +03:00
Section *s = NULL, *sr;
2020-01-17 23:58:39 +02:00
struct pe_reloc_header *hdr;
2020-01-17 23:58:39 +02:00
sh_addr = offset = block_ptr = count = i = 0;
2005-04-11 00:46:58 +03:00
rel = rel_end = NULL;
for(;;) {
if (rel < rel_end) {
2011-07-14 20:23:04 +03:00
int type = ELFW(R_TYPE)(rel->r_info);
2020-01-17 23:58:39 +02:00
addr = rel->r_offset + sh_addr;
++ rel;
2009-07-06 22:34:49 +03:00
if (type != REL_TYPE_DIRECT)
continue;
if (count == 0) { /* new block */
block_ptr = pe->reloc->data_offset;
section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header));
offset = addr & 0xFFFFFFFF<<12;
}
if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */
WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD));
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
*wp = addr | PE_IMAGE_REL<<12;
++count;
continue;
}
-- rel;
2020-01-17 23:58:39 +02:00
} else if (s) {
sr = s->reloc;
if (sr) {
2009-07-06 22:34:49 +03:00
rel = (ElfW_Rel *)sr->data;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
2020-01-17 23:58:39 +02:00
sh_addr = s->sh_addr;
}
2020-01-17 23:58:39 +02:00
s = s->prev;
continue;
2020-01-17 23:58:39 +02:00
} else if (i < pe->sec_count) {
s = pe->sec_info[i]->sec, ++i;
continue;
2020-01-17 23:58:39 +02:00
} else if (!count)
break;
2020-01-17 23:58:39 +02:00
/* fill the last block and ready for a new one */
if (count & 1) /* align for DWORDS */
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
2020-01-17 23:58:39 +02:00
hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
hdr -> offset = offset - pe->imagebase;
hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
count = 0;
2005-04-11 00:46:58 +03:00
}
}
/* ------------------------------------------------------------- */
static int pe_section_class(Section *s)
2005-04-11 00:46:58 +03:00
{
int type, flags;
const char *name;
type = s->sh_type;
flags = s->sh_flags;
name = s->name;
if (0 == memcmp(name, ".stab", 5) || 0 == memcmp(name, ".debug_", 7)) {
if (s->s1->do_debug)
return sec_debug;
} else if (flags & SHF_ALLOC) {
if (type == SHT_PROGBITS
|| type == SHT_INIT_ARRAY
|| type == SHT_FINI_ARRAY) {
if (flags & SHF_EXECINSTR)
return sec_text;
if (flags & SHF_WRITE)
return sec_data;
if (0 == strcmp(name, ".rsrc"))
return sec_rsrc;
if (0 == strcmp(name, ".iedat"))
return sec_idata;
if (0 == strcmp(name, ".pdata"))
return sec_pdata;
return sec_rdata;
} else if (type == SHT_NOBITS) {
return sec_bss;
}
return sec_other;
} else {
if (0 == strcmp(name, ".reloc"))
return sec_reloc;
}
return sec_last;
}
static int pe_assign_addresses (struct pe_info *pe)
{
int i, k, n, c, nbs;
ADDR3264 addr;
int *sec_order, *sec_cls;
struct section_info *si;
Section *s;
TCCState *s1 = pe->s1;
2016-10-18 00:24:01 +03:00
if (PE_DLL == pe->type)
pe->reloc = new_section(pe->s1, ".reloc", SHT_PROGBITS, 0);
//pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
nbs = s1->nb_sections;
sec_order = tcc_mallocz(2 * sizeof (int) * nbs);
sec_cls = sec_order + nbs;
for (i = 1; i < nbs; ++i) {
s = s1->sections[i];
k = pe_section_class(s);
for (n = i; n > 1 && k < (c = sec_cls[n - 1]); --n)
sec_cls[n] = c, sec_order[n] = sec_order[n - 1];
sec_cls[n] = k, sec_order[n] = i;
}
2020-01-17 23:58:39 +02:00
si = NULL;
2005-04-11 00:46:58 +03:00
addr = pe->imagebase + 1;
for (i = 1; (c = sec_cls[i]) < sec_last; ++i) {
s = s1->sections[sec_order[i]];
2020-01-17 23:58:39 +02:00
if (PE_MERGE_DATA && c == sec_bss)
2020-01-17 23:58:39 +02:00
c = sec_data;
if (si && c == si->cls && c != sec_debug) {
2020-01-17 23:58:39 +02:00
/* merge with previous section */
s->sh_addr = addr = ((addr - 1) | (16 - 1)) + 1;
} else {
si = NULL;
s->sh_addr = addr = pe_virtual_align(pe, addr);
}
if (NULL == pe->thunk
&& c == (data_section == rodata_section ? sec_data : sec_rdata))
2020-01-17 23:58:39 +02:00
pe->thunk = s;
if (s == pe->thunk) {
pe_build_imports(pe);
pe_build_exports(pe);
}
if (s == pe->reloc)
pe_build_reloc (pe);
if (0 == s->data_offset)
2012-12-22 19:06:17 +02:00
continue;
2020-01-17 23:58:39 +02:00
if (si)
goto add_section;
si = tcc_mallocz(sizeof *si);
dynarray_add(&pe->sec_info, &pe->sec_count, si);
2020-01-17 23:58:39 +02:00
strcpy(si->name, s->name);
si->cls = c;
2020-01-17 23:58:39 +02:00
si->sh_addr = addr;
si->pe_flags = IMAGE_SCN_MEM_READ;
if (s->sh_flags & SHF_EXECINSTR)
si->pe_flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE;
else if (s->sh_type == SHT_NOBITS)
si->pe_flags |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
else
si->pe_flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
if (s->sh_flags & SHF_WRITE)
si->pe_flags |= IMAGE_SCN_MEM_WRITE;
2020-01-17 23:58:39 +02:00
if (0 == (s->sh_flags & SHF_ALLOC))
si->pe_flags |= IMAGE_SCN_MEM_DISCARDABLE;
2020-01-17 23:58:39 +02:00
add_section:
addr += s->data_offset;
si->sh_size = addr - si->sh_addr;
if (s->sh_type != SHT_NOBITS) {
Section **ps = &si->sec;
while (*ps)
ps = &(*ps)->prev;
*ps = s, s->prev = NULL;
si->data_size = si->sh_size;
}
2020-01-17 23:58:39 +02:00
//printf("%08x %05x %08x %s\n", si->sh_addr, si->sh_size, si->pe_flags, s->name);
2005-04-11 00:46:58 +03:00
}
#if 0
for (i = 1; i < nbs; ++i) {
Section *s = s1->sections[sec_order[i]];
int type = s->sh_type;
int flags = s->sh_flags;
printf("section %-16s %-10s %p %04x %s,%s,%s\n",
s->name,
type == SHT_PROGBITS ? "progbits" :
type == SHT_INIT_ARRAY ? "initarr" :
type == SHT_FINI_ARRAY ? "finiarr" :
type == SHT_NOBITS ? "nobits" :
type == SHT_SYMTAB ? "symtab" :
type == SHT_STRTAB ? "strtab" :
2009-07-06 22:34:49 +03:00
type == SHT_RELX ? "rel" : "???",
s->sh_addr,
(unsigned)s->data_offset,
flags & SHF_ALLOC ? "alloc" : "",
flags & SHF_WRITE ? "write" : "",
flags & SHF_EXECINSTR ? "exec" : ""
);
fflush(stdout);
}
s1->verbose = 2;
#endif
tcc_free(sec_order);
2005-04-11 00:46:58 +03:00
return 0;
}
/*----------------------------------------------------------------------------*/
static int pe_isafunc(TCCState *s1, int sym_index)
{
Section *sr = text_section->reloc;
ElfW_Rel *rel, *rel_end;
ElfW(Addr)info = ELFW(R_INFO)(sym_index, R_XXX_FUNCCALL);
#ifdef R_XXX_FUNCCALL2
ElfW(Addr)info2 = ELFW(R_INFO)(sym_index, R_XXX_FUNCCALL2);
#endif
if (!sr)
return 0;
rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
if (rel->r_info == info)
return 1;
#ifdef R_XXX_FUNCCALL2
if (rel->r_info == info2)
return 1;
#endif
}
return 0;
}
2005-04-11 00:46:58 +03:00
/*----------------------------------------------------------------------------*/
static int pe_check_symbols(struct pe_info *pe)
2005-04-11 00:46:58 +03:00
{
2009-07-06 22:34:49 +03:00
ElfW(Sym) *sym;
int sym_index, sym_end;
2005-04-11 00:46:58 +03:00
int ret = 0;
TCCState *s1 = pe->s1;
2005-04-11 00:46:58 +03:00
pe_align_section(text_section, 8);
2009-07-06 22:34:49 +03:00
sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
for (sym_index = 1; sym_index < sym_end; ++sym_index) {
2009-07-06 22:34:49 +03:00
sym = (ElfW(Sym) *)symtab_section->data + sym_index;
if (sym->st_shndx == SHN_UNDEF) {
const char *name = (char*)symtab_section->link->data + sym->st_name;
2011-07-14 20:23:04 +03:00
unsigned type = ELFW(ST_TYPE)(sym->st_info);
int imp_sym = pe_find_import(pe->s1, sym);
struct import_symbol *is;
if (imp_sym <= 0)
goto not_found;
if (type == STT_NOTYPE) {
/* symbols from assembler have no type, find out which */
if (pe_isafunc(s1, sym_index))
type = STT_FUNC;
else
type = STT_OBJECT;
}
is = pe_add_import(pe, imp_sym);
if (type == STT_FUNC) {
unsigned offset = is->thk_offset;
if (offset) {
/* got aliased symbol, like stricmp and _stricmp */
} else {
char buffer[100];
unsigned char *p;
/* add a helper symbol, will be patched later in
pe_build_imports */
sprintf(buffer, "IAT.%s", name);
is->iat_index = put_elf_sym(
symtab_section, 0, sizeof(DWORD),
ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT),
0, SHN_UNDEF, buffer);
offset = text_section->data_offset;
is->thk_offset = offset;
/* add the 'jmp IAT[x]' instruction */
2010-04-19 15:50:22 +03:00
#ifdef TCC_TARGET_ARM
p = section_ptr_add(text_section, 8+4); // room for code and address
write32le(p + 0, 0xE59FC000); // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx
write32le(p + 4, 0xE59CF000); // arm code ldr pc, [ip]
2010-04-19 15:50:22 +03:00
put_elf_reloc(symtab_section, text_section,
offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position
#else
p = section_ptr_add(text_section, 8);
write16le(p, 0x25FF);
#ifdef TCC_TARGET_X86_64
write32le(p + 2, (DWORD)-4);
#endif
put_elf_reloc(symtab_section, text_section,
2009-07-06 22:34:49 +03:00
offset + 2, R_XXX_THUNKFIX, is->iat_index);
2010-04-19 15:50:22 +03:00
#endif
}
/* tcc_realloc might have altered sym's address */
2009-07-06 22:34:49 +03:00
sym = (ElfW(Sym) *)symtab_section->data + sym_index;
/* patch the original symbol */
sym->st_value = offset;
sym->st_shndx = text_section->sh_num;
sym->st_other &= ~ST_PE_EXPORT; /* do not export */
continue;
}
if (type == STT_OBJECT) { /* data, ptr to that should be */
if (0 == is->iat_index) {
/* original symbol will be patched later in pe_build_imports */
is->iat_index = sym_index;
continue;
}
}
not_found:
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
/* STB_WEAK undefined symbols are accepted */
continue;
ret = tcc_error_noabort("undefined symbol '%s'%s", name,
imp_sym < 0 ? ", missing __declspec(dllimport)?":"");
} else if (pe->s1->rdynamic
2011-07-14 20:23:04 +03:00
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
/* if -rdynamic option, then export all non local symbols */
sym->st_other |= ST_PE_EXPORT;
}
2005-04-11 00:46:58 +03:00
}
return ret;
}
/*----------------------------------------------------------------------------*/
#if PE_PRINT_SECTIONS
static void pe_print_section(FILE * f, Section * s)
{
2017-05-08 07:38:09 +03:00
/* just if you're curious */
2005-04-11 00:46:58 +03:00
BYTE *p, *e, b;
int i, n, l, m;
p = s->data;
e = s->data + s->data_offset;
l = e - p;
fprintf(f, "section \"%s\"", s->name);
if (s->link)
fprintf(f, "\nlink \"%s\"", s->link->name);
2005-04-11 00:46:58 +03:00
if (s->reloc)
fprintf(f, "\nreloc \"%s\"", s->reloc->name);
2009-07-06 22:34:49 +03:00
fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr);
fprintf(f, "\ncontents %08X", (unsigned)l);
2005-04-11 00:46:58 +03:00
fprintf(f, "\n\n");
if (s->sh_type == SHT_NOBITS)
return;
2005-04-11 00:46:58 +03:00
if (0 == l)
return;
2005-04-11 00:46:58 +03:00
if (s->sh_type == SHT_SYMTAB)
2009-07-06 22:34:49 +03:00
m = sizeof(ElfW(Sym));
else if (s->sh_type == SHT_RELX)
m = sizeof(ElfW_Rel);
2005-04-11 00:46:58 +03:00
else
m = 16;
2005-04-11 00:46:58 +03:00
fprintf(f, "%-8s", "offset");
for (i = 0; i < m; ++i)
fprintf(f, " %02x", i);
n = 56;
2009-07-06 22:34:49 +03:00
if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) {
const char *fields1[] = {
"name",
"value",
"size",
"bind",
"type",
"other",
"shndx",
NULL
};
const char *fields2[] = {
"offs",
"type",
"symb",
NULL
};
const char **p;
if (s->sh_type == SHT_SYMTAB)
p = fields1, n = 106;
else
p = fields2, n = 58;
for (i = 0; p[i]; ++i)
fprintf(f, "%6s", p[i]);
fprintf(f, " symbol");
}
fprintf(f, "\n");
for (i = 0; i < n; ++i)
fprintf(f, "-");
fprintf(f, "\n");
for (i = 0; i < l;)
{
fprintf(f, "%08X", i);
for (n = 0; n < m; ++n) {
if (n + i < l)
fprintf(f, " %02X", p[i + n]);
else
fprintf(f, " ");
}
if (s->sh_type == SHT_SYMTAB) {
2009-07-06 22:34:49 +03:00
ElfW(Sym) *sym = (ElfW(Sym) *) (p + i);
const char *name = s->link->data + sym->st_name;
fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"",
2009-07-06 22:34:49 +03:00
(unsigned)sym->st_name,
(unsigned)sym->st_value,
(unsigned)sym->st_size,
2011-07-14 20:23:04 +03:00
(unsigned)ELFW(ST_BIND)(sym->st_info),
(unsigned)ELFW(ST_TYPE)(sym->st_info),
2009-07-06 22:34:49 +03:00
(unsigned)sym->st_other,
(unsigned)sym->st_shndx,
name);
} else if (s->sh_type == SHT_RELX) {
ElfW_Rel *rel = (ElfW_Rel *) (p + i);
ElfW(Sym) *sym =
2011-07-14 20:23:04 +03:00
(ElfW(Sym) *) s->link->data + ELFW(R_SYM)(rel->r_info);
const char *name = s->link->link->data + sym->st_name;
fprintf(f, " %04X %02X %04X \"%s\"",
2009-07-06 22:34:49 +03:00
(unsigned)rel->r_offset,
2011-07-14 20:23:04 +03:00
(unsigned)ELFW(R_TYPE)(rel->r_info),
(unsigned)ELFW(R_SYM)(rel->r_info),
2009-07-06 22:34:49 +03:00
name);
} else {
fprintf(f, " ");
for (n = 0; n < m; ++n) {
if (n + i < l) {
b = p[i + n];
if (b < 32 || b >= 127)
b = '.';
fprintf(f, "%c", b);
}
}
}
i += m;
fprintf(f, "\n");
2005-04-11 00:46:58 +03:00
}
fprintf(f, "\n\n");
}
static void pe_print_sections(TCCState *s1, const char *fname)
{
Section *s;
FILE *f;
int i;
2009-07-06 22:35:25 +03:00
f = fopen(fname, "w");
for (i = 1; i < s1->nb_sections; ++i) {
s = s1->sections[i];
pe_print_section(f, s);
}
pe_print_section(f, s1->dynsymtab_section);
fclose(f);
}
2005-04-11 00:46:58 +03:00
#endif
/* ------------------------------------------------------------- */
/* helper function for load/store to insert one more indirection */
various stuff win32/Makefile ("for cygwin") removed - On cygwin, the normal ./configure && make can be used with either cygwin's "GCC for Win32 Toolchain" ./configure --cross-prefix=i686-w64-mingw32- or with an existing tcc: ./configure --cc=<old-tccdir>/tcc.exe tcctest.c: - exclude test_high_clobbers() on _WIN64 (does not work) tests2/95_bitfield.c: - use 'signed char' for ARM (where default 'char' is unsigned) tests: - remove -I "expr" diff option to allow tests with busybox-diff. libtcc.c, tcc.c: - removed -iwithprefix option. It is supposed to be combined with -iprefix which we don't have either. tccgen.c: - fix assignments and return of 'void', as in void f() { void *p, *q; *p = *q: return *p; } This appears to be allowed but should do nothing. tcc.h, libtcc.c, tccpp.c: - Revert "Introduce VIP sysinclude paths which are always searched first" This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1. The patch was giving tcc's system includes priority over -I which is not how it should be. tccelf.c: - add DT_TEXTREL tag only if text relocations are actually used (which is likely not the case on x86_64) - prepare_dynamic_rel(): avoid relocation of unresolved (weak) symbols tccrun.c: - for HAVE_SELINUX, use two mappings to the same (real) file. (it was so once except the RX mapping wasn't used at all). tccpe.c: - fix relocation constant used for x86_64 (by Andrei E. Warentin) - #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin. tccasm.c: - keep forward asm labels static, otherwise they will endup in dynsym eventually. configure, Makefile: - mingw32: respect ./configure options --bindir --docdir --libdir - allow overriding tcc when building libtcc1.a and libtcc.def with make XTCC=<tcc program to use> - use $(wildcard ...) for install to allow installing just a cross compiler for example make cross-arm make install - use name <target>-libtcc1.a build-tcc.bat: - add options: -clean, -b bindir
2017-10-11 19:13:43 +03:00
#if defined TCC_TARGET_I386 || defined TCC_TARGET_X86_64
ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2)
{
int r2;
if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST))
return sv;
if (!sv->sym->a.dllimport)
return sv;
// printf("import %04x %04x %04x %s\n", sv->type.t, sv->sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL));
memset(v2, 0, sizeof *v2);
v2->type.t = VT_PTR;
v2->r = VT_CONST | VT_SYM | VT_LVAL;
v2->sym = sv->sym;
r2 = get_reg(RC_INT);
load(r2, v2);
v2->r = r2;
if ((uint32_t)sv->c.i) {
vpushv(v2);
vpushi(sv->c.i);
gen_opi('+');
*v2 = *vtop--;
}
v2->type.t = sv->type.t;
v2->r |= sv->r & VT_LVAL;
return v2;
}
#endif
ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value)
{
return set_elf_sym(
s1->dynsymtab_section,
value,
dllindex, /* st_size */
2011-07-14 20:23:04 +03:00
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
0,
value ? SHN_ABS : SHN_UNDEF,
name
);
}
static int read_mem(int fd, unsigned offset, void *buffer, unsigned len)
2005-04-11 00:46:58 +03:00
{
lseek(fd, offset, SEEK_SET);
return len == read(fd, buffer, len);
}
2005-04-11 00:46:58 +03:00
/* ------------------------------------------------------------- */
static int get_dllexports(int fd, char **pp)
{
int i, k, l, n, n0, ret;
char *p;
IMAGE_SECTION_HEADER ish;
IMAGE_EXPORT_DIRECTORY ied;
IMAGE_DOS_HEADER dh;
IMAGE_FILE_HEADER ih;
DWORD sig, ref, addr;
DWORD *namep = NULL, p0 = 0, p1;
int pef_hdroffset, opt_hdroffset, sec_hdroffset;
n = n0 = 0;
p = NULL;
ret = 1;
if (!read_mem(fd, 0, &dh, sizeof dh))
goto the_end;
if (!read_mem(fd, dh.e_lfanew, &sig, sizeof sig))
goto the_end;
if (sig != 0x00004550)
goto the_end;
pef_hdroffset = dh.e_lfanew + sizeof sig;
if (!read_mem(fd, pef_hdroffset, &ih, sizeof ih))
goto the_end;
opt_hdroffset = pef_hdroffset + sizeof ih;
if (ih.Machine == 0x014C) {
IMAGE_OPTIONAL_HEADER32 oh;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
} else if (ih.Machine == 0x8664) {
IMAGE_OPTIONAL_HEADER64 oh;
sec_hdroffset = opt_hdroffset + sizeof oh;
if (!read_mem(fd, opt_hdroffset, &oh, sizeof oh))
goto the_end;
if (IMAGE_DIRECTORY_ENTRY_EXPORT >= oh.NumberOfRvaAndSizes)
goto the_end_0;
addr = oh.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
} else
goto the_end;
//printf("addr: %08x\n", addr);
for (i = 0; i < ih.NumberOfSections; ++i) {
if (!read_mem(fd, sec_hdroffset + i * sizeof ish, &ish, sizeof ish))
goto the_end;
//printf("vaddr: %08x\n", ish.VirtualAddress);
if (addr >= ish.VirtualAddress && addr < ish.VirtualAddress + ish.SizeOfRawData)
goto found;
}
goto the_end_0;
found:
ref = ish.VirtualAddress - ish.PointerToRawData;
if (!read_mem(fd, addr - ref, &ied, sizeof ied))
goto the_end;
k = ied.NumberOfNames;
if (k) {
namep = tcc_malloc(l = k * sizeof *namep);
if (!read_mem(fd, ied.AddressOfNames - ref, namep, l))
goto the_end;
for (i = l = 0; i < k; ++i) {
p1 = namep[i] - ref;
if (p1 != p0)
lseek(fd, p0 = p1, SEEK_SET), l = 0;
do {
if (0 == l) {
if (n + 1000 >= n0)
p = tcc_realloc(p, n0 += 1000);
if ((l = read(fd, p + n, 1000 - 1)) <= 0)
goto the_end;
}
--l, ++p0;
} while (p[n++]);
}
p[n] = 0;
}
the_end_0:
ret = 0;
the_end:
tcc_free(namep);
if (ret && p)
tcc_free(p), p = NULL;
*pp = p;
return ret;
}
2009-07-18 23:07:25 +03:00
/* -------------------------------------------------------------
* This is for compiled windows resources in 'coff' format
* as generated by 'windres.exe -O coff ...'.
*/
static int pe_load_res(TCCState *s1, int fd)
{
struct pe_rsrc_header hdr;
Section *rsrc_section;
int i, ret = -1, sym_index;
BYTE *ptr;
2009-07-18 23:07:25 +03:00
unsigned offs;
if (!read_mem(fd, 0, &hdr, sizeof hdr))
goto quit;
2009-07-18 23:07:25 +03:00
2014-08-01 11:51:28 +03:00
if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE
2009-07-18 23:07:25 +03:00
|| hdr.filehdr.NumberOfSections != 1
|| strcmp((char*)hdr.sectionhdr.Name, ".rsrc") != 0)
goto quit;
rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
2009-07-18 23:07:25 +03:00
offs = hdr.sectionhdr.PointerToRawData;
if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData))
goto quit;
2009-07-18 23:07:25 +03:00
offs = hdr.sectionhdr.PointerToRelocations;
sym_index = put_elf_sym(symtab_section, 0, 0, 0, 0, rsrc_section->sh_num, ".rsrc");
for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) {
struct pe_rsrc_reloc rel;
if (!read_mem(fd, offs, &rel, sizeof rel))
goto quit;
// printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
2014-08-01 11:51:28 +03:00
if (rel.type != RSRC_RELTYPE)
goto quit;
put_elf_reloc(symtab_section, rsrc_section,
rel.offset, R_XXX_RELATIVE, sym_index);
2009-07-18 23:07:25 +03:00
offs += sizeof rel;
2005-04-11 00:46:58 +03:00
}
ret = 0;
quit:
2005-04-11 00:46:58 +03:00
return ret;
}
/* ------------------------------------------------------------- */
static char *trimfront(char *p)
{
while ((unsigned char)*p <= ' ' && *p && *p != '\n')
++p;
return p;
}
/*
static char *trimback(char *a, char *e)
{
while (e > a && (unsigned char)e[-1] <= ' ')
--e;
*e = 0;;
return a;
}*/
static char *get_token(char **s, char *f)
{
char *p = *s, *e;
p = e = trimfront(p);
while ((unsigned char)*e > ' ')
++e;
*s = trimfront(e);
*f = **s; *e = 0;
return p;
}
static int pe_load_def(TCCState *s1, int fd)
2005-04-17 16:15:54 +03:00
{
int state = 0, ret = -1, dllindex = 0, ord;
char dllname[80], *buf, *line, *p, *x, next;
buf = tcc_load_text(fd);
for (line = buf;; ++line) {
p = get_token(&line, &next);
if (!(*p && *p != ';'))
goto skip;
switch (state) {
case 0:
if (0 != stricmp(p, "LIBRARY") || next == '\n')
goto quit;
pstrcpy(dllname, sizeof dllname, get_token(&line, &next));
++state;
break;
case 1:
if (0 != stricmp(p, "EXPORTS"))
goto quit;
++state;
break;
case 2:
dllindex = tcc_add_dllref(s1, dllname, 0)->index;
++state;
/* fall through */
default:
/* get ordinal and will store in sym->st_value */
ord = 0;
if (next == '@') {
x = get_token(&line, &next);
ord = (int)strtol(x + 1, &x, 10);
}
//printf("token %s ; %s : %d\n", dllname, p, ord);
pe_putimport(s1, dllindex, p, ord);
break;
}
skip:
while ((unsigned char)next > ' ')
get_token(&line, &next);
if (next != '\n')
break;
}
ret = 0;
quit:
tcc_free(buf);
2009-07-18 23:07:25 +03:00
return ret;
}
/* ------------------------------------------------------------- */
static int pe_load_dll(TCCState *s1, int fd, const char *filename)
2009-07-18 23:07:25 +03:00
{
char *p, *q;
DLLReference *ref = tcc_add_dllref(s1, filename, 0);
if (ref->found)
return 0;
if (get_dllexports(fd, &p))
return -1;
if (p) {
for (q = p; *q; q += 1 + strlen(q))
pe_putimport(s1, ref->index, q, 0);
tcc_free(p);
}
return 0;
2009-07-18 23:07:25 +03:00
}
ST_FUNC int pe_load_file(struct TCCState *s1, int fd, const char *filename)
2009-07-18 23:07:25 +03:00
{
int ret = -1;
char buf[10];
if (0 == strcmp(tcc_fileextension(filename), ".def"))
ret = pe_load_def(s1, fd);
else if (pe_load_res(s1, fd) == 0)
ret = 0;
else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2))
ret = pe_load_dll(s1, fd, filename);
return ret;
}
PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp)
{
int ret, fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
ret = get_dllexports(fd, pp);
close(fd);
return ret;
2005-04-17 16:15:54 +03:00
}
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
static unsigned pe_add_uwwind_info(TCCState *s1)
{
if (NULL == s1->uw_pdata) {
s1->uw_pdata = find_section(s1, ".pdata");
s1->uw_pdata->sh_addralign = 4;
}
if (0 == s1->uw_sym)
s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, ".uw_base");
if (0 == s1->uw_offs) {
/* As our functions all have the same stackframe, we use one entry for all */
static const unsigned char uw_info[] = {
0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
0x04, // UBYTE Size of prolog
0x02, // UBYTE Count of unwind codes
0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled)
// USHORT * n Unwind codes array
// 0x0b, 0x01, 0xff, 0xff, // stack size
0x04, 0x03, // set frame ptr (mov rsp -> rbp)
0x01, 0x50 // push reg (rbp)
};
Section *s = text_section;
unsigned char *p;
section_ptr_add(s, -s->data_offset & 3); /* align */
s1->uw_offs = s->data_offset;
p = section_ptr_add(s, sizeof uw_info);
memcpy(p, uw_info, sizeof uw_info);
}
return s1->uw_offs;
}
ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
{
TCCState *s1 = tcc_state;
Section *pd;
unsigned o, n, d;
struct /* _RUNTIME_FUNCTION */ {
DWORD BeginAddress;
DWORD EndAddress;
DWORD UnwindData;
} *p;
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_XXX_RELATIVE, s1->uw_sym);
}
#endif
2005-04-11 00:46:58 +03:00
/* ------------------------------------------------------------- */
2009-07-06 22:35:25 +03:00
#ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n
#else
#define PE_STDSYM(n,s) "_" n s
#endif
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
2005-04-11 00:46:58 +03:00
{
const char *start_symbol;
int pe_type;
2005-04-11 00:46:58 +03:00
if (TCC_OUTPUT_DLL == s1->output_type) {
2005-04-17 16:15:54 +03:00
pe_type = PE_DLL;
start_symbol = PE_STDSYM("__dllstart","@12");
} else {
const char *run_symbol;
if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16"))) {
start_symbol = "__winstart";
run_symbol = "__runwinmain";
pe_type = PE_GUI;
} else if (find_elf_sym(symtab_section, PE_STDSYM("wWinMain","@16"))) {
start_symbol = "__wwinstart";
run_symbol = "__runwwinmain";
pe_type = PE_GUI;
} else if (find_elf_sym(symtab_section, "wmain")) {
start_symbol = "__wstart";
run_symbol = "__runwmain";
pe_type = PE_EXE;
} else {
start_symbol = "__start";
run_symbol = "__runmain";
pe_type = PE_EXE;
if (s1->pe_subsystem == 2)
pe_type = PE_GUI;
}
if (TCC_OUTPUT_MEMORY == s1->output_type && !s1->nostdlib)
start_symbol = run_symbol;
}
if (s1->elf_entryname) {
pe->start_symbol = start_symbol = s1->elf_entryname;
} else {
pe->start_symbol = start_symbol + 1;
if (!s1->leading_underscore || strchr(start_symbol, '@'))
++start_symbol;
}
2020-01-17 23:58:39 +02:00
#ifdef CONFIG_TCC_BACKTRACE
if (s1->do_backtrace) {
2020-01-17 23:58:39 +02:00
#ifdef CONFIG_TCC_BCHECK
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bcheck.o");
2020-01-17 23:58:39 +02:00
#endif
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-dll.o");
if (s1->output_type != TCC_OUTPUT_DLL)
tcc_add_support(s1, "bt-log.o");
tcc_add_btstub(s1);
2020-01-17 23:58:39 +02:00
}
#endif
/* grab the startup code from libtcc1.a */
#ifdef TCC_IS_NATIVE
if (TCC_OUTPUT_MEMORY != s1->output_type || s1->run_main)
#endif
set_global_sym(s1, start_symbol, NULL, 0);
2005-04-11 00:46:58 +03:00
if (0 == s1->nostdlib) {
static const char * const libs[] = {
2019-12-10 09:07:25 +02:00
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
2009-07-06 22:35:25 +03:00
};
const char * const *pp, *p;
if (TCC_LIBTCC1[0])
tcc_add_support(s1, TCC_LIBTCC1);
bcheck cleanup - revert Makefiles to state before last bcheck additions Instead, just load bcheck.o explicitly if that is what is wanted. - move tcc_add_bcheck() to the <target>-link.c files and remove revently added arguments. This function is to support tccelf.c with linking, not for tccgen.c to support compilation. - remove -ba option: It said: "-ba Enable better address checking with bounds checker" Okay, if it is better then to have it is not an option. - remove va_copy. It is C99 and we try to stay C89 in tinycc when possible. For example, MS compilers do not have va_copy. - win64: revert any 'fixes' to alloca It was correct as it was before, except for bound_checking where it was not implemented. This should now work too. - remove parasitic filename:linenum features Such feature is already present with rt_printline in tccrun.c. If it doesn't work it can be fixed. - revert changes to gen_bounded_ptr_add() gen_bounded_ptr_add() was working as it should before (mostly). For the sake of simplicity I switched it to CDECL. Anyway, FASTCALL means SLOWCALL with tinycc. In exchange you get one addition which is required for bounds_cnecking function arguments. The important thing is to check them *BEFORE* they are loaded into registers. New function gbound_args() does that. In any case, code instrumentation with the bounds-check functions as such now seems to work flawlessly again, which means when they are inserted as NOPs, any code that tcc can compile, seems to behave just the same as without them. What these functions then do when fully enabled, is a differnt story. I did not touch this.
2019-12-12 16:45:45 +02:00
for (pp = libs; 0 != (p = *pp); ++pp) {
if (*p)
tcc_add_library_err(s1, p);
bcheck cleanup - revert Makefiles to state before last bcheck additions Instead, just load bcheck.o explicitly if that is what is wanted. - move tcc_add_bcheck() to the <target>-link.c files and remove revently added arguments. This function is to support tccelf.c with linking, not for tccgen.c to support compilation. - remove -ba option: It said: "-ba Enable better address checking with bounds checker" Okay, if it is better then to have it is not an option. - remove va_copy. It is C99 and we try to stay C89 in tinycc when possible. For example, MS compilers do not have va_copy. - win64: revert any 'fixes' to alloca It was correct as it was before, except for bound_checking where it was not implemented. This should now work too. - remove parasitic filename:linenum features Such feature is already present with rt_printline in tccrun.c. If it doesn't work it can be fixed. - revert changes to gen_bounded_ptr_add() gen_bounded_ptr_add() was working as it should before (mostly). For the sake of simplicity I switched it to CDECL. Anyway, FASTCALL means SLOWCALL with tinycc. In exchange you get one addition which is required for bounds_cnecking function arguments. The important thing is to check them *BEFORE* they are loaded into registers. New function gbound_args() does that. In any case, code instrumentation with the bounds-check functions as such now seems to work flawlessly again, which means when they are inserted as NOPs, any code that tcc can compile, seems to behave just the same as without them. What these functions then do when fully enabled, is a differnt story. I did not touch this.
2019-12-12 16:45:45 +02:00
else if (PE_DLL != pe_type && PE_GUI != pe_type)
break;
}
2005-04-11 00:46:58 +03:00
}
2020-01-17 23:58:39 +02:00
/* need this for 'tccelf.c:relocate_sections()' */
if (TCC_OUTPUT_DLL == s1->output_type)
s1->output_type = TCC_OUTPUT_EXE;
if (TCC_OUTPUT_MEMORY == s1->output_type)
pe_type = PE_RUN;
2009-07-06 22:35:25 +03:00
pe->type = pe_type;
}
static void pe_set_options(TCCState * s1, struct pe_info *pe)
2016-10-18 00:24:01 +03:00
{
if (PE_DLL == pe->type) {
/* XXX: check if is correct for arm-pe target */
pe->imagebase = 0x10000000;
} else {
#if defined(TCC_TARGET_ARM)
pe->imagebase = 0x00010000;
#else
pe->imagebase = 0x00400000;
#endif
}
#if defined(TCC_TARGET_ARM)
/* we use "console" subsystem by default */
pe->subsystem = 9;
#else
if (PE_DLL == pe->type || PE_GUI == pe->type)
pe->subsystem = 2;
else
pe->subsystem = 3;
#endif
/* Allow override via -Wl,-subsystem=... option */
if (s1->pe_subsystem != 0)
pe->subsystem = s1->pe_subsystem;
2016-10-18 00:24:01 +03:00
/* set default file/section alignment */
if (pe->subsystem == 1) {
pe->section_align = 0x20;
pe->file_align = 0x20;
} else {
pe->section_align = 0x1000;
pe->file_align = 0x200;
}
if (s1->section_align != 0)
pe->section_align = s1->section_align;
if (s1->pe_file_align != 0)
pe->file_align = s1->pe_file_align;
2016-10-18 00:24:01 +03:00
if ((pe->subsystem >= 10) && (pe->subsystem <= 12))
pe->imagebase = 0;
if (s1->has_text_addr)
pe->imagebase = s1->text_addr;
2016-10-18 00:24:01 +03:00
}
ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
2005-04-11 00:46:58 +03:00
{
struct pe_info pe;
2005-04-11 00:46:58 +03:00
memset(&pe, 0, sizeof pe);
pe.filename = filename;
pe.s1 = s1;
s1->filetype = 0;
2005-04-11 00:46:58 +03:00
2020-01-17 23:58:39 +02:00
#ifdef CONFIG_TCC_BCHECK
tcc_add_bcheck(s1);
2020-01-17 23:58:39 +02:00
#endif
pe_add_runtime(s1, &pe);
tcc_add_pragma_libs(s1);
resolve_common_syms(s1);
pe_set_options(s1, &pe);
pe_check_symbols(&pe);
if (s1->nb_errors)
;
else if (filename) {
pe_assign_addresses(&pe);
relocate_syms(s1, s1->symtab, 0);
s1->pe_imagebase = pe.imagebase;
relocate_sections(s1);
pe.start_addr = (DWORD)
(get_sym_addr(s1, pe.start_symbol, 1, 1) - pe.imagebase);
if (0 == s1->nb_errors)
pe_write(&pe);
dynarray_reset(&pe.sec_info, &pe.sec_count);
} else {
#ifdef TCC_IS_NATIVE
pe.thunk = data_section;
pe_build_imports(&pe);
s1->run_main = pe.start_symbol;
#ifdef TCC_TARGET_X86_64
s1->uw_pdata = find_section(s1, ".pdata");
#endif
#endif
2005-04-11 00:46:58 +03:00
}
pe_free_imports(&pe);
#if PE_PRINT_SECTIONS
if (s1->g_debug & 8)
pe_print_sections(s1, "tcc.log");
2005-04-11 00:46:58 +03:00
#endif
return s1->nb_errors ? -1 : 0;
2005-04-11 00:46:58 +03:00
}
/* ------------------------------------------------------------- */