From 2f73e42d871e9bed3afccbfd8f4c7098895cc3a3 Mon Sep 17 00:00:00 2001 From: Frederic Feret Date: Thu, 27 Aug 2009 10:12:13 +0200 Subject: [PATCH] various fixes and new options for PE format --- libtcc.c | 4 ++++ tcc.c | 39 +++++++++++++++++++++++++++++++++++++++ tcc.h | 9 +++++++++ tccelf.c | 20 ++++++++++---------- tccpe.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 100 insertions(+), 18 deletions(-) diff --git a/libtcc.c b/libtcc.c index e2027da..dfb000a 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1944,6 +1944,10 @@ TCCState *tcc_new(void) /* XXX: currently the PE linker is not ready to support that */ s->leading_underscore = 1; #endif + + if (s->section_align == 0) + s->section_align = ELF_PAGE_SIZE; + #ifdef TCC_TARGET_I386 s->seg_size = 32; #endif diff --git a/tcc.c b/tcc.c index 501dc01..76c3469 100644 --- a/tcc.c +++ b/tcc.c @@ -386,8 +386,47 @@ int parse_args(TCCState *s, int argc, char **argv) if (strstart(optarg, "-Ttext,", &p)) { s->text_addr = strtoul(p, NULL, 16); s->has_text_addr = 1; + } else if (strstart(optarg, "--section-alignment,", &p)) { + s->section_align = strtoul(p, NULL, 16); + } else if (strstart(optarg, "--image-base,", &p)) { + s->text_addr = strtoul(p, NULL, 16); + s->has_text_addr = 1; +#ifdef TCC_TARGET_PE + } else if (strstart(optarg, "--file-alignment,", &p)) { + s->pe_file_align = strtoul(p, NULL, 16); + } else if (strstart(optarg, "--subsystem,", &p)) { +#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) + if (!strcmp(p, "native")) + s->pe_subsystem = 1; + else if (!strcmp(p, "console")) + s->pe_subsystem = 3; + else if (!strcmp(p, "gui")) + s->pe_subsystem = 2; + else if (!strcmp(p, "posix")) + s->pe_subsystem = 7; + else if (!strcmp(p, "efiapp")) + s->pe_subsystem = 10; + else if (!strcmp(p, "efiboot")) + s->pe_subsystem = 11; + else if (!strcmp(p, "efiruntime")) + s->pe_subsystem = 12; + else if (!strcmp(p, "efirom")) + s->pe_subsystem = 13; +#endif + else { + error("invalid subsystem '%s'", p); + } +#endif } else if (strstart(optarg, "--oformat,", &p)) { +#if defined(TCC_TARGET_PE) + if (strstart(p, "pe-", NULL)) { +#else +#if defined(TCC_TARGET_X86_64) + if (strstart(p, "elf64-", NULL)) { +#else if (strstart(p, "elf32-", NULL)) { +#endif +#endif s->output_format = TCC_OUTPUT_FORMAT_ELF; } else if (!strcmp(p, "binary")) { s->output_format = TCC_OUTPUT_FORMAT_BINARY; diff --git a/tcc.h b/tcc.h index 8d52491..b481981 100644 --- a/tcc.h +++ b/tcc.h @@ -515,6 +515,15 @@ struct TCCState { int seg_size; #endif + /* section alignment */ + unsigned long section_align; + +#ifdef TCC_TARGET_PE + /* PE info */ + int pe_subsystem; + unsigned long pe_file_align; +#endif + #ifndef TCC_TARGET_PE #ifdef TCC_TARGET_X86_64 /* write PLT and GOT here */ diff --git a/tccelf.c b/tccelf.c index 34a4df9..5d73b4a 100644 --- a/tccelf.c +++ b/tccelf.c @@ -1632,10 +1632,10 @@ int elf_output_file(TCCState *s1, const char *filename) addr = s1->text_addr; /* we ensure that (addr % ELF_PAGE_SIZE) == file_offset % ELF_PAGE_SIZE */ - a_offset = addr & (ELF_PAGE_SIZE - 1); - p_offset = file_offset & (ELF_PAGE_SIZE - 1); + a_offset = addr & (s1->section_align - 1); + p_offset = file_offset & (s1->section_align - 1); if (a_offset < p_offset) - a_offset += ELF_PAGE_SIZE; + a_offset += s1->section_align; file_offset += (a_offset - p_offset); } else { if (file_type == TCC_OUTPUT_DLL) @@ -1643,7 +1643,7 @@ int elf_output_file(TCCState *s1, const char *filename) else addr = ELF_START_ADDR; /* compute address after headers */ - addr += (file_offset & (ELF_PAGE_SIZE - 1)); + addr += (file_offset & (s1->section_align - 1)); } /* dynamic relocation table information, for .dynamic section */ @@ -1661,7 +1661,7 @@ int elf_output_file(TCCState *s1, const char *filename) ph->p_flags = PF_R | PF_X; else ph->p_flags = PF_R | PF_W; - ph->p_align = ELF_PAGE_SIZE; + ph->p_align = s1->section_align; /* we do the following ordering: interp, symbol tables, relocations, progbits, nobits */ @@ -1731,12 +1731,12 @@ int elf_output_file(TCCState *s1, const char *filename) if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { /* if in the middle of a page, we duplicate the page in memory so that one copy is RX and the other is RW */ - if ((addr & (ELF_PAGE_SIZE - 1)) != 0) - addr += ELF_PAGE_SIZE; + if ((addr & (s1->section_align - 1)) != 0) + addr += s1->section_align; } else { - addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1); - file_offset = (file_offset + ELF_PAGE_SIZE - 1) & - ~(ELF_PAGE_SIZE - 1); + addr = (addr + s1->section_align - 1) & ~(s1->section_align - 1); + file_offset = (file_offset + s1->section_align - 1) & + ~(s1->section_align - 1); } } } diff --git a/tccpe.c b/tccpe.c index d16df50..d53782d 100644 --- a/tccpe.c +++ b/tccpe.c @@ -349,6 +349,9 @@ struct pe_info { 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; @@ -417,14 +420,14 @@ ST_FN DWORD umax(DWORD a, DWORD b) return a < b ? b : a; } -ST_FN DWORD pe_file_align(DWORD n) +ST_FN DWORD pe_file_align(struct pe_info *pe, DWORD n) { - return (n + (0x200 - 1)) & ~(0x200 - 1); + return (n + (pe->file_align - 1)) & ~(pe->file_align - 1); } -ST_FN DWORD pe_virtual_align(DWORD n) +ST_FN DWORD pe_virtual_align(struct pe_info *pe, DWORD n) { - return (n + (0x1000 - 1)) & ~(0x1000 - 1); + return (n + (pe->section_align - 1)) & ~(pe->section_align - 1); } ST_FN void pe_align_section(Section *s, int a) @@ -578,7 +581,7 @@ ST_FN int pe_write(struct pe_info *pe) return -1; } - pe->sizeofheaders = pe_file_align( + pe->sizeofheaders = pe_file_align(pe, sizeof (struct pe_header) + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) ); @@ -648,11 +651,11 @@ ST_FN int pe_write(struct pe_info *pe) psh->VirtualAddress = addr; psh->Misc.VirtualSize = size; pe_header.opthdr.SizeOfImage = - umax(pe_virtual_align(size + addr), pe_header.opthdr.SizeOfImage); + umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage); if (si->data_size) { psh->PointerToRawData = file_offset; - file_offset = pe_file_align(file_offset + si->data_size); + file_offset = pe_file_align(pe, file_offset + si->data_size); psh->SizeOfRawData = file_offset - psh->PointerToRawData; } } @@ -1085,7 +1088,7 @@ ST_FN int pe_assign_addresses (struct pe_info *pe) strcpy(si->name, s->name); si->cls = c; si->ord = k; - si->sh_addr = s->sh_addr = addr = pe_virtual_align(addr); + 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) @@ -1649,6 +1652,33 @@ PUB_FN int pe_output_file(TCCState * s1, const char *filename) } else { pe.imagebase = 0x00400000; } + + /* if no subsystem specified, we use "console" subsystem by default */ + if (s1->pe_subsystem != 0) + pe.subsystem = s1->pe_subsystem; + else + pe.subsystem = 3; + + /* 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; + pe_assign_addresses(&pe); relocate_syms(s1, 0); for (i = 1; i < s1->nb_sections; ++i) {