2048 lines · 61.4 KB · C
RawDownload
/* *  TCCPE.C - PE file output for the Tiny C Compiler * *  Copyright (c) 2005-2007 grischka * * 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" #define PE_MERGE_DATA/* #define PE_PRINT_SECTIONS */ #ifndef _WIN32#define stricmp strcasecmp#define strnicmp strncasecmp#include <sys/stat.h> /* chmod() */#endif #ifdef TCC_TARGET_X86_64# define ADDR3264 ULONGLONG# define PE_IMAGE_REL IMAGE_REL_BASED_DIR64# 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 IMAGE_FILE_MACHINE 0x8664# define RSRC_RELTYPE 3 #elif defined TCC_TARGET_ARM# define ADDR3264 DWORD# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW# define REL_TYPE_DIRECT R_ARM_ABS32# define R_XXX_THUNKFIX R_ARM_ABS32# define R_XXX_RELATIVE R_ARM_RELATIVE# define IMAGE_FILE_MACHINE 0x01C0# define RSRC_RELTYPE 7 /* ??? (not tested) */ #elif defined TCC_TARGET_I386# define ADDR3264 DWORD# define PE_IMAGE_REL IMAGE_REL_BASED_HIGHLOW# define REL_TYPE_DIRECT R_386_32# define R_XXX_THUNKFIX R_386_32# define R_XXX_RELATIVE R_386_RELATIVE# define IMAGE_FILE_MACHINE 0x014C# define RSRC_RELTYPE 7 /* DIR32NB */ #endif #ifndef IMAGE_NT_SIGNATURE/* ----------------------------------------------------------- *//* definitions below are from winnt.h */ typedef unsigned char BYTE;typedef unsigned short WORD;typedef unsigned int DWORD;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 */} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; #define IMAGE_NT_SIGNATURE  0x00004550  /* PE00 */#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;} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;  #define IMAGE_SIZEOF_FILE_HEADER 20 typedef struct _IMAGE_DATA_DIRECTORY {    DWORD   VirtualAddress;    DWORD   Size;} 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;#ifndef TCC_TARGET_X86_64    DWORD   BaseOfData;#endif    /* NT additional fields. */    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;    ADDR3264 SizeOfStackReserve;    ADDR3264 SizeOfStackCommit;    ADDR3264 SizeOfHeapReserve;    ADDR3264 SizeOfHeapCommit;    DWORD   LoaderFlags;    DWORD   NumberOfRvaAndSizes;    IMAGE_DATA_DIRECTORY DataDirectory[16];} IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER; #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 *//*      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 */ /* Section header format. */#define IMAGE_SIZEOF_SHORT_NAME         8 typedef struct _IMAGE_SECTION_HEADER {    BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];    union {            DWORD   PhysicalAddress;            DWORD   VirtualSize;    } Misc;    DWORD   VirtualAddress;    DWORD   SizeOfRawData;    DWORD   PointerToRawData;    DWORD   PointerToRelocations;    DWORD   PointerToLinenumbers;    WORD    NumberOfRelocations;    WORD    NumberOfLinenumbers;    DWORD   Characteristics;} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; #define IMAGE_SIZEOF_SECTION_HEADER     40 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 {        DWORD Characteristics;        DWORD OriginalFirstThunk;    };    DWORD TimeDateStamp;    DWORD ForwarderChain;    DWORD Name;    DWORD FirstThunk;} IMAGE_IMPORT_DESCRIPTOR; typedef struct _IMAGE_BASE_RELOCATION {    DWORD   VirtualAddress;    DWORD   SizeOfBlock;//  WORD    TypeOffset[1];} IMAGE_BASE_RELOCATION; #define IMAGE_SIZEOF_BASE_RELOCATION     8 #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#define IMAGE_REL_BASED_DIR64           10 #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) /* ----------------------------------------------------------- */#endif /* ndef IMAGE_NT_SIGNATURE *//* ----------------------------------------------------------- */ #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;#ifdef TCC_TARGET_X86_64    IMAGE_OPTIONAL_HEADER64 opthdr;#else#ifdef _WIN64    IMAGE_OPTIONAL_HEADER32 opthdr;#else    IMAGE_OPTIONAL_HEADER opthdr;#endif#endif}; 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) /* ------------------------------------------------------------- *//* internal temporary structures */ enum {    sec_text = 0,    sec_data ,    sec_bss ,    sec_idata ,    sec_pdata ,    sec_other ,    sec_rsrc ,    sec_stab ,    sec_stabstr ,    sec_reloc ,    sec_last}; #if 0static const DWORD pe_sec_flags[] = {    0x60000020, /* ".text"     , */    0xC0000040, /* ".data"     , */    0xC0000080, /* ".bss"      , */    0x40000040, /* ".idata"    , */    0x40000040, /* ".pdata"    , */    0xE0000060, /* < other >   , */    0x40000040, /* ".rsrc"     , */    0x42000802, /* ".stab"     , */    0x42000040, /* ".reloc"    , */};#endif struct section_info {    int cls;    char name[32];    DWORD sh_addr;    DWORD sh_size;    DWORD pe_flags;    Section *sec;    DWORD data_size;    IMAGE_SECTION_HEADER ish;}; struct import_symbol {    int sym_index;    int iat_index;    int thk_offset;}; struct pe_import_info {    int dll_index;    int sym_count;    struct import_symbol **symbols;}; struct pe_info {    TCCState *s1;    Section *reloc;    Section *thunk;    const char *filename;    int type;    DWORD sizeofheaders;    ADDR3264 imagebase;    const char *start_symbol;    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;    struct section_info **sec_info;    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 /* --------------------------------------------*/ 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;} /*----------------------------------------------------------------------------*/ static int dynarray_assoc(void **pp, int n, int key){    int i;    for (i = 0; i < n; ++i, ++pp)    if (key == **(int **) pp)        return i;    return -1;} static DWORD umin(DWORD a, DWORD b){    return a < b ? a : b;} static DWORD umax(DWORD a, DWORD b){    return a < b ? b : a;} static DWORD pe_file_align(struct pe_info *pe, DWORD n){    return (n + (pe->file_align - 1)) & ~(pe->file_align - 1);} static DWORD pe_virtual_align(struct pe_info *pe, DWORD n){    return (n + (pe->section_align - 1)) & ~(pe->section_align - 1);} static void pe_align_section(Section *s, int a){    int i = s->data_offset & (a-1);    if (i)        section_ptr_add(s, a - i);} static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size){    hdr->opthdr.DataDirectory[dir].VirtualAddress = addr;    hdr->opthdr.DataDirectory[dir].Size = size;} struct pe_file {    FILE *op;    DWORD sum;    unsigned pos;}; static int pe_fwrite(void *data, int len, struct pe_file *pf){    WORD *p = data;    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;    }    pf->sum = sum;    return len == ret ? 0 : -1;} static void pe_fpad(struct pe_file *pf, DWORD new_pos){    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;} /*----------------------------------------------------------------------------*/

Lines 1–500 of 2048.