int pe_load_res_file(TCCState *s1, int fd) { struct pe_rsrc_header hdr; Section *rsrc_section; int i, ret = -1; BYTE *ptr; lseek(fd, 0, SEEK_SET); if (!read_n(fd, &hdr, sizeof hdr)) goto quit; if (!pe_test_res_file(&hdr, sizeof hdr)) goto quit; rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); lseek(fd, hdr.sectionhdr.PointerToRawData, SEEK_SET); if (!read_n(fd, ptr, hdr.sectionhdr.SizeOfRawData)) goto quit; lseek(fd, hdr.sectionhdr.PointerToRelocations, SEEK_SET); for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) { struct pe_rsrc_reloc rel; if (!read_n(fd, &rel, sizeof rel)) goto quit; if (rel.type != 7) goto quit; // DIR32NB put_elf_reloc(symtab_section, rsrc_section, rel.offset, R_386_RELATIVE, 0); } ret = 0; quit: if (ret) error_noabort("unrecognized resource file format"); return ret; }
/* ------------------------------------------------------------- */ PUB_FN int pe_load_def_file(TCCState *s1, int fd) { DLLReference *dllref; int state = 0, ret = -1; char line[400], dllname[80], *p; FILE *fp = fdopen(dup(fd), "rb"); if (NULL == fp) goto quit; for (;;) { p = get_line(line, sizeof line, fp); if (NULL == p) break; if (0 == *p || ';' == *p) continue; switch (state) { case 0: if (0 != strnicmp(p, "LIBRARY", 7)) goto quit; strcpy(dllname, trimfront(p+7)); ++state; continue; case 1: if (0 != stricmp(p, "EXPORTS")) goto quit; ++state; continue; case 2: dllref = tcc_malloc(sizeof(DLLReference) + strlen(dllname)); strcpy(dllref->name, dllname); dllref->level = 0; dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); ++state; default: add_elf_sym(s1->dynsymtab_section, s1->nb_loaded_dlls, 0, ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), 0, text_section->sh_num, p); continue; } } ret = 0; quit: if (fp) fclose(fp); if (ret) error_noabort("unrecognized export definition file format"); return ret; }
int pe_load_def_file(TCCState *s1, int fd) { DLLReference *dllref; int state = 0, ret = -1, hint; char line[400], dllname[80], *p, *ordinal; FILE *fp = fdopen(dup(fd), "rb"); if (fp == NULL) goto quit; for (;;) { p = get_line(line, sizeof line, fp); if (p == NULL) break; if (*p == 0 || *p == ';') continue; switch (state) { case 0: if (strncasecmp(p, "LIBRARY", 7) != 0) goto quit; strcpy(dllname, trimfront(p + 7)); ++state; continue; case 1: if (strcasecmp(p, "EXPORTS") != 0) goto quit; ++state; continue; case 2: dllref = tcc_malloc(sizeof(DLLReference) + strlen(dllname)); strcpy(dllref->name, dllname); dllref->level = 0; dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); ++state; default: hint = 0; ordinal = strchr(p, '@'); if (ordinal) { *ordinal = 0; trimback(p, ordinal); ordinal++; hint = atoi(ordinal); } add_elf_sym(s1->dynsymtab_section, s1->nb_loaded_dlls, 0, ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), hint, text_section->sh_num, p); continue; } } ret = 0; quit: if (fp) fclose(fp); if (ret) error_noabort("unrecognized export definition file format"); return ret; }
static int pe_check_symbols(struct pe_info *pe) { Elf32_Sym *sym; int sym_index, sym_end; int ret = 0; pe_align_section(text_section, 8); sym_end = symtab_section->data_offset / sizeof(Elf32_Sym); for (sym_index = 1; sym_index < sym_end; ++sym_index) { sym = (Elf32_Sym *) symtab_section->data + sym_index; if (sym->st_shndx == SHN_UNDEF) { const char *name = symtab_section->link->data + sym->st_name; unsigned type = ELF32_ST_TYPE(sym->st_info); int imp_sym = pe_find_import(pe->s1, name); struct import_symbol *is; if (imp_sym == 0) goto not_found; is = pe_add_import(pe, imp_sym); if (!is) goto not_found; if (type == STT_FUNC) { unsigned long offset = is->thk_offset; if (offset) { // Got aliased symbol, like stricmp and _stricmp } else { char buffer[100]; offset = text_section->data_offset; // Add the 'jmp IAT[x]' instruction *(WORD *) section_ptr_add(text_section, 8) = 0x25FF; // 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), ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), 0, SHN_UNDEF, buffer); put_elf_reloc(symtab_section, text_section, offset + 2, R_386_32, is->iat_index); is->thk_offset = offset; } // tcc_realloc might have altered sym's address sym = (Elf32_Sym *) symtab_section->data + sym_index; // Patch the original symbol sym->st_value = offset; sym->st_shndx = text_section->sh_num; sym->st_other &= ~1; // Do not export continue; } if (type == STT_OBJECT) { if (is->iat_index == 0) { // Original symbol will be patched later in pe_build_imports is->iat_index = sym_index; continue; } } not_found: error_noabort("undefined symbol '%s'", name); ret = 1; } else if (pe->s1->rdynamic && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { // If -rdynamic option, then export all non local symbols sym->st_other |= 1; } } return ret; }
static void pe_build_exports(struct pe_info *pe) { Elf32_Sym *sym; int sym_index, sym_end; DWORD rva_base, func_o, name_o, ord_o, str_o; struct pe_export_header *hdr; int sym_count, n, ord, *sorted, *sp; FILE *op; char buf[260]; const char *dllname; const char *name; rva_base = pe->thunk->sh_addr - pe->imagebase; sym_count = 0; n = 1; sorted = NULL; op = NULL; sym_end = symtab_section->data_offset / sizeof(Elf32_Sym); for (sym_index = 1; sym_index < sym_end; ++sym_index) { sym = (Elf32_Sym *) symtab_section->data + sym_index; name = symtab_section->link->data + sym->st_name; // Only export symbols from actually written sections if ((sym->st_other & 1) && pe->s1->sections[sym->st_shndx]->sh_addr) { dynarray_add((void ***) &sorted, &sym_count, (void *) n); dynarray_add((void ***) &sorted, &sym_count, (void *) name); } ++n; } if (sym_count == 0) return; sym_count /= 2; qsort(sorted, sym_count, 2 * sizeof(sorted[0]), 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(struct pe_export_header); 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 (pe->def != NULL) { // Write exports to .def file op = fopen(pe->def, "w"); if (op == NULL) { error_noabort("could not create '%s': %s", pe->def, strerror(errno)); } else { fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); if (verbose) { printf("<- %s (%d symbols)\n", buf, sym_count); } } } for (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2) { sym_index = sp[0]; name = (const char *) sp[1]; // Insert actual address later in pe_relocate_rva put_elf_reloc(symtab_section, pe->thunk, func_o, R_386_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@%d\n", name, ord); } pe->exp_size = pe->thunk->data_offset - pe->exp_offs; tcc_free(sorted); if (op) fclose(op); }
static int pe_write(struct pe_info *pe) { int i; int fd; FILE *op; FILE *stubfile; char *stub; int stub_size; DWORD file_offset, r; Section *s; if (pe->stub) { stubfile = fopen(pe->stub, "rb"); if (stubfile == NULL) { error_noabort("could not read '%s': %s", pe->stub, strerror(errno)); return 1; } fseek(stubfile, 0, SEEK_END); stub_size = ftell(stubfile); fseek(stubfile, 0, SEEK_SET); if (stub_size < sizeof(IMAGE_DOS_HEADER)) { error_noabort("invalid stub (%d bytes): %s", stub_size, pe->stub); return 1; } stub = tcc_malloc(stub_size); if (fread(stub, 1, stub_size, stubfile) != stub_size) { error_noabort("error reading stub '%s': %s", pe->stub, strerror(errno)); return 1; } fclose(stubfile); } else { stub_size = DOSSTUB_SIZE + sizeof(IMAGE_DOS_HEADER); stub = tcc_malloc(stub_size); memcpy(stub, &pe_doshdr, sizeof(IMAGE_DOS_HEADER)); memcpy(stub + sizeof(IMAGE_DOS_HEADER), pe_dosstub, DOSSTUB_SIZE); } ((PIMAGE_DOS_HEADER) stub)->e_lfanew = stub_size; fd = open(pe->filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0777); if (fd < 0) { error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); return 1; } op = fdopen(fd, "wb"); pe->sizeofheaders = pe_file_align(pe, stub_size + sizeof(DWORD) + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER) + pe->sec_count * sizeof (IMAGE_SECTION_HEADER)); file_offset = pe->sizeofheaders; pe_fpad(op, file_offset, 0); if (verbose == 2) { printf("------------------------------------\n virt file size ord section" "\n"); } for (i = 0; i < pe->sec_count; ++i) { struct section_info *si = pe->sec_info + i; const char *sh_name = si->name; unsigned long addr = si->sh_addr - pe->imagebase; unsigned long size = si->sh_size; IMAGE_SECTION_HEADER *psh = &si->ish; if (verbose == 2) { printf("%6lx %6lx %6lx %4d %s\n", addr, file_offset, size, si->ord, sh_name); } switch (si->cls) { case sec_text: pe_opthdr.BaseOfCode = addr; pe_opthdr.SizeOfCode += size; pe_opthdr.AddressOfEntryPoint = ((Elf32_Sym *) symtab_section->data)[pe->start_sym_index].st_value - pe->imagebase; break; case sec_data: pe_opthdr.BaseOfData = addr; pe_opthdr.SizeOfInitializedData += size; break; case sec_bss: pe_opthdr.SizeOfUninitializedData += size; break; case sec_reloc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); break; case sec_rsrc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); break; case sec_stab: break; } if (pe->thunk == pe->s1->sections[si->ord]) { if (pe->imp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT, pe->imp_offs + addr, pe->imp_size); pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT, pe->iat_offs + addr, pe->iat_size); } if (pe->exp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT, pe->exp_offs + addr, pe->exp_size); } } strcpy((char *) psh->Name, sh_name); psh->Characteristics = pe_sec_flags[si->cls]; psh->VirtualAddress = addr; psh->Misc.VirtualSize = size; pe_opthdr.SizeOfImage = umax(pe_virtual_align(size + addr), pe_opthdr.SizeOfImage); if (si->sh_size) { psh->PointerToRawData = r = file_offset; for (s = si->first; s; s = s->next) { if (s->sh_type != SHT_NOBITS) { file_offset = align(file_offset, s->sh_addralign); pe_fpad(op, file_offset, si->cls == sec_text ? 0x90 : 0x00); fwrite(s->data, 1, s->data_offset, op); file_offset += s->data_offset; } } file_offset = pe_file_align(pe, file_offset); psh->SizeOfRawData = file_offset - r; pe_fpad(op, file_offset, 0); } } pe_filehdr.TimeDateStamp = time(NULL); pe_filehdr.NumberOfSections = pe->sec_count; pe_filehdr.Characteristics = do_debug ? 0x0102 : 0x030E; pe_opthdr.SizeOfHeaders = pe->sizeofheaders; pe_opthdr.ImageBase = pe->imagebase; pe_opthdr.FileAlignment = pe->filealign; if (pe->type == PE_DLL) { pe_filehdr.Characteristics = do_debug ? 0x2102 : 0x230E; } else if (pe->type != PE_GUI) { pe_opthdr.Subsystem = 3; } if (!pe->reloc) pe_filehdr.Characteristics |= 1; if (pe->s1->noshare) pe_filehdr.Characteristics |= 0x4000; fseek(op, 0, SEEK_SET); fwrite(stub, 1, stub_size, op); fwrite(&pe_ntsig, 1, sizeof pe_ntsig, op); fwrite(&pe_filehdr, 1, sizeof pe_filehdr, op); fwrite(&pe_opthdr, 1, sizeof pe_opthdr, op); for (i = 0; i < pe->sec_count; ++i) { fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op); } fclose(op); if (verbose == 2) { printf("------------------------------------\n"); } if (verbose) { printf("<- %s (%lu bytes)\n", pe->filename, file_offset); } tcc_free(stub); return 0; }
ST_FN void pe_build_exports(struct pe_info *pe) { Elf32_Sym *sym; int sym_index, sym_end; DWORD rva_base, func_o, name_o, ord_o, str_o; struct pe_export_header *hdr; int sym_count, n, ord, *sorted, *sp; FILE *op; char buf[MAX_PATH]; const char *dllname; const char *name; rva_base = pe->thunk->sh_addr - pe->imagebase; sym_count = 0, n = 1, sorted = NULL, op = NULL; sym_end = symtab_section->data_offset / sizeof(Elf32_Sym); for (sym_index = 1; sym_index < sym_end; ++sym_index) { sym = (Elf32_Sym*)symtab_section->data + sym_index; name = symtab_section->link->data + sym->st_name; if ((sym->st_other & 1) /* export only symbols from actually written sections */ && pe->s1->sections[sym->st_shndx]->sh_addr) { dynarray_add((void***)&sorted, &sym_count, (void*)n); dynarray_add((void***)&sorted, &sym_count, (void*)name); } ++n; #if 0 if (sym->st_other & 1) printf("export: %s\n", name); if (sym->st_other & 2) printf("stdcall: %s\n", name); #endif } if (0 == sym_count) return; sym_count /= 2; qsort (sorted, sym_count, 2 * sizeof sorted[0], 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(struct pe_export_header); 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 */ strcpy(buf, pe->filename); strcpy(tcc_fileextension(buf), ".def"); op = fopen(buf, "w"); if (NULL == op) { 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 (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2) { sym_index = sp[0], name = (const char *)sp[1]; /* insert actual address later in pe_relocate_rva */ put_elf_reloc(symtab_section, pe->thunk, func_o, R_386_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; tcc_free(sorted); }
/*----------------------------------------------------------------------------*/ ST_FN int pe_write(struct pe_info *pe) { int i; FILE *op; DWORD file_offset, r; op = fopen(pe->filename, "wb"); if (NULL == op) { error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); return 1; } pe->sizeofheaders = pe_file_align( sizeof pe_header + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) ); file_offset = pe->sizeofheaders; pe_fpad(op, file_offset); if (2 == pe->s1->verbose) printf("-------------------------------" "\n virt file size section" "\n"); for (i = 0; i < pe->sec_count; ++i) { struct section_info *si = pe->sec_info + i; const char *sh_name = si->name; unsigned long addr = si->sh_addr - pe->imagebase; unsigned long size = si->sh_size; IMAGE_SECTION_HEADER *psh = &si->ish; if (2 == pe->s1->verbose) printf("%6lx %6lx %6lx %s\n", addr, file_offset, 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: pe_header.opthdr.BaseOfData = addr; break; case sec_bss: break; case sec_reloc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); break; case sec_rsrc: pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); break; case sec_stab: break; } if (pe->thunk == pe->s1->sections[si->ord]) { if (pe->imp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT, pe->imp_offs + addr, pe->imp_size); pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT, pe->iat_offs + addr, pe->iat_size); } if (pe->exp_size) { pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT, pe->exp_offs + addr, pe->exp_size); } } strcpy((char*)psh->Name, sh_name); psh->Characteristics = pe_sec_flags[si->cls]; psh->VirtualAddress = addr; psh->Misc.VirtualSize = size; pe_header.opthdr.SizeOfImage = umax(pe_virtual_align(size + addr), pe_header.opthdr.SizeOfImage); if (si->data_size) { psh->PointerToRawData = r = file_offset; fwrite(si->data, 1, si->data_size, op); file_offset = pe_file_align(file_offset + si->data_size); psh->SizeOfRawData = file_offset - r; pe_fpad(op, file_offset); } } // 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; if (PE_DLL == pe->type) pe_header.filehdr.Characteristics = 0x230E; else if (PE_GUI != pe->type) pe_header.opthdr.Subsystem = 3; fseek(op, SEEK_SET, 0); fwrite(&pe_header, 1, sizeof pe_header, op); for (i = 0; i < pe->sec_count; ++i) fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op); fclose (op); if (2 == pe->s1->verbose) printf("-------------------------------\n"); if (pe->s1->verbose) printf("<- %s (%lu bytes)\n", pe->filename, file_offset); return 0; }