Alien-TinyCCx

 view release on metacpan or  search on metacpan

src/tccpe.c  view on Meta::CPAN

# define IMAGE_FILE_MACHINE 0x8664
# define RSRC_RELTYPE 3

#elif defined TCC_TARGET_ARM
# define ADDR3264 DWORD
# 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 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

#if 0
#ifdef _WIN32
void dbg_printf (const char *fmt, ...)
{
    char buffer[4000];
    va_list arg;
    int x;
    va_start(arg, fmt);
    x = vsprintf (buffer, fmt, arg);
    strcpy(buffer+x, "\n");
    OutputDebugString(buffer);
}
#endif
#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;

src/tccpe.c  view on Meta::CPAN

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

static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum)
{
    if (psum) {
        DWORD sum = *psum;
        WORD *p = data;
        int i;
        for (i = len; i > 0; i -= 2) {
            sum += (i >= 2) ? *p++ : *(BYTE*)p;
            sum = (sum + (sum >> 16)) & 0xFFFF;
        }
        *psum = sum;
    }
    return len == fwrite(data, 1, len, fp) ? 0 : -1;
}

static void pe_fpad(FILE *fp, DWORD new_pos)
{
    DWORD pos = ftell(fp);
    while (++pos <= new_pos)
        fputc(0, fp);
}

/*----------------------------------------------------------------------------*/
static int pe_write(struct pe_info *pe)
{
    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 */
    IMAGE_FILE_MACHINE, /*WORD    Machine; */
    0x0003, /*WORD    NumberOfSections; */
    0x00000000, /*DWORD   TimeDateStamp; */
    0x00000000, /*DWORD   PointerToSymbolTable; */
    0x00000000, /*DWORD   NumberOfSymbols; */
#if defined(TCC_TARGET_X86_64)
    0x00F0, /*WORD    SizeOfOptionalHeader; */
    0x022F  /*WORD    Characteristics; */
#define CHARACTERISTICS_DLL 0x222E
#elif defined(TCC_TARGET_I386)
    0x00E0, /*WORD    SizeOfOptionalHeader; */
    0x030F  /*WORD    Characteristics; */
#define CHARACTERISTICS_DLL 0x230E
#elif defined(TCC_TARGET_ARM)
    0x00E0, /*WORD    SizeOfOptionalHeader; */
    0x010F, /*WORD    Characteristics; */
#define CHARACTERISTICS_DLL 0x230F
#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. */
#if defined(TCC_TARGET_ARM)
    0x00100000,	    /*DWORD   ImageBase; */
#else
    0x00400000,	    /*DWORD   ImageBase; */
#endif
    0x00001000, /*DWORD   SectionAlignment; */

src/tccpe.c  view on Meta::CPAN

        sym = (ElfW(Sym)*)symtab_section->data + sym_index;
        name = pe_export_name(pe->s1, sym);
        if ((sym->st_other & ST_PE_EXPORT)
            /* export only symbols from actually written sections */
            && pe->s1->sections[sym->st_shndx]->sh_addr) {
            p = tcc_malloc(sizeof *p);
            p->index = sym_index;
            p->name = name;
            dynarray_add((void***)&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
    }

    if (0 == sym_count)
        return;

    qsort (sorted, sym_count, sizeof *sorted, sym_cmp);

    pe_align_section(pe->thunk, 16);
    dllname = tcc_basename(pe->filename);

    pe->exp_offs = pe->thunk->data_offset;
    func_o = pe->exp_offs + 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 - pe->exp_offs);
    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, "w");
    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 symbols)\n", buf, sym_count);
    }
#endif

    for (ord = 0; ord < sym_count; ++ord)
    {
        p = sorted[ord], sym_index = p->index, name = p->name;
        /* insert actual address later in pe_relocate_rva */
        put_elf_reloc(symtab_section, pe->thunk,
            func_o, R_XXX_RELATIVE, sym_index);
        *(DWORD*)(pe->thunk->data + name_o)
            = pe->thunk->data_offset + rva_base;
        *(WORD*)(pe->thunk->data + ord_o)
            = ord;
        put_elf_str(pe->thunk, name);
        func_o += sizeof (DWORD);
        name_o += sizeof (DWORD);
        ord_o += sizeof (WORD);
        if (op)
            fprintf(op, "%s\n", name);
    }
    pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
    dynarray_reset(&sorted, &sym_count);
    if (op)
        fclose(op);
}

/* ------------------------------------------------------------- */
static void pe_build_reloc (struct pe_info *pe)
{
    DWORD offset, block_ptr, addr;
    int count, i;
    ElfW_Rel *rel, *rel_end;
    Section *s = NULL, *sr;

    offset = addr = block_ptr = count = i = 0;
    rel = rel_end = NULL;

    for(;;) {
        if (rel < rel_end) {
            int type = ELFW(R_TYPE)(rel->r_info);
            addr = rel->r_offset + s->sh_addr;
            ++ rel;
            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));
                *wp = addr | IMAGE_REL_BASED_HIGHLOW<<12;
                ++count;
                continue;
            }
            -- rel;

        } else if (i < pe->sec_count) {
            sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
            if (sr) {
                rel = (ElfW_Rel *)sr->data;
                rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
            }
            continue;
        }

        if (count) {

src/tccpe.c  view on Meta::CPAN

        if (c == sec_stab && 0 == pe->s1->do_debug)
            continue;

        strcpy(si->name, s->name);
        si->cls = c;
        si->ord = k;
        si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr);
        si->sh_flags = s->sh_flags;

        if (c == sec_data && NULL == pe->thunk)
            pe->thunk = s;

        if (s == pe->thunk) {
            pe_build_imports(pe);
            pe_build_exports(pe);
        }

        if (c == sec_reloc)
            pe_build_reloc (pe);

        if (s->data_offset)
        {
            if (s->sh_type != SHT_NOBITS) {
                si->data = s->data;
                si->data_size = s->data_offset;
            }

            addr += s->data_offset;
            si->sh_size = s->data_offset;
            ++pe->sec_count;
        }
        // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name);
    }

#if 0
    for (i = 1; i < pe->s1->nb_sections; ++i) {
        Section *s = pe->s1->sections[i];
        int type = s->sh_type;
        int flags = s->sh_flags;
        printf("section %-16s %-10s %5x %s,%s,%s\n",
            s->name,
            type == SHT_PROGBITS ? "progbits" :
            type == SHT_NOBITS ? "nobits" :
            type == SHT_SYMTAB ? "symtab" :
            type == SHT_STRTAB ? "strtab" :
            type == SHT_RELX ? "rel" : "???",
            s->data_offset,
            flags & SHF_ALLOC ? "alloc" : "",
            flags & SHF_WRITE ? "write" : "",
            flags & SHF_EXECINSTR ? "exec" : ""
            );
    }
    pe->s1->verbose = 2;
#endif

    tcc_free(section_order);
    return 0;
}

/* ------------------------------------------------------------- */
static void pe_relocate_rva (struct pe_info *pe, Section *s)
{
    Section *sr = s->reloc;
    ElfW_Rel *rel, *rel_end;
    rel_end = (ElfW_Rel *)(sr->data + sr->data_offset);
    for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) {
        if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) {
            int sym_index = ELFW(R_SYM)(rel->r_info);
            DWORD addr = s->sh_addr;
            if (sym_index) {
                ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
                addr = sym->st_value;
            }
            // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name);
            *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
        }
    }
}

/*----------------------------------------------------------------------------*/

static int pe_isafunc(int sym_index)
{
    Section *sr = text_section->reloc;
    ElfW_Rel *rel, *rel_end;
    Elf32_Word info = ELF32_R_INFO(sym_index, R_386_PC32);
    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;
    return 0;
}

/*----------------------------------------------------------------------------*/
static int pe_check_symbols(struct pe_info *pe)
{
    ElfW(Sym) *sym;
    int sym_index, sym_end;
    int ret = 0;

    pe_align_section(text_section, 8);

    sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
    for (sym_index = 1; sym_index < sym_end; ++sym_index) {

        sym = (ElfW(Sym) *)symtab_section->data + sym_index;
        if (sym->st_shndx == SHN_UNDEF) {

            const char *name = symtab_section->link->data + sym->st_name;
            unsigned type = ELFW(ST_TYPE)(sym->st_info);
            int imp_sym = pe_find_import(pe->s1, sym);
            struct import_symbol *is;

            if (0 == imp_sym)
                goto not_found;

            if (type == STT_NOTYPE) {
                /* symbols from assembler have no type, find out which */
                if (pe_isafunc(sym_index))

src/tccpe.c  view on Meta::CPAN

        ret = pe_load_dll(s1, tcc_basename(filename), fd);
    return ret;
}

/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
static unsigned pe_add_uwwind_info(TCCState *s1)
{
    if (NULL == s1->uw_pdata) {
        s1->uw_pdata = find_section(tcc_state, ".pdata");
        s1->uw_pdata->sh_addralign = 4;
        s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL);
    }

    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_X86_64_RELATIVE, s1->uw_sym);
}
#endif
/* ------------------------------------------------------------- */
#ifdef TCC_TARGET_X86_64
#define PE_STDSYM(n,s) n
#else
#define PE_STDSYM(n,s) "_" n s
#endif

static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
{
    const char *start_symbol;
    int pe_type = 0;

    if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16")))
        pe_type = PE_GUI;
    else
    if (TCC_OUTPUT_DLL == s1->output_type) {
        pe_type = PE_DLL;
        /* need this for 'tccelf.c:relocate_section()' */
        s1->output_type = TCC_OUTPUT_EXE;
    }
    else
        pe_type = PE_EXE;

    start_symbol =
        TCC_OUTPUT_MEMORY == s1->output_type
        ? PE_GUI == pe_type ? "__runwinmain" : "_main"
        : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12")
        : PE_GUI == pe_type ? "__winstart" : "__start"
        ;

    if (!s1->leading_underscore || strchr(start_symbol, '@'))
        ++start_symbol;

    /* grab the startup code from libtcc1 */
    if (TCC_OUTPUT_MEMORY != s1->output_type || PE_GUI == pe_type)
        add_elf_sym(symtab_section,
            0, 0,
            ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
            SHN_UNDEF, start_symbol);

    tcc_add_pragma_libs(s1);

    if (0 == s1->nostdlib) {
        static const char *libs[] = {
            "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL
        };
        const char **pp, *p;
        for (pp = libs; 0 != (p = *pp); ++pp) {
            if (0 == *p) {
                if (PE_DLL != pe_type && PE_GUI != pe_type)
                    break;
            } else if (tcc_add_library_err(s1, p) < 0) {
                break;
            }
        }
    }

    if (TCC_OUTPUT_MEMORY == s1->output_type) {
        pe_type = PE_RUN;
#ifdef TCC_IS_NATIVE
        s1->runtime_main = start_symbol;
#endif
    } else {
        pe->start_addr = (DWORD)(uintptr_t)tcc_get_symbol_err(s1, start_symbol);
    }

    pe->type = pe_type;
}

static void pe_set_options(TCCState * s1, struct pe_info *pe)
{
    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;

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

    if ((pe->subsystem >= 10) && (pe->subsystem <= 12))
        pe->imagebase = 0;

    if (s1->has_text_addr)
        pe->imagebase = s1->text_addr;
}

ST_FUNC int pe_output_file(TCCState *s1, const char *filename)
{
    int ret;
    struct pe_info pe;
    int i;

    memset(&pe, 0, sizeof pe);
    pe.filename = filename;
    pe.s1 = s1;

    tcc_add_bcheck(s1);
    pe_add_runtime(s1, &pe);
    relocate_common_syms(); /* assign bss adresses */
    tcc_add_linker_symbols(s1);
    pe_set_options(s1, &pe);

    ret = pe_check_symbols(&pe);
    if (ret)
        ;
    else if (filename) {
        pe_assign_addresses(&pe);
        relocate_syms(s1, 0);
        for (i = 1; i < s1->nb_sections; ++i) {
            Section *s = s1->sections[i];
            if (s->reloc) {
                relocate_section(s1, s);
                pe_relocate_rva(&pe, s);
            }
        }
        if (s1->nb_errors)
            ret = -1;
        else
            ret = pe_write(&pe);
        tcc_free(pe.sec_info);
    } else {
#ifdef TCC_IS_NATIVE
        pe.thunk = data_section;
        pe_build_imports(&pe);
#endif
    }

#ifdef PE_PRINT_SECTIONS
    pe_print_sections(s1, "tcc.log");
#endif
    return ret;
}

/* ------------------------------------------------------------- */



( run in 1.404 second using v1.01-cache-2.11-cpan-71847e10f99 )