static void pe_build_reloc(struct pe_info *pe) { DWORD offset, block_ptr, addr; int count, i; Elf32_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 = ELF32_R_TYPE(rel->r_info); addr = rel->r_offset + s->sh_addr; rel++; if (type != R_386_32) 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 (s) s = s->next; if (!s && i < pe->sec_count) s = pe->sec_info[i++].first; if (s) { sr = s->reloc; if (sr) { rel = (Elf32_Rel *) sr->data; rel_end = (Elf32_Rel *) (sr->data + sr->data_offset); } continue; } } if (count) { // Store the last block and ready for a new one struct pe_reloc_header *hdr; // Align for DWORDS if (count & 1) { 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; } }
/* ------------------------------------------------------------- */ ST_FN void pe_build_reloc (struct pe_info *pe) { DWORD offset, block_ptr, addr; int count, i; Elf32_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 = ELF32_R_TYPE(rel->r_info); addr = rel->r_offset + s->sh_addr; ++ rel; if (type != R_386_32) 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 = (Elf32_Rel *)sr->data; rel_end = (Elf32_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; } }
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; }
/*********************************************************** * 功能: 增加COFF符号 * symtab: 保存COFF符号表的节 * name: 符号名称 * val: 与符号相关的值 * sec_index: 定义此符号的节 * type: Coff符号类型 * StorageClass: Coff符号存储类别 * 返回值: 符号COFF符号表中序号 **********************************************************/ int coffsym_add(Section *symtab,char* name, int val, int sec_index, short type, char StorageClass) { CoffSym *cfsym; int cs,keyno; char *csname; Section *strtab = symtab->link; int *hashtab; hashtab = symtab->hashtab; cs = coffsym_search(symtab,name); if(cs == 0) { cfsym = section_ptr_add(symtab, sizeof(CoffSym)); csname = coffstr_add(strtab, name); cfsym->Name = csname - strtab->data; cfsym->Value = val; cfsym->Section = sec_index; cfsym->Type = type; cfsym->StorageClass = StorageClass; cfsym->Value = val; keyno = elf_hash(name); cfsym->Next = hashtab[keyno]; cs = cfsym - (CoffSym*)symtab->data; hashtab[keyno] = cs; } return cs; }
/*********************************************************** * 功能: 增加COFF重定位信息 * offset: 需要进行重定位的代码或数据在其相应节的偏移位置 * cfsym: 符号表的索引 * section: 符号所在节,重点讲一下与Coff区别 * type: 重定位类型 **********************************************************/ void coffreloc_direct_add(int offset, int cfsym, char section, char type) { CoffReloc *rel; rel = section_ptr_add(sec_rel, sizeof(CoffReloc)); rel->offset = offset; rel->cfsym = cfsym; rel->section = section; rel->type = type; }
/*********************************************************** * 功能: 增加COFF符号名字符串 * strtab: 保存COFF字符串表的节 * name: 符号名称字符串 * 返回值: 新增COFF字符串 **********************************************************/ char *coffstr_add(Section *strtab,char* name) { int len; char *pstr; len = strlen(name); pstr = section_ptr_add(strtab, len+1); memcpy(pstr,name,len); return pstr; }
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 void pe_build_imports(struct pe_info *pe) { int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; DWORD rva_base = pe->thunk->sh_addr - pe->imagebase; int ndlls = pe->imp_count; for (sym_cnt = i = 0; i < ndlls; ++i) { sym_cnt += pe->imp_info[i]->sym_count; } if (sym_cnt == 0) return; pe_align_section(pe->thunk, 16); pe->imp_offs = dll_ptr = pe->thunk->data_offset; pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header); pe->iat_offs = dll_ptr + pe->imp_size; pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD); section_ptr_add(pe->thunk, pe->imp_size + 2 * pe->iat_size); thk_ptr = pe->iat_offs; ent_ptr = pe->iat_offs + pe->iat_size; for (i = 0; i < pe->imp_count; ++i) { struct pe_import_header *hdr; int k, n, v; struct pe_import_info *p = pe->imp_info[i]; const char *name = pe->s1->loaded_dlls[p->dll_index - 1]->name; // Put the DLL name into the import header v = put_elf_str(pe->thunk, name); hdr = (struct pe_import_header *) (pe->thunk->data + dll_ptr); hdr->first_thunk = thk_ptr + rva_base; hdr->first_entry = ent_ptr + rva_base; hdr->lib_name_offset = v + rva_base; for (k = 0, n = p->sym_count; k <= n; ++k) { if (k < n) { DWORD iat_index = p->symbols[k]->iat_index; int sym_index = p->symbols[k]->sym_index; Elf32_Sym *imp_sym = (Elf32_Sym *) pe->s1->dynsymtab_section->data + sym_index; Elf32_Sym *org_sym = (Elf32_Sym *) symtab_section->data + iat_index; const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name; org_sym->st_value = thk_ptr; org_sym->st_shndx = pe->thunk->sh_num; v = pe->thunk->data_offset + rva_base; *(WORD *) section_ptr_add(pe->thunk, sizeof(WORD)) = imp_sym->st_other; // Hint put_elf_str(pe->thunk, name); } else { v = 0; // Last entry is zero } *(DWORD *)(pe->thunk->data + thk_ptr) = v; *(DWORD *)(pe->thunk->data + ent_ptr) = v; thk_ptr += sizeof(DWORD); ent_ptr += sizeof(DWORD); } dll_ptr += sizeof(struct pe_import_header); dynarray_reset(&p->symbols, &p->sym_count); } dynarray_reset(&pe->imp_info, &pe->imp_count); }
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 asm_parse_directive(TCCState *s1) { int n, offset, v, size, tok1; Section *sec; uint8_t *ptr; /* assembler directive */ next(); sec = cur_text_section; switch(tok) { case TOK_ASM_align: case TOK_ASM_p2align: case TOK_ASM_skip: case TOK_ASM_space: tok1 = tok; next(); n = asm_int_expr(s1); if (tok1 == TOK_ASM_p2align) { if (n < 0 || n > 30) tcc_error("invalid p2align, must be between 0 and 30"); n = 1 << n; tok1 = TOK_ASM_align; } if (tok1 == TOK_ASM_align) { if (n < 0 || (n & (n-1)) != 0) tcc_error("alignment must be a positive power of two"); offset = (ind + n - 1) & -n; size = offset - ind; /* the section must have a compatible alignment */ if (sec->sh_addralign < n) sec->sh_addralign = n; } else { size = n; } v = 0; if (tok == ',') { next(); v = asm_int_expr(s1); } zero_pad: if (sec->sh_type != SHT_NOBITS) { sec->data_offset = ind; ptr = section_ptr_add(sec, size); memset(ptr, v, size); } ind += size; break; case TOK_ASM_quad: next(); for(;;) { uint64_t vl; const char *p; p = tokc.cstr->data; if (tok != TOK_PPNUM) { error_constant: tcc_error("64 bit constant"); } vl = strtoll(p, (char **)&p, 0); if (*p != '\0') goto error_constant; next(); if (sec->sh_type != SHT_NOBITS) { /* XXX: endianness */ gen_le32(vl); gen_le32(vl >> 32); } else { ind += 8; } if (tok != ',') break; next(); }
void genblk(unsigned char *data, int size) { memcpy(section_ptr_add(cur_text_section, size), data, size); }
void genword(int w) { *(int *) section_ptr_add(cur_text_section, 4) = w; }
void gen(int c) { *(char *) section_ptr_add(cur_text_section, 1) = c; }
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); }
/* generate function epilog */ void gfunc_epilog(void) { int v, saved_ind; #ifdef CONFIG_TCC_BCHECK if (tcc_state->do_bounds_check && func_bound_offset != lbounds_section->data_offset) { int saved_ind; int *bounds_ptr; Sym *sym, *sym_data; /* add end of table info */ bounds_ptr = section_ptr_add(lbounds_section, sizeof(int)); *bounds_ptr = 0; /* generate bound local allocation */ saved_ind = ind; ind = func_sub_sp_offset; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, func_bound_offset, lbounds_section->data_offset); greloc(cur_text_section, sym_data, ind + 1, R_386_32); oad(0xb8, 0); /* mov %eax, xxx */ sym = external_global_sym(TOK___bound_local_new, &func_old_type, 0); greloc(cur_text_section, sym, ind + 1, R_386_PC32); oad(0xe8, -4); ind = saved_ind; /* generate bound check local freeing */ o(0x5250); /* save returned value, if any */ greloc(cur_text_section, sym_data, ind + 1, R_386_32); oad(0xb8, 0); /* mov %eax, xxx */ sym = external_global_sym(TOK___bound_local_delete, &func_old_type, 0); greloc(cur_text_section, sym, ind + 1, R_386_PC32); oad(0xe8, -4); o(0x585a); /* restore returned value, if any */ } #endif o(0xc9); /* leave */ if (func_ret_sub == 0) { o(0xc3); /* ret */ } else { o(0xc2); /* ret n */ g(func_ret_sub); g(func_ret_sub >> 8); } /* align local size to word & save local variables */ v = (-loc + 3) & -4; saved_ind = ind; ind = func_sub_sp_offset - FUNC_PROLOG_SIZE; #ifdef TCC_TARGET_PE if (v >= 4096) { Sym *sym = external_global_sym(TOK___chkstk, &func_old_type, 0); oad(0xb8, v); /* mov stacksize, %eax */ oad(0xe8, -4); /* call __chkstk, (does the stackframe too) */ greloc(cur_text_section, sym, ind-4, R_386_PC32); } else #endif { o(0xe58955); /* push %ebp, mov %esp, %ebp */ o(0xec81); /* sub esp, stacksize */ gen_le32(v); #if FUNC_PROLOG_SIZE == 10 o(0x90); /* adjust to FUNC_PROLOG_SIZE */ #endif } ind = saved_ind; }