Alien-TinyCC
view release on metacpan or search on metacpan
src/tccpe.c view on Meta::CPAN
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 */
/*
#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
*/
enum {
sec_text = 0,
sec_data ,
sec_bss ,
sec_idata ,
sec_pdata ,
sec_other ,
sec_rsrc ,
sec_stab ,
sec_reloc ,
sec_last
};
static const DWORD pe_sec_flags[] = {
0x60000020, /* ".text" , */
0xC0000040, /* ".data" , */
0xC0000080, /* ".bss" , */
0x40000040, /* ".idata" , */
0x40000040, /* ".pdata" , */
0xE0000060, /* < other > , */
0x40000040, /* ".rsrc" , */
0x42000802, /* ".stab" , */
0x42000040, /* ".reloc" , */
};
struct section_info {
int cls, ord;
char name[32];
DWORD sh_addr;
DWORD sh_size;
DWORD sh_flags;
unsigned char *data;
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;
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 = symtab_section->link->data + sym->st_name;
if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & 2))
return name + 1;
return name;
}
static int pe_find_import(TCCState * s1, ElfW(Sym) *sym)
{
char buffer[200];
src/tccpe.c view on Meta::CPAN
for (i = 0; i < pe->sec_count; ++i) {
DWORD addr, size;
const char *sh_name;
si = pe->sec_info + i;
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:
pe_header.opthdr.BaseOfCode = addr;
pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr;
break;
case sec_data:
#ifndef TCC_TARGET_X86_64
pe_header.opthdr.BaseOfData = addr;
#endif
break;
case sec_bss:
break;
case sec_reloc:
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
break;
case sec_rsrc:
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;
case sec_stab:
break;
}
if (pe->thunk == pe->s1->sections[si->ord]) {
if (pe->imp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT,
pe->imp_offs + addr, pe->imp_size);
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT,
pe->iat_offs + addr, pe->iat_size);
}
if (pe->exp_size) {
pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT,
pe->exp_offs + addr, pe->exp_size);
}
}
strncpy((char*)psh->Name, sh_name, sizeof psh->Name);
psh->Characteristics = pe_sec_flags[si->cls];
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) {
psh->PointerToRawData = file_offset;
file_offset = pe_file_align(pe, file_offset + si->data_size);
psh->SizeOfRawData = file_offset - psh->PointerToRawData;
}
}
//pe_header.filehdr.TimeDateStamp = time(NULL);
pe_header.filehdr.NumberOfSections = pe->sec_count;
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)
pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL;
sum = 0;
pe_fwrite(&pe_header, sizeof pe_header, op, &sum);
for (i = 0; i < pe->sec_count; ++i)
pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum);
pe_fpad(op, pe->sizeofheaders);
for (i = 0; i < pe->sec_count; ++i) {
si = pe->sec_info + i;
psh = &si->ish;
if (si->data_size) {
pe_fwrite(si->data, si->data_size, op, &sum);
file_offset = psh->PointerToRawData + psh->SizeOfRawData;
pe_fpad(op, file_offset);
}
}
pe_header.opthdr.CheckSum = sum + file_offset;
fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET);
pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL);
fclose (op);
if (2 == pe->s1->verbose)
printf("-------------------------------\n");
if (pe->s1->verbose)
printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset);
return 0;
}
/*----------------------------------------------------------------------------*/
#if defined(TCC_TARGET_X86_64)
#define REL_TYPE_DIRECT R_X86_64_64
#define R_XXX_THUNKFIX R_X86_64_PC32
#define R_XXX_RELATIVE R_X86_64_RELATIVE
#elif defined(TCC_TARGET_I386)
#define REL_TYPE_DIRECT R_386_32
#define R_XXX_THUNKFIX R_386_32
src/tccpe.c view on Meta::CPAN
/* ------------------------------------------------------------- */
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) {
/* store the last block and ready for a new one */
struct pe_reloc_header *hdr;
if (count & 1) /* align for DWORDS */
section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
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;
}
if (rel >= rel_end)
break;
}
}
/* ------------------------------------------------------------- */
static int pe_section_class(Section *s)
{
int type, flags;
const char *name;
type = s->sh_type;
flags = s->sh_flags;
name = s->name;
if (flags & SHF_ALLOC) {
if (type == SHT_PROGBITS) {
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_other;
} else if (type == SHT_NOBITS) {
if (flags & SHF_WRITE)
return sec_bss;
}
} else {
if (0 == strcmp(name, ".reloc"))
return sec_reloc;
if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */
return sec_stab;
}
return -1;
}
static int pe_assign_addresses (struct pe_info *pe)
{
int i, k, o, c;
DWORD addr;
int *section_order;
struct section_info *si;
Section *s;
// pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
for (o = k = 0 ; k < sec_last; ++k) {
for (i = 1; i < pe->s1->nb_sections; ++i) {
s = pe->s1->sections[i];
if (k == pe_section_class(s)) {
// printf("%s %d\n", s->name, k);
s->sh_addr = pe->imagebase;
section_order[o++] = i;
}
}
}
pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
addr = pe->imagebase + 1;
for (i = 0; i < o; ++i)
{
k = section_order[i];
s = pe->s1->sections[k];
c = pe_section_class(s);
si = &pe->sec_info[pe->sec_count];
#ifdef PE_MERGE_DATA
if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
/* append .bss to .data */
s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1;
addr += s->data_offset;
si[-1].sh_size = addr - si[-1].sh_addr;
continue;
}
#endif
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) {
( run in 0.458 second using v1.01-cache-2.11-cpan-9bca49b1385 )