Rev 9284 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
145 | halyavin | 1 | /* |
6429 | siemargl | 2 | * TCCPE.C - PE file output for the Tiny C Compiler |
145 | halyavin | 3 | * |
6429 | siemargl | 4 | * Copyright (c) 2005-2007 grischka |
5 | * |
||
145 | halyavin | 6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
||
8 | * License as published by the Free Software Foundation; either |
||
9 | * version 2 of the License, or (at your option) any later version. |
||
10 | * |
||
11 | * This library is distributed in the hope that it will be useful, |
||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
14 | * Lesser General Public License for more details. |
||
15 | * |
||
16 | * You should have received a copy of the GNU Lesser General Public |
||
17 | * License along with this library; if not, write to the Free Software |
||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
19 | */ |
||
20 | |||
6429 | siemargl | 21 | #include "tcc.h" |
145 | halyavin | 22 | |
6429 | siemargl | 23 | #ifndef _WIN32 |
24 | #define stricmp strcasecmp |
||
25 | #define strnicmp strncasecmp |
||
26 | #endif |
||
145 | halyavin | 27 | |
6429 | siemargl | 28 | #ifndef MAX_PATH |
29 | #define MAX_PATH 260 |
||
30 | #endif |
||
31 | |||
32 | #define PE_MERGE_DATA |
||
33 | /* #define PE_PRINT_SECTIONS */ |
||
34 | |||
35 | #ifdef TCC_TARGET_X86_64 |
||
36 | # define ADDR3264 ULONGLONG |
||
37 | # define REL_TYPE_DIRECT R_X86_64_64 |
||
38 | # define R_XXX_THUNKFIX R_X86_64_PC32 |
||
39 | # define R_XXX_RELATIVE R_X86_64_RELATIVE |
||
40 | # define IMAGE_FILE_MACHINE 0x8664 |
||
41 | # define RSRC_RELTYPE 3 |
||
42 | |||
43 | #elif defined TCC_TARGET_ARM |
||
44 | # define ADDR3264 DWORD |
||
45 | # define REL_TYPE_DIRECT R_ARM_ABS32 |
||
46 | # define R_XXX_THUNKFIX R_ARM_ABS32 |
||
47 | # define R_XXX_RELATIVE R_ARM_RELATIVE |
||
48 | # define IMAGE_FILE_MACHINE 0x01C0 |
||
49 | # define RSRC_RELTYPE 7 /* ??? (not tested) */ |
||
50 | |||
51 | #elif defined TCC_TARGET_I386 |
||
52 | # define ADDR3264 DWORD |
||
53 | # define REL_TYPE_DIRECT R_386_32 |
||
54 | # define R_XXX_THUNKFIX R_386_32 |
||
55 | # define R_XXX_RELATIVE R_386_RELATIVE |
||
56 | # define IMAGE_FILE_MACHINE 0x014C |
||
57 | # define RSRC_RELTYPE 7 /* DIR32NB */ |
||
58 | |||
59 | #endif |
||
60 | |||
61 | #ifdef _WIN32 |
||
62 | void dbg_printf (const char *fmt, ...) |
||
63 | { |
||
64 | char buffer[4000]; |
||
65 | va_list arg; |
||
66 | int x; |
||
67 | va_start(arg, fmt); |
||
68 | x = vsprintf (buffer, fmt, arg); |
||
69 | strcpy(buffer+x, "\n"); |
||
70 | OutputDebugString(buffer); |
||
71 | } |
||
72 | #endif |
||
73 | |||
74 | /* ----------------------------------------------------------- */ |
||
75 | #ifndef IMAGE_NT_SIGNATURE |
||
76 | /* ----------------------------------------------------------- */ |
||
145 | halyavin | 77 | /* definitions below are from winnt.h */ |
78 | |||
6429 | siemargl | 79 | typedef unsigned char BYTE; |
80 | typedef unsigned short WORD; |
||
81 | typedef unsigned int DWORD; |
||
82 | typedef unsigned long long ULONGLONG; |
||
83 | #pragma pack(push, 1) |
||
145 | halyavin | 84 | |
6429 | siemargl | 85 | typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ |
86 | WORD e_magic; /* Magic number */ |
||
87 | WORD e_cblp; /* Bytes on last page of file */ |
||
88 | WORD e_cp; /* Pages in file */ |
||
89 | WORD e_crlc; /* Relocations */ |
||
90 | WORD e_cparhdr; /* Size of header in paragraphs */ |
||
91 | WORD e_minalloc; /* Minimum extra paragraphs needed */ |
||
92 | WORD e_maxalloc; /* Maximum extra paragraphs needed */ |
||
93 | WORD e_ss; /* Initial (relative) SS value */ |
||
94 | WORD e_sp; /* Initial SP value */ |
||
95 | WORD e_csum; /* Checksum */ |
||
96 | WORD e_ip; /* Initial IP value */ |
||
97 | WORD e_cs; /* Initial (relative) CS value */ |
||
98 | WORD e_lfarlc; /* File address of relocation table */ |
||
99 | WORD e_ovno; /* Overlay number */ |
||
100 | WORD e_res[4]; /* Reserved words */ |
||
101 | WORD e_oemid; /* OEM identifier (for e_oeminfo) */ |
||
102 | WORD e_oeminfo; /* OEM information; e_oemid specific */ |
||
103 | WORD e_res2[10]; /* Reserved words */ |
||
104 | DWORD e_lfanew; /* File address of new exe header */ |
||
145 | halyavin | 105 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; |
106 | |||
6429 | siemargl | 107 | #define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ |
145 | halyavin | 108 | #define SIZE_OF_NT_SIGNATURE 4 |
109 | |||
110 | typedef struct _IMAGE_FILE_HEADER { |
||
6429 | siemargl | 111 | WORD Machine; |
112 | WORD NumberOfSections; |
||
113 | DWORD TimeDateStamp; |
||
114 | DWORD PointerToSymbolTable; |
||
115 | DWORD NumberOfSymbols; |
||
116 | WORD SizeOfOptionalHeader; |
||
117 | WORD Characteristics; |
||
145 | halyavin | 118 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; |
119 | |||
120 | |||
121 | #define IMAGE_SIZEOF_FILE_HEADER 20 |
||
122 | |||
123 | typedef struct _IMAGE_DATA_DIRECTORY { |
||
6429 | siemargl | 124 | DWORD VirtualAddress; |
125 | DWORD Size; |
||
145 | halyavin | 126 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; |
127 | |||
128 | |||
129 | typedef struct _IMAGE_OPTIONAL_HEADER { |
||
130 | /* Standard fields. */ |
||
6429 | siemargl | 131 | WORD Magic; |
132 | BYTE MajorLinkerVersion; |
||
133 | BYTE MinorLinkerVersion; |
||
134 | DWORD SizeOfCode; |
||
135 | DWORD SizeOfInitializedData; |
||
136 | DWORD SizeOfUninitializedData; |
||
137 | DWORD AddressOfEntryPoint; |
||
138 | DWORD BaseOfCode; |
||
139 | #ifndef TCC_TARGET_X86_64 |
||
140 | DWORD BaseOfData; |
||
141 | #endif |
||
145 | halyavin | 142 | /* NT additional fields. */ |
6429 | siemargl | 143 | ADDR3264 ImageBase; |
144 | DWORD SectionAlignment; |
||
145 | DWORD FileAlignment; |
||
146 | WORD MajorOperatingSystemVersion; |
||
147 | WORD MinorOperatingSystemVersion; |
||
148 | WORD MajorImageVersion; |
||
149 | WORD MinorImageVersion; |
||
150 | WORD MajorSubsystemVersion; |
||
151 | WORD MinorSubsystemVersion; |
||
152 | DWORD Win32VersionValue; |
||
153 | DWORD SizeOfImage; |
||
154 | DWORD SizeOfHeaders; |
||
155 | DWORD CheckSum; |
||
156 | WORD Subsystem; |
||
157 | WORD DllCharacteristics; |
||
158 | ADDR3264 SizeOfStackReserve; |
||
159 | ADDR3264 SizeOfStackCommit; |
||
160 | ADDR3264 SizeOfHeapReserve; |
||
161 | ADDR3264 SizeOfHeapCommit; |
||
162 | DWORD LoaderFlags; |
||
163 | DWORD NumberOfRvaAndSizes; |
||
145 | halyavin | 164 | IMAGE_DATA_DIRECTORY DataDirectory[16]; |
6429 | siemargl | 165 | } IMAGE_OPTIONAL_HEADER32, IMAGE_OPTIONAL_HEADER64, IMAGE_OPTIONAL_HEADER; |
145 | halyavin | 166 | |
6429 | siemargl | 167 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ |
168 | #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ |
||
169 | #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ |
||
170 | #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ |
||
171 | #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ |
||
172 | #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ |
||
173 | #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ |
||
145 | halyavin | 174 | /* IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) */ |
6429 | siemargl | 175 | #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 /* Architecture Specific Data */ |
176 | #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* RVA of GP */ |
||
177 | #define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ |
||
178 | #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ |
||
179 | #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ |
||
180 | #define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ |
||
181 | #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 /* Delay Load Import Descriptors */ |
||
182 | #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 /* COM Runtime descriptor */ |
||
145 | halyavin | 183 | |
184 | /* Section header format. */ |
||
6429 | siemargl | 185 | #define IMAGE_SIZEOF_SHORT_NAME 8 |
145 | halyavin | 186 | |
187 | typedef struct _IMAGE_SECTION_HEADER { |
||
6429 | siemargl | 188 | BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; |
145 | halyavin | 189 | union { |
6429 | siemargl | 190 | DWORD PhysicalAddress; |
191 | DWORD VirtualSize; |
||
145 | halyavin | 192 | } Misc; |
6429 | siemargl | 193 | DWORD VirtualAddress; |
194 | DWORD SizeOfRawData; |
||
195 | DWORD PointerToRawData; |
||
196 | DWORD PointerToRelocations; |
||
197 | DWORD PointerToLinenumbers; |
||
198 | WORD NumberOfRelocations; |
||
199 | WORD NumberOfLinenumbers; |
||
200 | DWORD Characteristics; |
||
145 | halyavin | 201 | } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; |
202 | |||
6429 | siemargl | 203 | #define IMAGE_SIZEOF_SECTION_HEADER 40 |
145 | halyavin | 204 | |
6429 | siemargl | 205 | typedef struct _IMAGE_EXPORT_DIRECTORY { |
206 | DWORD Characteristics; |
||
207 | DWORD TimeDateStamp; |
||
208 | WORD MajorVersion; |
||
209 | WORD MinorVersion; |
||
210 | DWORD Name; |
||
211 | DWORD Base; |
||
212 | DWORD NumberOfFunctions; |
||
213 | DWORD NumberOfNames; |
||
214 | DWORD AddressOfFunctions; |
||
215 | DWORD AddressOfNames; |
||
216 | DWORD AddressOfNameOrdinals; |
||
217 | } IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; |
||
218 | |||
219 | typedef struct _IMAGE_IMPORT_DESCRIPTOR { |
||
220 | union { |
||
221 | DWORD Characteristics; |
||
222 | DWORD OriginalFirstThunk; |
||
223 | }; |
||
224 | DWORD TimeDateStamp; |
||
225 | DWORD ForwarderChain; |
||
226 | DWORD Name; |
||
227 | DWORD FirstThunk; |
||
228 | } IMAGE_IMPORT_DESCRIPTOR; |
||
229 | |||
145 | halyavin | 230 | typedef struct _IMAGE_BASE_RELOCATION { |
6429 | siemargl | 231 | DWORD VirtualAddress; |
232 | DWORD SizeOfBlock; |
||
145 | halyavin | 233 | // WORD TypeOffset[1]; |
234 | } IMAGE_BASE_RELOCATION; |
||
235 | |||
6429 | siemargl | 236 | #define IMAGE_SIZEOF_BASE_RELOCATION 8 |
145 | halyavin | 237 | |
6429 | siemargl | 238 | #define IMAGE_REL_BASED_ABSOLUTE 0 |
239 | #define IMAGE_REL_BASED_HIGH 1 |
||
240 | #define IMAGE_REL_BASED_LOW 2 |
||
241 | #define IMAGE_REL_BASED_HIGHLOW 3 |
||
242 | #define IMAGE_REL_BASED_HIGHADJ 4 |
||
243 | #define IMAGE_REL_BASED_MIPS_JMPADDR 5 |
||
244 | #define IMAGE_REL_BASED_SECTION 6 |
||
245 | #define IMAGE_REL_BASED_REL32 7 |
||
145 | halyavin | 246 | |
6429 | siemargl | 247 | #pragma pack(pop) |
145 | halyavin | 248 | |
249 | /* ----------------------------------------------------------- */ |
||
6429 | siemargl | 250 | #endif /* ndef IMAGE_NT_SIGNATURE */ |
251 | /* ----------------------------------------------------------- */ |
||
252 | #pragma pack(push, 1) |
||
145 | halyavin | 253 | |
6429 | siemargl | 254 | struct pe_header |
255 | { |
||
256 | IMAGE_DOS_HEADER doshdr; |
||
257 | BYTE dosstub[0x40]; |
||
258 | DWORD nt_sig; |
||
259 | IMAGE_FILE_HEADER filehdr; |
||
260 | #ifdef TCC_TARGET_X86_64 |
||
261 | IMAGE_OPTIONAL_HEADER64 opthdr; |
||
262 | #else |
||
263 | #ifdef _WIN64 |
||
264 | IMAGE_OPTIONAL_HEADER32 opthdr; |
||
265 | #else |
||
266 | IMAGE_OPTIONAL_HEADER opthdr; |
||
267 | #endif |
||
268 | #endif |
||
145 | halyavin | 269 | }; |
270 | |||
6429 | siemargl | 271 | struct pe_reloc_header { |
272 | DWORD offset; |
||
273 | DWORD size; |
||
145 | halyavin | 274 | }; |
275 | |||
6429 | siemargl | 276 | struct pe_rsrc_header { |
277 | struct _IMAGE_FILE_HEADER filehdr; |
||
278 | struct _IMAGE_SECTION_HEADER sectionhdr; |
||
145 | halyavin | 279 | }; |
280 | |||
6429 | siemargl | 281 | struct pe_rsrc_reloc { |
145 | halyavin | 282 | DWORD offset; |
283 | DWORD size; |
||
6429 | siemargl | 284 | WORD type; |
145 | halyavin | 285 | }; |
286 | |||
6429 | siemargl | 287 | #pragma pack(pop) |
288 | |||
145 | halyavin | 289 | /* ------------------------------------------------------------- */ |
290 | /* internal temporary structures */ |
||
291 | |||
6429 | siemargl | 292 | /* |
293 | #define IMAGE_SCN_CNT_CODE 0x00000020 |
||
294 | #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 |
||
295 | #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 |
||
296 | #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 |
||
297 | #define IMAGE_SCN_MEM_SHARED 0x10000000 |
||
298 | #define IMAGE_SCN_MEM_EXECUTE 0x20000000 |
||
299 | #define IMAGE_SCN_MEM_READ 0x40000000 |
||
300 | #define IMAGE_SCN_MEM_WRITE 0x80000000 |
||
301 | */ |
||
145 | halyavin | 302 | |
303 | enum { |
||
304 | sec_text = 0, |
||
6429 | siemargl | 305 | sec_data , |
306 | sec_bss , |
||
307 | sec_idata , |
||
308 | sec_pdata , |
||
309 | sec_other , |
||
310 | sec_rsrc , |
||
311 | sec_stab , |
||
312 | sec_reloc , |
||
313 | sec_last |
||
145 | halyavin | 314 | }; |
315 | |||
6429 | siemargl | 316 | static const DWORD pe_sec_flags[] = { |
317 | 0x60000020, /* ".text" , */ |
||
318 | 0xC0000040, /* ".data" , */ |
||
319 | 0xC0000080, /* ".bss" , */ |
||
320 | 0x40000040, /* ".idata" , */ |
||
321 | 0x40000040, /* ".pdata" , */ |
||
322 | 0xE0000060, /* < other > , */ |
||
323 | 0x40000040, /* ".rsrc" , */ |
||
324 | 0x42000802, /* ".stab" , */ |
||
325 | 0x42000040, /* ".reloc" , */ |
||
145 | halyavin | 326 | }; |
327 | |||
328 | struct section_info { |
||
6429 | siemargl | 329 | int cls, ord; |
330 | char name[32]; |
||
145 | halyavin | 331 | DWORD sh_addr; |
332 | DWORD sh_size; |
||
6429 | siemargl | 333 | DWORD sh_flags; |
145 | halyavin | 334 | unsigned char *data; |
335 | DWORD data_size; |
||
6429 | siemargl | 336 | IMAGE_SECTION_HEADER ish; |
145 | halyavin | 337 | }; |
338 | |||
339 | struct import_symbol { |
||
340 | int sym_index; |
||
6429 | siemargl | 341 | int iat_index; |
342 | int thk_offset; |
||
145 | halyavin | 343 | }; |
344 | |||
345 | struct pe_import_info { |
||
346 | int dll_index; |
||
347 | int sym_count; |
||
348 | struct import_symbol **symbols; |
||
349 | }; |
||
350 | |||
351 | struct pe_info { |
||
6429 | siemargl | 352 | TCCState *s1; |
353 | Section *reloc; |
||
354 | Section *thunk; |
||
145 | halyavin | 355 | const char *filename; |
6429 | siemargl | 356 | int type; |
145 | halyavin | 357 | DWORD sizeofheaders; |
6429 | siemargl | 358 | ADDR3264 imagebase; |
145 | halyavin | 359 | DWORD start_addr; |
360 | DWORD imp_offs; |
||
361 | DWORD imp_size; |
||
362 | DWORD iat_offs; |
||
363 | DWORD iat_size; |
||
364 | DWORD exp_offs; |
||
365 | DWORD exp_size; |
||
6429 | siemargl | 366 | int subsystem; |
367 | DWORD section_align; |
||
368 | DWORD file_align; |
||
369 | struct section_info *sec_info; |
||
145 | halyavin | 370 | int sec_count; |
371 | struct pe_import_info **imp_info; |
||
372 | int imp_count; |
||
373 | }; |
||
374 | |||
375 | #define PE_NUL 0 |
||
376 | #define PE_DLL 1 |
||
377 | #define PE_GUI 2 |
||
378 | #define PE_EXE 3 |
||
6429 | siemargl | 379 | #define PE_RUN 4 |
145 | halyavin | 380 | |
6429 | siemargl | 381 | /* --------------------------------------------*/ |
382 | |||
383 | static const char *pe_export_name(TCCState *s1, ElfW(Sym) *sym) |
||
145 | halyavin | 384 | { |
6429 | siemargl | 385 | const char *name = symtab_section->link->data + sym->st_name; |
386 | if (s1->leading_underscore && name[0] == '_' && !(sym->st_other & ST_PE_STDCALL)) |
||
387 | return name + 1; |
||
388 | return name; |
||
145 | halyavin | 389 | } |
390 | |||
6429 | siemargl | 391 | static int pe_find_import(TCCState * s1, ElfW(Sym) *sym) |
145 | halyavin | 392 | { |
6429 | siemargl | 393 | char buffer[200]; |
394 | const char *s, *p; |
||
395 | int sym_index = 0, n = 0; |
||
145 | halyavin | 396 | |
6429 | siemargl | 397 | do { |
398 | s = pe_export_name(s1, sym); |
||
399 | if (n) { |
||
400 | /* second try: */ |
||
401 | if (sym->st_other & ST_PE_STDCALL) { |
||
402 | /* try w/0 stdcall deco (windows API convention) */ |
||
403 | p = strrchr(s, '@'); |
||
404 | if (!p || s[0] != '_') |
||
405 | break; |
||
406 | strcpy(buffer, s+1)[p-s-1] = 0; |
||
407 | } else if (s[0] != '_') { /* try non-ansi function */ |
||
408 | buffer[0] = '_', strcpy(buffer + 1, s); |
||
409 | } else if (0 == memcmp(s, "__imp__", 7)) { /* mingw 2.0 */ |
||
410 | strcpy(buffer, s + 6); |
||
411 | } else if (0 == memcmp(s, "_imp___", 7)) { /* mingw 3.7 */ |
||
412 | strcpy(buffer, s + 6); |
||
413 | } else { |
||
414 | break; |
||
415 | } |
||
416 | s = buffer; |
||
145 | halyavin | 417 | } |
6429 | siemargl | 418 | sym_index = find_elf_sym(s1->dynsymtab_section, s); |
419 | // printf("find (%d) %d %s\n", n, sym_index, s); |
||
420 | } while (0 == sym_index && ++n < 2); |
||
421 | return sym_index; |
||
145 | halyavin | 422 | } |
423 | |||
424 | /*----------------------------------------------------------------------------*/ |
||
425 | |||
6429 | siemargl | 426 | static int dynarray_assoc(void **pp, int n, int key) |
145 | halyavin | 427 | { |
428 | int i; |
||
429 | for (i = 0; i < n; ++i, ++pp) |
||
6429 | siemargl | 430 | if (key == **(int **) pp) |
431 | return i; |
||
145 | halyavin | 432 | return -1; |
433 | } |
||
434 | |||
435 | #if 0 |
||
6429 | siemargl | 436 | ST_FN DWORD umin(DWORD a, DWORD b) |
145 | halyavin | 437 | { |
438 | return a < b ? a : b; |
||
439 | } |
||
440 | #endif |
||
441 | |||
6429 | siemargl | 442 | static DWORD umax(DWORD a, DWORD b) |
145 | halyavin | 443 | { |
444 | return a < b ? b : a; |
||
445 | } |
||
446 | |||
6429 | siemargl | 447 | static DWORD pe_file_align(struct pe_info *pe, DWORD n) |
145 | halyavin | 448 | { |
6429 | siemargl | 449 | return (n + (pe->file_align - 1)) & ~(pe->file_align - 1); |
145 | halyavin | 450 | } |
451 | |||
6429 | siemargl | 452 | static DWORD pe_virtual_align(struct pe_info *pe, DWORD n) |
145 | halyavin | 453 | { |
6429 | siemargl | 454 | return (n + (pe->section_align - 1)) & ~(pe->section_align - 1); |
145 | halyavin | 455 | } |
456 | |||
6429 | siemargl | 457 | static void pe_align_section(Section *s, int a) |
145 | halyavin | 458 | { |
6429 | siemargl | 459 | int i = s->data_offset & (a-1); |
460 | if (i) |
||
461 | section_ptr_add(s, a - i); |
||
145 | halyavin | 462 | } |
463 | |||
6429 | siemargl | 464 | static void pe_set_datadir(struct pe_header *hdr, int dir, DWORD addr, DWORD size) |
145 | halyavin | 465 | { |
6429 | siemargl | 466 | hdr->opthdr.DataDirectory[dir].VirtualAddress = addr; |
467 | hdr->opthdr.DataDirectory[dir].Size = size; |
||
145 | halyavin | 468 | } |
469 | |||
6429 | siemargl | 470 | static int pe_fwrite(void *data, unsigned len, FILE *fp, DWORD *psum) |
471 | { |
||
472 | if (psum) { |
||
473 | DWORD sum = *psum; |
||
474 | WORD *p = data; |
||
475 | int i; |
||
476 | for (i = len; i > 0; i -= 2) { |
||
477 | sum += (i >= 2) ? *p++ : *(BYTE*)p; |
||
478 | sum = (sum + (sum >> 16)) & 0xFFFF; |
||
479 | } |
||
480 | *psum = sum; |
||
481 | } |
||
482 | return len == fwrite(data, 1, len, fp) ? 0 : -1; |
||
483 | } |
||
145 | halyavin | 484 | |
6429 | siemargl | 485 | static void pe_fpad(FILE *fp, DWORD new_pos) |
486 | { |
||
487 | DWORD pos = ftell(fp); |
||
488 | while (++pos <= new_pos) |
||
489 | fputc(0, fp); |
||
490 | } |
||
491 | |||
145 | halyavin | 492 | /*----------------------------------------------------------------------------*/ |
6429 | siemargl | 493 | static int pe_write(struct pe_info *pe) |
145 | halyavin | 494 | { |
6429 | siemargl | 495 | static const struct pe_header pe_template = { |
496 | { |
||
497 | /* IMAGE_DOS_HEADER doshdr */ |
||
498 | 0x5A4D, /*WORD e_magic; Magic number */ |
||
499 | 0x0090, /*WORD e_cblp; Bytes on last page of file */ |
||
500 | 0x0003, /*WORD e_cp; Pages in file */ |
||
501 | 0x0000, /*WORD e_crlc; Relocations */ |
||
502 | |||
503 | 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ |
||
504 | 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ |
||
505 | 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ |
||
506 | 0x0000, /*WORD e_ss; Initial (relative) SS value */ |
||
507 | |||
508 | 0x00B8, /*WORD e_sp; Initial SP value */ |
||
509 | 0x0000, /*WORD e_csum; Checksum */ |
||
510 | 0x0000, /*WORD e_ip; Initial IP value */ |
||
511 | 0x0000, /*WORD e_cs; Initial (relative) CS value */ |
||
512 | 0x0040, /*WORD e_lfarlc; File address of relocation table */ |
||
513 | 0x0000, /*WORD e_ovno; Overlay number */ |
||
514 | {0,0,0,0}, /*WORD e_res[4]; Reserved words */ |
||
515 | 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ |
||
516 | 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ |
||
517 | {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10]; Reserved words */ |
||
518 | 0x00000080 /*DWORD e_lfanew; File address of new exe header */ |
||
519 | },{ |
||
520 | /* BYTE dosstub[0x40] */ |
||
521 | /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ |
||
522 | 0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68, |
||
523 | 0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f, |
||
524 | 0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20, |
||
525 | 0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
||
526 | }, |
||
527 | 0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */ |
||
528 | { |
||
529 | /* IMAGE_FILE_HEADER filehdr */ |
||
530 | IMAGE_FILE_MACHINE, /*WORD Machine; */ |
||
531 | 0x0003, /*WORD NumberOfSections; */ |
||
532 | 0x00000000, /*DWORD TimeDateStamp; */ |
||
533 | 0x00000000, /*DWORD PointerToSymbolTable; */ |
||
534 | 0x00000000, /*DWORD NumberOfSymbols; */ |
||
535 | #if defined(TCC_TARGET_X86_64) |
||
536 | 0x00F0, /*WORD SizeOfOptionalHeader; */ |
||
537 | 0x022F /*WORD Characteristics; */ |
||
538 | #define CHARACTERISTICS_DLL 0x222E |
||
539 | #elif defined(TCC_TARGET_I386) |
||
540 | 0x00E0, /*WORD SizeOfOptionalHeader; */ |
||
541 | 0x030F /*WORD Characteristics; */ |
||
542 | #define CHARACTERISTICS_DLL 0x230E |
||
543 | #elif defined(TCC_TARGET_ARM) |
||
544 | 0x00E0, /*WORD SizeOfOptionalHeader; */ |
||
545 | 0x010F, /*WORD Characteristics; */ |
||
546 | #define CHARACTERISTICS_DLL 0x230F |
||
547 | #endif |
||
548 | },{ |
||
549 | /* IMAGE_OPTIONAL_HEADER opthdr */ |
||
550 | /* Standard fields. */ |
||
551 | #ifdef TCC_TARGET_X86_64 |
||
552 | 0x020B, /*WORD Magic; */ |
||
553 | #else |
||
554 | 0x010B, /*WORD Magic; */ |
||
555 | #endif |
||
556 | 0x06, /*BYTE MajorLinkerVersion; */ |
||
557 | 0x00, /*BYTE MinorLinkerVersion; */ |
||
558 | 0x00000000, /*DWORD SizeOfCode; */ |
||
559 | 0x00000000, /*DWORD SizeOfInitializedData; */ |
||
560 | 0x00000000, /*DWORD SizeOfUninitializedData; */ |
||
561 | 0x00000000, /*DWORD AddressOfEntryPoint; */ |
||
562 | 0x00000000, /*DWORD BaseOfCode; */ |
||
563 | #ifndef TCC_TARGET_X86_64 |
||
564 | 0x00000000, /*DWORD BaseOfData; */ |
||
565 | #endif |
||
566 | /* NT additional fields. */ |
||
567 | #if defined(TCC_TARGET_ARM) |
||
568 | 0x00100000, /*DWORD ImageBase; */ |
||
569 | #else |
||
570 | 0x00400000, /*DWORD ImageBase; */ |
||
571 | #endif |
||
572 | 0x00001000, /*DWORD SectionAlignment; */ |
||
573 | 0x00000200, /*DWORD FileAlignment; */ |
||
574 | 0x0004, /*WORD MajorOperatingSystemVersion; */ |
||
575 | 0x0000, /*WORD MinorOperatingSystemVersion; */ |
||
576 | 0x0000, /*WORD MajorImageVersion; */ |
||
577 | 0x0000, /*WORD MinorImageVersion; */ |
||
578 | 0x0004, /*WORD MajorSubsystemVersion; */ |
||
579 | 0x0000, /*WORD MinorSubsystemVersion; */ |
||
580 | 0x00000000, /*DWORD Win32VersionValue; */ |
||
581 | 0x00000000, /*DWORD SizeOfImage; */ |
||
582 | 0x00000200, /*DWORD SizeOfHeaders; */ |
||
583 | 0x00000000, /*DWORD CheckSum; */ |
||
584 | 0x0002, /*WORD Subsystem; */ |
||
585 | 0x0000, /*WORD DllCharacteristics; */ |
||
586 | 0x00100000, /*DWORD SizeOfStackReserve; */ |
||
587 | 0x00001000, /*DWORD SizeOfStackCommit; */ |
||
588 | 0x00100000, /*DWORD SizeOfHeapReserve; */ |
||
589 | 0x00001000, /*DWORD SizeOfHeapCommit; */ |
||
590 | 0x00000000, /*DWORD LoaderFlags; */ |
||
591 | 0x00000010, /*DWORD NumberOfRvaAndSizes; */ |
||
592 | |||
593 | /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ |
||
594 | {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, |
||
595 | {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}} |
||
596 | }}; |
||
597 | |||
598 | struct pe_header pe_header = pe_template; |
||
599 | |||
145 | halyavin | 600 | int i; |
601 | FILE *op; |
||
6429 | siemargl | 602 | DWORD file_offset, sum; |
603 | struct section_info *si; |
||
604 | IMAGE_SECTION_HEADER *psh; |
||
145 | halyavin | 605 | |
606 | op = fopen(pe->filename, "wb"); |
||
607 | if (NULL == op) { |
||
6429 | siemargl | 608 | tcc_error_noabort("could not write '%s': %s", pe->filename, strerror(errno)); |
609 | return -1; |
||
145 | halyavin | 610 | } |
611 | |||
6429 | siemargl | 612 | pe->sizeofheaders = pe_file_align(pe, |
613 | sizeof (struct pe_header) |
||
614 | + pe->sec_count * sizeof (IMAGE_SECTION_HEADER) |
||
615 | ); |
||
145 | halyavin | 616 | |
617 | file_offset = pe->sizeofheaders; |
||
618 | |||
6429 | siemargl | 619 | if (2 == pe->s1->verbose) |
620 | printf("-------------------------------" |
||
621 | "\n virt file size section" "\n"); |
||
145 | halyavin | 622 | for (i = 0; i < pe->sec_count; ++i) { |
6429 | siemargl | 623 | DWORD addr, size; |
624 | const char *sh_name; |
||
145 | halyavin | 625 | |
6429 | siemargl | 626 | si = pe->sec_info + i; |
627 | sh_name = si->name; |
||
628 | addr = si->sh_addr - pe->imagebase; |
||
629 | size = si->sh_size; |
||
630 | psh = &si->ish; |
||
145 | halyavin | 631 | |
6429 | siemargl | 632 | if (2 == pe->s1->verbose) |
633 | printf("%6x %6x %6x %s\n", |
||
634 | (unsigned)addr, (unsigned)file_offset, (unsigned)size, sh_name); |
||
145 | halyavin | 635 | |
6429 | siemargl | 636 | switch (si->cls) { |
637 | case sec_text: |
||
638 | pe_header.opthdr.BaseOfCode = addr; |
||
639 | pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr; |
||
640 | break; |
||
145 | halyavin | 641 | |
6429 | siemargl | 642 | case sec_data: |
643 | #ifndef TCC_TARGET_X86_64 |
||
644 | pe_header.opthdr.BaseOfData = addr; |
||
645 | #endif |
||
646 | break; |
||
145 | halyavin | 647 | |
6429 | siemargl | 648 | case sec_bss: |
649 | break; |
||
145 | halyavin | 650 | |
6429 | siemargl | 651 | case sec_reloc: |
652 | pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); |
||
653 | break; |
||
145 | halyavin | 654 | |
6429 | siemargl | 655 | case sec_rsrc: |
656 | pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); |
||
657 | break; |
||
145 | halyavin | 658 | |
6429 | siemargl | 659 | case sec_pdata: |
660 | pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXCEPTION, addr, size); |
||
661 | break; |
||
145 | halyavin | 662 | |
6429 | siemargl | 663 | case sec_stab: |
664 | break; |
||
665 | } |
||
145 | halyavin | 666 | |
6429 | siemargl | 667 | if (pe->thunk == pe->s1->sections[si->ord]) { |
668 | if (pe->imp_size) { |
||
669 | pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IMPORT, |
||
670 | pe->imp_offs + addr, pe->imp_size); |
||
671 | pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_IAT, |
||
672 | pe->iat_offs + addr, pe->iat_size); |
||
673 | } |
||
674 | if (pe->exp_size) { |
||
675 | pe_set_datadir(&pe_header, IMAGE_DIRECTORY_ENTRY_EXPORT, |
||
676 | pe->exp_offs + addr, pe->exp_size); |
||
677 | } |
||
678 | } |
||
145 | halyavin | 679 | |
6429 | siemargl | 680 | strncpy((char*)psh->Name, sh_name, sizeof psh->Name); |
681 | |||
682 | psh->Characteristics = pe_sec_flags[si->cls]; |
||
683 | psh->VirtualAddress = addr; |
||
684 | psh->Misc.VirtualSize = size; |
||
685 | pe_header.opthdr.SizeOfImage = |
||
686 | umax(pe_virtual_align(pe, size + addr), pe_header.opthdr.SizeOfImage); |
||
687 | |||
688 | if (si->data_size) { |
||
689 | psh->PointerToRawData = file_offset; |
||
690 | file_offset = pe_file_align(pe, file_offset + si->data_size); |
||
691 | psh->SizeOfRawData = file_offset - psh->PointerToRawData; |
||
692 | } |
||
145 | halyavin | 693 | } |
694 | |||
6429 | siemargl | 695 | //pe_header.filehdr.TimeDateStamp = time(NULL); |
696 | pe_header.filehdr.NumberOfSections = pe->sec_count; |
||
697 | pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders; |
||
698 | pe_header.opthdr.ImageBase = pe->imagebase; |
||
699 | pe_header.opthdr.Subsystem = pe->subsystem; |
||
700 | if (pe->s1->pe_stack_size) |
||
701 | pe_header.opthdr.SizeOfStackReserve = pe->s1->pe_stack_size; |
||
702 | if (PE_DLL == pe->type) |
||
703 | pe_header.filehdr.Characteristics = CHARACTERISTICS_DLL; |
||
145 | halyavin | 704 | |
6429 | siemargl | 705 | sum = 0; |
706 | pe_fwrite(&pe_header, sizeof pe_header, op, &sum); |
||
707 | for (i = 0; i < pe->sec_count; ++i) |
||
708 | pe_fwrite(&pe->sec_info[i].ish, sizeof(IMAGE_SECTION_HEADER), op, &sum); |
||
709 | pe_fpad(op, pe->sizeofheaders); |
||
710 | for (i = 0; i < pe->sec_count; ++i) { |
||
711 | si = pe->sec_info + i; |
||
712 | psh = &si->ish; |
||
713 | if (si->data_size) { |
||
714 | pe_fwrite(si->data, si->data_size, op, &sum); |
||
715 | file_offset = psh->PointerToRawData + psh->SizeOfRawData; |
||
716 | pe_fpad(op, file_offset); |
||
717 | } |
||
718 | } |
||
145 | halyavin | 719 | |
6429 | siemargl | 720 | pe_header.opthdr.CheckSum = sum + file_offset; |
721 | fseek(op, offsetof(struct pe_header, opthdr.CheckSum), SEEK_SET); |
||
722 | pe_fwrite(&pe_header.opthdr.CheckSum, sizeof pe_header.opthdr.CheckSum, op, NULL); |
||
723 | fclose (op); |
||
145 | halyavin | 724 | |
6429 | siemargl | 725 | if (2 == pe->s1->verbose) |
726 | printf("-------------------------------\n"); |
||
727 | if (pe->s1->verbose) |
||
728 | printf("<- %s (%u bytes)\n", pe->filename, (unsigned)file_offset); |
||
145 | halyavin | 729 | |
730 | return 0; |
||
731 | } |
||
732 | |||
733 | /*----------------------------------------------------------------------------*/ |
||
6429 | siemargl | 734 | |
735 | static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index) |
||
145 | halyavin | 736 | { |
737 | int i; |
||
738 | int dll_index; |
||
739 | struct pe_import_info *p; |
||
740 | struct import_symbol *s; |
||
6429 | siemargl | 741 | ElfW(Sym) *isym; |
145 | halyavin | 742 | |
6429 | siemargl | 743 | isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; |
744 | dll_index = isym->st_size; |
||
745 | |||
746 | i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index); |
||
145 | halyavin | 747 | if (-1 != i) { |
6429 | siemargl | 748 | p = pe->imp_info[i]; |
749 | goto found_dll; |
||
145 | halyavin | 750 | } |
751 | p = tcc_mallocz(sizeof *p); |
||
752 | p->dll_index = dll_index; |
||
6429 | siemargl | 753 | dynarray_add((void***)&pe->imp_info, &pe->imp_count, p); |
145 | halyavin | 754 | |
6429 | siemargl | 755 | found_dll: |
756 | i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index); |
||
145 | halyavin | 757 | if (-1 != i) |
6429 | siemargl | 758 | return p->symbols[i]; |
759 | |||
145 | halyavin | 760 | s = tcc_mallocz(sizeof *s); |
6429 | siemargl | 761 | dynarray_add((void***)&p->symbols, &p->sym_count, s); |
145 | halyavin | 762 | s->sym_index = sym_index; |
6429 | siemargl | 763 | return s; |
145 | halyavin | 764 | } |
765 | |||
766 | /*----------------------------------------------------------------------------*/ |
||
6429 | siemargl | 767 | static void pe_build_imports(struct pe_info *pe) |
145 | halyavin | 768 | { |
769 | int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; |
||
6429 | siemargl | 770 | DWORD rva_base = pe->thunk->sh_addr - pe->imagebase; |
145 | halyavin | 771 | int ndlls = pe->imp_count; |
772 | |||
773 | for (sym_cnt = i = 0; i < ndlls; ++i) |
||
6429 | siemargl | 774 | sym_cnt += pe->imp_info[i]->sym_count; |
145 | halyavin | 775 | |
776 | if (0 == sym_cnt) |
||
6429 | siemargl | 777 | return; |
145 | halyavin | 778 | |
779 | pe_align_section(pe->thunk, 16); |
||
780 | |||
781 | pe->imp_offs = dll_ptr = pe->thunk->data_offset; |
||
6429 | siemargl | 782 | pe->imp_size = (ndlls + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR); |
145 | halyavin | 783 | pe->iat_offs = dll_ptr + pe->imp_size; |
6429 | siemargl | 784 | pe->iat_size = (sym_cnt + ndlls) * sizeof(ADDR3264); |
785 | section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size); |
||
145 | halyavin | 786 | |
787 | thk_ptr = pe->iat_offs; |
||
788 | ent_ptr = pe->iat_offs + pe->iat_size; |
||
6429 | siemargl | 789 | |
145 | halyavin | 790 | for (i = 0; i < pe->imp_count; ++i) { |
6429 | siemargl | 791 | IMAGE_IMPORT_DESCRIPTOR *hdr; |
792 | int k, n, dllindex; |
||
793 | ADDR3264 v; |
||
794 | struct pe_import_info *p = pe->imp_info[i]; |
||
795 | const char *name; |
||
796 | DLLReference *dllref; |
||
145 | halyavin | 797 | |
6429 | siemargl | 798 | dllindex = p->dll_index; |
799 | if (dllindex) |
||
800 | name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name; |
||
801 | else |
||
802 | name = "", dllref = NULL; |
||
145 | halyavin | 803 | |
6429 | siemargl | 804 | /* put the dll name into the import header */ |
805 | v = put_elf_str(pe->thunk, name); |
||
806 | hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr); |
||
807 | hdr->FirstThunk = thk_ptr + rva_base; |
||
808 | hdr->OriginalFirstThunk = ent_ptr + rva_base; |
||
809 | hdr->Name = v + rva_base; |
||
145 | halyavin | 810 | |
6429 | siemargl | 811 | for (k = 0, n = p->sym_count; k <= n; ++k) { |
812 | if (k < n) { |
||
813 | int iat_index = p->symbols[k]->iat_index; |
||
814 | int sym_index = p->symbols[k]->sym_index; |
||
815 | ElfW(Sym) *imp_sym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; |
||
816 | ElfW(Sym) *org_sym = (ElfW(Sym) *)symtab_section->data + iat_index; |
||
817 | const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name; |
||
818 | int ordinal; |
||
145 | halyavin | 819 | |
6429 | siemargl | 820 | org_sym->st_value = thk_ptr; |
821 | org_sym->st_shndx = pe->thunk->sh_num; |
||
145 | halyavin | 822 | |
6429 | siemargl | 823 | if (dllref) |
824 | v = 0, ordinal = imp_sym->st_value; /* ordinal from pe_load_def */ |
||
825 | else |
||
826 | ordinal = 0, v = imp_sym->st_value; /* address from tcc_add_symbol() */ |
||
145 | halyavin | 827 | |
6429 | siemargl | 828 | #ifdef TCC_IS_NATIVE |
829 | if (pe->type == PE_RUN) { |
||
830 | if (dllref) { |
||
831 | if ( !dllref->handle ) |
||
832 | dllref->handle = LoadLibrary(dllref->name); |
||
833 | v = (ADDR3264)GetProcAddress(dllref->handle, ordinal?(LPCSTR)NULL+ordinal:name); |
||
834 | } |
||
835 | if (!v) |
||
836 | tcc_error_noabort("can't build symbol '%s'", name); |
||
837 | } else |
||
838 | #endif |
||
839 | if (ordinal) { |
||
840 | v = ordinal | (ADDR3264)1 << (sizeof(ADDR3264)*8 - 1); |
||
841 | } else { |
||
842 | v = pe->thunk->data_offset + rva_base; |
||
843 | section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */ |
||
844 | put_elf_str(pe->thunk, name); |
||
845 | } |
||
846 | |||
847 | } else { |
||
848 | v = 0; /* last entry is zero */ |
||
849 | } |
||
850 | |||
851 | *(ADDR3264*)(pe->thunk->data+thk_ptr) = |
||
852 | *(ADDR3264*)(pe->thunk->data+ent_ptr) = v; |
||
853 | thk_ptr += sizeof (ADDR3264); |
||
854 | ent_ptr += sizeof (ADDR3264); |
||
855 | } |
||
856 | dll_ptr += sizeof(IMAGE_IMPORT_DESCRIPTOR); |
||
857 | dynarray_reset(&p->symbols, &p->sym_count); |
||
145 | halyavin | 858 | } |
6429 | siemargl | 859 | dynarray_reset(&pe->imp_info, &pe->imp_count); |
145 | halyavin | 860 | } |
861 | |||
862 | /* ------------------------------------------------------------- */ |
||
6429 | siemargl | 863 | |
864 | struct pe_sort_sym |
||
145 | halyavin | 865 | { |
6429 | siemargl | 866 | int index; |
867 | const char *name; |
||
868 | }; |
||
869 | |||
870 | static int sym_cmp(const void *va, const void *vb) |
||
871 | { |
||
872 | const char *ca = (*(struct pe_sort_sym**)va)->name; |
||
873 | const char *cb = (*(struct pe_sort_sym**)vb)->name; |
||
145 | halyavin | 874 | return strcmp(ca, cb); |
875 | } |
||
876 | |||
6429 | siemargl | 877 | static void pe_build_exports(struct pe_info *pe) |
145 | halyavin | 878 | { |
6429 | siemargl | 879 | ElfW(Sym) *sym; |
880 | int sym_index, sym_end; |
||
881 | DWORD rva_base, func_o, name_o, ord_o, str_o; |
||
882 | IMAGE_EXPORT_DIRECTORY *hdr; |
||
883 | int sym_count, ord; |
||
884 | struct pe_sort_sym **sorted, *p; |
||
145 | halyavin | 885 | |
6429 | siemargl | 886 | FILE *op; |
887 | char buf[MAX_PATH]; |
||
888 | const char *dllname; |
||
889 | const char *name; |
||
145 | halyavin | 890 | |
6429 | siemargl | 891 | rva_base = pe->thunk->sh_addr - pe->imagebase; |
892 | sym_count = 0, sorted = NULL, op = NULL; |
||
893 | |||
894 | sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); |
||
895 | for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
||
896 | sym = (ElfW(Sym)*)symtab_section->data + sym_index; |
||
897 | name = pe_export_name(pe->s1, sym); |
||
898 | if ((sym->st_other & ST_PE_EXPORT) |
||
899 | /* export only symbols from actually written sections */ |
||
900 | && pe->s1->sections[sym->st_shndx]->sh_addr) { |
||
901 | p = tcc_malloc(sizeof *p); |
||
902 | p->index = sym_index; |
||
903 | p->name = name; |
||
904 | dynarray_add((void***)&sorted, &sym_count, p); |
||
905 | } |
||
906 | #if 0 |
||
907 | if (sym->st_other & ST_PE_EXPORT) |
||
908 | printf("export: %s\n", name); |
||
909 | if (sym->st_other & ST_PE_STDCALL) |
||
910 | printf("stdcall: %s\n", name); |
||
911 | #endif |
||
145 | halyavin | 912 | } |
913 | |||
914 | if (0 == sym_count) |
||
6429 | siemargl | 915 | return; |
145 | halyavin | 916 | |
6429 | siemargl | 917 | qsort (sorted, sym_count, sizeof *sorted, sym_cmp); |
918 | |||
145 | halyavin | 919 | pe_align_section(pe->thunk, 16); |
6429 | siemargl | 920 | dllname = tcc_basename(pe->filename); |
145 | halyavin | 921 | |
922 | pe->exp_offs = pe->thunk->data_offset; |
||
6429 | siemargl | 923 | func_o = pe->exp_offs + sizeof(IMAGE_EXPORT_DIRECTORY); |
924 | name_o = func_o + sym_count * sizeof (DWORD); |
||
925 | ord_o = name_o + sym_count * sizeof (DWORD); |
||
926 | str_o = ord_o + sym_count * sizeof(WORD); |
||
145 | halyavin | 927 | |
6429 | siemargl | 928 | hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs); |
929 | hdr->Characteristics = 0; |
||
930 | hdr->Base = 1; |
||
931 | hdr->NumberOfFunctions = sym_count; |
||
932 | hdr->NumberOfNames = sym_count; |
||
933 | hdr->AddressOfFunctions = func_o + rva_base; |
||
934 | hdr->AddressOfNames = name_o + rva_base; |
||
935 | hdr->AddressOfNameOrdinals = ord_o + rva_base; |
||
936 | hdr->Name = str_o + rva_base; |
||
937 | put_elf_str(pe->thunk, dllname); |
||
145 | halyavin | 938 | |
6429 | siemargl | 939 | #if 1 |
940 | /* automatically write exports to |
||
941 | pstrcpy(buf, sizeof buf, pe->filename); |
||
942 | strcpy(tcc_fileextension(buf), ".def"); |
||
943 | op = fopen(buf, "w"); |
||
944 | if (NULL == op) { |
||
945 | tcc_error_noabort("could not create '%s': %s", buf, strerror(errno)); |
||
946 | } else { |
||
947 | fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname); |
||
948 | if (pe->s1->verbose) |
||
949 | printf("<- %s (%d symbols)\n", buf, sym_count); |
||
950 | } |
||
951 | #endif |
||
145 | halyavin | 952 | |
953 | for (ord = 0; ord < sym_count; ++ord) |
||
954 | { |
||
6429 | siemargl | 955 | p = sorted[ord], sym_index = p->index, name = p->name; |
956 | /* insert actual address later in pe_relocate_rva */ |
||
957 | put_elf_reloc(symtab_section, pe->thunk, |
||
958 | func_o, R_XXX_RELATIVE, sym_index); |
||
959 | *(DWORD*)(pe->thunk->data + name_o) |
||
960 | = pe->thunk->data_offset + rva_base; |
||
961 | *(WORD*)(pe->thunk->data + ord_o) |
||
962 | = ord; |
||
963 | put_elf_str(pe->thunk, name); |
||
964 | func_o += sizeof (DWORD); |
||
965 | name_o += sizeof (DWORD); |
||
966 | ord_o += sizeof (WORD); |
||
967 | if (op) |
||
968 | fprintf(op, "%s\n", name); |
||
145 | halyavin | 969 | } |
970 | pe->exp_size = pe->thunk->data_offset - pe->exp_offs; |
||
6429 | siemargl | 971 | dynarray_reset(&sorted, &sym_count); |
972 | if (op) |
||
973 | fclose(op); |
||
145 | halyavin | 974 | } |
975 | |||
976 | /* ------------------------------------------------------------- */ |
||
6429 | siemargl | 977 | static void pe_build_reloc (struct pe_info *pe) |
145 | halyavin | 978 | { |
979 | DWORD offset, block_ptr, addr; |
||
980 | int count, i; |
||
6429 | siemargl | 981 | ElfW_Rel *rel, *rel_end; |
145 | halyavin | 982 | Section *s = NULL, *sr; |
6429 | siemargl | 983 | |
145 | halyavin | 984 | offset = addr = block_ptr = count = i = 0; |
985 | rel = rel_end = NULL; |
||
986 | |||
6429 | siemargl | 987 | for(;;) { |
988 | if (rel < rel_end) { |
||
989 | int type = ELFW(R_TYPE)(rel->r_info); |
||
990 | addr = rel->r_offset + s->sh_addr; |
||
991 | ++ rel; |
||
992 | if (type != REL_TYPE_DIRECT) |
||
993 | continue; |
||
994 | if (count == 0) { /* new block */ |
||
995 | block_ptr = pe->reloc->data_offset; |
||
996 | section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header)); |
||
997 | offset = addr & 0xFFFFFFFF<<12; |
||
998 | } |
||
999 | if ((addr -= offset) < (1<<12)) { /* one block spans 4k addresses */ |
||
1000 | WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD)); |
||
1001 | *wp = addr | IMAGE_REL_BASED_HIGHLOW<<12; |
||
1002 | ++count; |
||
1003 | continue; |
||
1004 | } |
||
1005 | -- rel; |
||
1006 | |||
1007 | } else if (i < pe->sec_count) { |
||
1008 | sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc; |
||
1009 | if (sr) { |
||
1010 | rel = (ElfW_Rel *)sr->data; |
||
1011 | rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
||
1012 | } |
||
1013 | continue; |
||
1014 | } |
||
1015 | |||
1016 | if (count) { |
||
1017 | /* store the last block and ready for a new one */ |
||
1018 | struct pe_reloc_header *hdr; |
||
1019 | if (count & 1) /* align for DWORDS */ |
||
1020 | section_ptr_add(pe->reloc, sizeof(WORD)), ++count; |
||
1021 | hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr); |
||
1022 | hdr -> offset = offset - pe->imagebase; |
||
1023 | hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header); |
||
1024 | count = 0; |
||
1025 | } |
||
1026 | |||
1027 | if (rel >= rel_end) |
||
1028 | break; |
||
145 | halyavin | 1029 | } |
1030 | } |
||
1031 | |||
1032 | /* ------------------------------------------------------------- */ |
||
6429 | siemargl | 1033 | static int pe_section_class(Section *s) |
145 | halyavin | 1034 | { |
6429 | siemargl | 1035 | int type, flags; |
1036 | const char *name; |
||
1037 | |||
1038 | type = s->sh_type; |
||
1039 | flags = s->sh_flags; |
||
1040 | name = s->name; |
||
1041 | if (flags & SHF_ALLOC) { |
||
1042 | if (type == SHT_PROGBITS) { |
||
1043 | if (flags & SHF_EXECINSTR) |
||
1044 | return sec_text; |
||
1045 | if (flags & SHF_WRITE) |
||
1046 | return sec_data; |
||
1047 | if (0 == strcmp(name, ".rsrc")) |
||
1048 | return sec_rsrc; |
||
1049 | if (0 == strcmp(name, ".iedat")) |
||
1050 | return sec_idata; |
||
1051 | if (0 == strcmp(name, ".pdata")) |
||
1052 | return sec_pdata; |
||
1053 | return sec_other; |
||
1054 | } else if (type == SHT_NOBITS) { |
||
1055 | if (flags & SHF_WRITE) |
||
1056 | return sec_bss; |
||
1057 | } |
||
1058 | } else { |
||
1059 | if (0 == strcmp(name, ".reloc")) |
||
1060 | return sec_reloc; |
||
1061 | if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */ |
||
1062 | return sec_stab; |
||
1063 | } |
||
1064 | return -1; |
||
1065 | } |
||
1066 | |||
1067 | static int pe_assign_addresses (struct pe_info *pe) |
||
1068 | { |
||
1069 | int i, k, o, c; |
||
145 | halyavin | 1070 | DWORD addr; |
6429 | siemargl | 1071 | int *section_order; |
1072 | struct section_info *si; |
||
1073 | Section *s; |
||
145 | halyavin | 1074 | |
6429 | siemargl | 1075 | // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC); |
1076 | |||
1077 | section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int)); |
||
1078 | for (o = k = 0 ; k < sec_last; ++k) { |
||
1079 | for (i = 1; i < pe->s1->nb_sections; ++i) { |
||
1080 | s = pe->s1->sections[i]; |
||
1081 | if (k == pe_section_class(s)) { |
||
1082 | // printf("%s %d\n", s->name, k); |
||
1083 | s->sh_addr = pe->imagebase; |
||
1084 | section_order[o++] = i; |
||
1085 | } |
||
1086 | } |
||
1087 | } |
||
1088 | |||
1089 | pe->sec_info = tcc_mallocz(o * sizeof (struct section_info)); |
||
145 | halyavin | 1090 | addr = pe->imagebase + 1; |
1091 | |||
6429 | siemargl | 1092 | for (i = 0; i < o; ++i) |
1093 | { |
||
1094 | k = section_order[i]; |
||
1095 | s = pe->s1->sections[k]; |
||
1096 | c = pe_section_class(s); |
||
1097 | si = &pe->sec_info[pe->sec_count]; |
||
145 | halyavin | 1098 | |
1099 | #ifdef PE_MERGE_DATA |
||
6429 | siemargl | 1100 | if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) { |
1101 | /* append .bss to .data */ |
||
1102 | s->sh_addr = addr = ((addr-1) | (s->sh_addralign-1)) + 1; |
||
1103 | addr += s->data_offset; |
||
1104 | si[-1].sh_size = addr - si[-1].sh_addr; |
||
1105 | continue; |
||
1106 | } |
||
145 | halyavin | 1107 | #endif |
6429 | siemargl | 1108 | if (c == sec_stab && 0 == pe->s1->do_debug) |
1109 | continue; |
||
145 | halyavin | 1110 | |
6429 | siemargl | 1111 | strcpy(si->name, s->name); |
1112 | si->cls = c; |
||
1113 | si->ord = k; |
||
1114 | si->sh_addr = s->sh_addr = addr = pe_virtual_align(pe, addr); |
||
1115 | si->sh_flags = s->sh_flags; |
||
145 | halyavin | 1116 | |
6429 | siemargl | 1117 | if (c == sec_data && NULL == pe->thunk) |
1118 | pe->thunk = s; |
||
145 | halyavin | 1119 | |
6429 | siemargl | 1120 | if (s == pe->thunk) { |
1121 | pe_build_imports(pe); |
||
1122 | pe_build_exports(pe); |
||
1123 | } |
||
1124 | |||
1125 | if (c == sec_reloc) |
||
1126 | pe_build_reloc (pe); |
||
1127 | |||
1128 | if (s->data_offset) |
||
1129 | { |
||
1130 | if (s->sh_type != SHT_NOBITS) { |
||
1131 | si->data = s->data; |
||
1132 | si->data_size = s->data_offset; |
||
1133 | } |
||
1134 | |||
1135 | addr += s->data_offset; |
||
1136 | si->sh_size = s->data_offset; |
||
1137 | ++pe->sec_count; |
||
1138 | } |
||
1139 | // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name); |
||
145 | halyavin | 1140 | } |
6429 | siemargl | 1141 | |
1142 | #if 0 |
||
1143 | for (i = 1; i < pe->s1->nb_sections; ++i) { |
||
1144 | Section *s = pe->s1->sections[i]; |
||
1145 | int type = s->sh_type; |
||
1146 | int flags = s->sh_flags; |
||
1147 | printf("section %-16s %-10s %5x %s,%s,%s\n", |
||
1148 | s->name, |
||
1149 | type == SHT_PROGBITS ? "progbits" : |
||
1150 | type == SHT_NOBITS ? "nobits" : |
||
1151 | type == SHT_SYMTAB ? "symtab" : |
||
1152 | type == SHT_STRTAB ? "strtab" : |
||
1153 | type == SHT_RELX ? "rel" : "???", |
||
1154 | s->data_offset, |
||
1155 | flags & SHF_ALLOC ? "alloc" : "", |
||
1156 | flags & SHF_WRITE ? "write" : "", |
||
1157 | flags & SHF_EXECINSTR ? "exec" : "" |
||
1158 | ); |
||
1159 | } |
||
1160 | pe->s1->verbose = 2; |
||
1161 | #endif |
||
1162 | |||
1163 | tcc_free(section_order); |
||
145 | halyavin | 1164 | return 0; |
1165 | } |
||
1166 | |||
6429 | siemargl | 1167 | /* ------------------------------------------------------------- */ |
1168 | static void pe_relocate_rva (struct pe_info *pe, Section *s) |
||
1169 | { |
||
1170 | Section *sr = s->reloc; |
||
1171 | ElfW_Rel *rel, *rel_end; |
||
1172 | rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
||
1173 | for(rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) { |
||
1174 | if (ELFW(R_TYPE)(rel->r_info) == R_XXX_RELATIVE) { |
||
1175 | int sym_index = ELFW(R_SYM)(rel->r_info); |
||
1176 | DWORD addr = s->sh_addr; |
||
1177 | if (sym_index) { |
||
1178 | ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
||
1179 | addr = sym->st_value; |
||
1180 | } |
||
1181 | // printf("reloc rva %08x %08x %s\n", (DWORD)rel->r_offset, addr, s->name); |
||
1182 | *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase; |
||
1183 | } |
||
1184 | } |
||
1185 | } |
||
1186 | |||
145 | halyavin | 1187 | /*----------------------------------------------------------------------------*/ |
6429 | siemargl | 1188 | |
1189 | static int pe_isafunc(int sym_index) |
||
145 | halyavin | 1190 | { |
6429 | siemargl | 1191 | Section *sr = text_section->reloc; |
1192 | ElfW_Rel *rel, *rel_end; |
||
1193 | Elf32_Word info = ELF32_R_INFO(sym_index, R_386_PC32); |
||
1194 | if (!sr) |
||
1195 | return 0; |
||
1196 | rel_end = (ElfW_Rel *)(sr->data + sr->data_offset); |
||
1197 | for (rel = (ElfW_Rel *)sr->data; rel < rel_end; rel++) |
||
1198 | if (rel->r_info == info) |
||
1199 | return 1; |
||
1200 | return 0; |
||
1201 | } |
||
1202 | |||
1203 | /*----------------------------------------------------------------------------*/ |
||
1204 | static int pe_check_symbols(struct pe_info *pe) |
||
1205 | { |
||
1206 | ElfW(Sym) *sym; |
||
1207 | int sym_index, sym_end; |
||
145 | halyavin | 1208 | int ret = 0; |
1209 | |||
1210 | pe_align_section(text_section, 8); |
||
1211 | |||
6429 | siemargl | 1212 | sym_end = symtab_section->data_offset / sizeof(ElfW(Sym)); |
1213 | for (sym_index = 1; sym_index < sym_end; ++sym_index) { |
||
1214 | |||
1215 | sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
||
1216 | if (sym->st_shndx == SHN_UNDEF) { |
||
1217 | |||
1218 | const char *name = symtab_section->link->data + sym->st_name; |
||
1219 | unsigned type = ELFW(ST_TYPE)(sym->st_info); |
||
1220 | int imp_sym = pe_find_import(pe->s1, sym); |
||
1221 | struct import_symbol *is; |
||
1222 | |||
1223 | if (0 == imp_sym) |
||
1224 | goto not_found; |
||
1225 | |||
1226 | if (type == STT_NOTYPE) { |
||
1227 | /* symbols from assembler have no type, find out which */ |
||
1228 | if (pe_isafunc(sym_index)) |
||
1229 | type = STT_FUNC; |
||
1230 | else |
||
1231 | type = STT_OBJECT; |
||
1232 | } |
||
1233 | |||
1234 | is = pe_add_import(pe, imp_sym); |
||
1235 | |||
1236 | if (type == STT_FUNC) { |
||
1237 | unsigned long offset = is->thk_offset; |
||
1238 | if (offset) { |
||
1239 | /* got aliased symbol, like stricmp and _stricmp */ |
||
1240 | |||
1241 | } else { |
||
1242 | char buffer[100]; |
||
1243 | WORD *p; |
||
1244 | |||
1245 | offset = text_section->data_offset; |
||
1246 | /* add the 'jmp IAT[x]' instruction */ |
||
1247 | #ifdef TCC_TARGET_ARM |
||
1248 | p = section_ptr_add(text_section, 8+4); // room for code and address |
||
1249 | (*(DWORD*)(p)) = 0xE59FC000; // arm code ldr ip, [pc] ; PC+8+0 = 0001xxxx |
||
1250 | (*(DWORD*)(p+2)) = 0xE59CF000; // arm code ldr pc, [ip] |
||
1251 | #else |
||
1252 | p = section_ptr_add(text_section, 8); |
||
1253 | *p = 0x25FF; |
||
1254 | #ifdef TCC_TARGET_X86_64 |
||
1255 | *(DWORD*)(p+1) = (DWORD)-4; |
||
1256 | #endif |
||
1257 | #endif |
||
1258 | /* add a helper symbol, will be patched later in |
||
1259 | pe_build_imports */ |
||
1260 | sprintf(buffer, "IAT.%s", name); |
||
1261 | is->iat_index = put_elf_sym( |
||
1262 | symtab_section, 0, sizeof(DWORD), |
||
1263 | ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), |
||
1264 | 0, SHN_UNDEF, buffer); |
||
1265 | #ifdef TCC_TARGET_ARM |
||
1266 | put_elf_reloc(symtab_section, text_section, |
||
1267 | offset + 8, R_XXX_THUNKFIX, is->iat_index); // offset to IAT position |
||
1268 | #else |
||
1269 | put_elf_reloc(symtab_section, text_section, |
||
1270 | offset + 2, R_XXX_THUNKFIX, is->iat_index); |
||
1271 | #endif |
||
1272 | is->thk_offset = offset; |
||
1273 | } |
||
1274 | |||
1275 | /* tcc_realloc might have altered sym's address */ |
||
1276 | sym = (ElfW(Sym) *)symtab_section->data + sym_index; |
||
1277 | |||
1278 | /* patch the original symbol */ |
||
1279 | sym->st_value = offset; |
||
1280 | sym->st_shndx = text_section->sh_num; |
||
1281 | sym->st_other &= ~ST_PE_EXPORT; /* do not export */ |
||
1282 | continue; |
||
1283 | } |
||
1284 | |||
1285 | if (type == STT_OBJECT) { /* data, ptr to that should be */ |
||
1286 | if (0 == is->iat_index) { |
||
1287 | /* original symbol will be patched later in pe_build_imports */ |
||
1288 | is->iat_index = sym_index; |
||
1289 | continue; |
||
1290 | } |
||
1291 | } |
||
1292 | |||
1293 | not_found: |
||
1294 | tcc_error_noabort("undefined symbol '%s'", name); |
||
1295 | ret = -1; |
||
1296 | |||
1297 | } else if (pe->s1->rdynamic |
||
1298 | && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) { |
||
1299 | /* if -rdynamic option, then export all non local symbols */ |
||
1300 | sym->st_other |= ST_PE_EXPORT; |
||
1301 | } |
||
145 | halyavin | 1302 | } |
1303 | return ret; |
||
1304 | } |
||
1305 | |||
1306 | /*----------------------------------------------------------------------------*/ |
||
1307 | #ifdef PE_PRINT_SECTIONS |
||
6429 | siemargl | 1308 | static void pe_print_section(FILE * f, Section * s) |
1309 | { |
||
1310 | /* just if you'r curious */ |
||
145 | halyavin | 1311 | BYTE *p, *e, b; |
1312 | int i, n, l, m; |
||
1313 | p = s->data; |
||
1314 | e = s->data + s->data_offset; |
||
1315 | l = e - p; |
||
1316 | |||
1317 | fprintf(f, "section \"%s\"", s->name); |
||
1318 | if (s->link) |
||
6429 | siemargl | 1319 | fprintf(f, "\nlink \"%s\"", s->link->name); |
145 | halyavin | 1320 | if (s->reloc) |
6429 | siemargl | 1321 | fprintf(f, "\nreloc \"%s\"", s->reloc->name); |
1322 | fprintf(f, "\nv_addr %08X", (unsigned)s->sh_addr); |
||
1323 | fprintf(f, "\ncontents %08X", (unsigned)l); |
||
145 | halyavin | 1324 | fprintf(f, "\n\n"); |
1325 | |||
1326 | if (s->sh_type == SHT_NOBITS) |
||
6429 | siemargl | 1327 | return; |
145 | halyavin | 1328 | |
6429 | siemargl | 1329 | if (0 == l) |
1330 | return; |
||
1331 | |||
145 | halyavin | 1332 | if (s->sh_type == SHT_SYMTAB) |
6429 | siemargl | 1333 | m = sizeof(ElfW(Sym)); |
1334 | else if (s->sh_type == SHT_RELX) |
||
1335 | m = sizeof(ElfW_Rel); |
||
145 | halyavin | 1336 | else |
6429 | siemargl | 1337 | m = 16; |
145 | halyavin | 1338 | |
6429 | siemargl | 1339 | fprintf(f, "%-8s", "offset"); |
1340 | for (i = 0; i < m; ++i) |
||
1341 | fprintf(f, " %02x", i); |
||
1342 | n = 56; |
||
145 | halyavin | 1343 | |
6429 | siemargl | 1344 | if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_RELX) { |
1345 | const char *fields1[] = { |
||
1346 | "name", |
||
1347 | "value", |
||
1348 | "size", |
||
1349 | "bind", |
||
1350 | "type", |
||
1351 | "other", |
||
1352 | "shndx", |
||
1353 | NULL |
||
1354 | }; |
||
1355 | |||
1356 | const char *fields2[] = { |
||
1357 | "offs", |
||
1358 | "type", |
||
1359 | "symb", |
||
1360 | NULL |
||
1361 | }; |
||
1362 | |||
1363 | const char **p; |
||
1364 | |||
1365 | if (s->sh_type == SHT_SYMTAB) |
||
1366 | p = fields1, n = 106; |
||
1367 | else |
||
1368 | p = fields2, n = 58; |
||
1369 | |||
1370 | for (i = 0; p[i]; ++i) |
||
1371 | fprintf(f, "%6s", p[i]); |
||
1372 | fprintf(f, " symbol"); |
||
145 | halyavin | 1373 | } |
6429 | siemargl | 1374 | |
1375 | fprintf(f, "\n"); |
||
1376 | for (i = 0; i < n; ++i) |
||
1377 | fprintf(f, "-"); |
||
1378 | fprintf(f, "\n"); |
||
1379 | |||
1380 | for (i = 0; i < l;) |
||
1381 | { |
||
1382 | fprintf(f, "%08X", i); |
||
1383 | for (n = 0; n < m; ++n) { |
||
1384 | if (n + i < l) |
||
1385 | fprintf(f, " %02X", p[i + n]); |
||
1386 | else |
||
1387 | fprintf(f, " "); |
||
1388 | } |
||
1389 | |||
1390 | if (s->sh_type == SHT_SYMTAB) { |
||
1391 | ElfW(Sym) *sym = (ElfW(Sym) *) (p + i); |
||
1392 | const char *name = s->link->data + sym->st_name; |
||
1393 | fprintf(f, " %04X %04X %04X %02X %02X %02X %04X \"%s\"", |
||
1394 | (unsigned)sym->st_name, |
||
1395 | (unsigned)sym->st_value, |
||
1396 | (unsigned)sym->st_size, |
||
1397 | (unsigned)ELFW(ST_BIND)(sym->st_info), |
||
1398 | (unsigned)ELFW(ST_TYPE)(sym->st_info), |
||
1399 | (unsigned)sym->st_other, |
||
1400 | (unsigned)sym->st_shndx, |
||
1401 | name); |
||
1402 | |||
1403 | } else if (s->sh_type == SHT_RELX) { |
||
1404 | ElfW_Rel *rel = (ElfW_Rel *) (p + i); |
||
1405 | ElfW(Sym) *sym = |
||
1406 | (ElfW(Sym) *) s->link->data + ELFW(R_SYM)(rel->r_info); |
||
1407 | const char *name = s->link->link->data + sym->st_name; |
||
1408 | fprintf(f, " %04X %02X %04X \"%s\"", |
||
1409 | (unsigned)rel->r_offset, |
||
1410 | (unsigned)ELFW(R_TYPE)(rel->r_info), |
||
1411 | (unsigned)ELFW(R_SYM)(rel->r_info), |
||
1412 | name); |
||
1413 | } else { |
||
1414 | fprintf(f, " "); |
||
1415 | for (n = 0; n < m; ++n) { |
||
1416 | if (n + i < l) { |
||
1417 | b = p[i + n]; |
||
1418 | if (b < 32 || b >= 127) |
||
1419 | b = '.'; |
||
1420 | fprintf(f, "%c", b); |
||
1421 | } |
||
1422 | } |
||
1423 | } |
||
1424 | i += m; |
||
1425 | fprintf(f, "\n"); |
||
1426 | } |
||
145 | halyavin | 1427 | fprintf(f, "\n\n"); |
1428 | } |
||
6429 | siemargl | 1429 | |
1430 | static void pe_print_sections(TCCState *s1, const char *fname) |
||
1431 | { |
||
1432 | Section *s; |
||
1433 | FILE *f; |
||
1434 | int i; |
||
1435 | f = fopen(fname, "w"); |
||
1436 | for (i = 1; i < s1->nb_sections; ++i) { |
||
1437 | s = s1->sections[i]; |
||
1438 | pe_print_section(f, s); |
||
1439 | } |
||
1440 | pe_print_section(f, s1->dynsymtab_section); |
||
1441 | fclose(f); |
||
1442 | } |
||
145 | halyavin | 1443 | #endif |
1444 | |||
6429 | siemargl | 1445 | /* ------------------------------------------------------------- */ |
1446 | /* helper function for load/store to insert one more indirection */ |
||
1447 | |||
1448 | ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) |
||
145 | halyavin | 1449 | { |
6429 | siemargl | 1450 | Sym *sym; |
1451 | ElfW(Sym) *esym; |
||
1452 | int r2; |
||
145 | halyavin | 1453 | |
6429 | siemargl | 1454 | if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) |
1455 | return sv; |
||
1456 | sym = sv->sym; |
||
1457 | if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN) |
||
1458 | return sv; |
||
1459 | if (!sym->c) |
||
1460 | put_extern_sym(sym, NULL, 0, 0); |
||
1461 | esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; |
||
1462 | if (!(esym->st_other & ST_PE_IMPORT)) |
||
1463 | return sv; |
||
1464 | |||
1465 | // printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); |
||
1466 | |||
1467 | memset(v2, 0, sizeof *v2); |
||
1468 | v2->type.t = VT_PTR; |
||
1469 | v2->r = VT_CONST | VT_SYM | VT_LVAL; |
||
1470 | v2->sym = sv->sym; |
||
1471 | |||
1472 | r2 = get_reg(RC_INT); |
||
1473 | load(r2, v2); |
||
1474 | v2->r = r2; |
||
1475 | |||
1476 | if ((uint32_t)sv->c.i) { |
||
1477 | vpushv(v2); |
||
1478 | vpushi(sv->c.i); |
||
1479 | gen_opi('+'); |
||
1480 | *v2 = *vtop--; |
||
145 | halyavin | 1481 | } |
6429 | siemargl | 1482 | |
1483 | v2->type.t = sv->type.t; |
||
1484 | v2->r |= sv->r & VT_LVAL; |
||
1485 | return v2; |
||
1486 | } |
||
1487 | |||
1488 | ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, addr_t value) |
||
1489 | { |
||
1490 | return add_elf_sym( |
||
1491 | s1->dynsymtab_section, |
||
1492 | value, |
||
1493 | dllindex, /* st_size */ |
||
1494 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), |
||
1495 | 0, |
||
9305 | Coldy | 1496 | #ifndef TCC_TARGET_KX |
1497 | value ? SHN_ABS : |
||
1498 | #endif |
||
1499 | SHN_UNDEF, |
||
6429 | siemargl | 1500 | name |
1501 | ); |
||
1502 | } |
||
1503 | |||
1504 | static int add_dllref(TCCState *s1, const char *dllname) |
||
1505 | { |
||
1506 | DLLReference *dllref; |
||
1507 | int i; |
||
1508 | for (i = 0; i < s1->nb_loaded_dlls; ++i) |
||
1509 | if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) |
||
1510 | return i + 1; |
||
1511 | dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); |
||
1512 | strcpy(dllref->name, dllname); |
||
1513 | dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
||
1514 | return s1->nb_loaded_dlls; |
||
1515 | } |
||
1516 | |||
1517 | /* ------------------------------------------------------------- */ |
||
1518 | |||
1519 | static int read_mem(int fd, unsigned offset, void *buffer, unsigned len) |
||
1520 | { |
||
1521 | lseek(fd, offset, SEEK_SET); |
||
1522 | return len == read(fd, buffer, len); |
||
1523 | } |
||
1524 | |||
1525 | /* ------------------------------------------------------------- |
||
1526 | * This is for compiled windows resources in 'coff' format |
||
1527 | * as generated by 'windres.exe -O coff ...'. |
||
1528 | */ |
||
1529 | |||
1530 | static int pe_load_res(TCCState *s1, int fd) |
||
1531 | { |
||
1532 | struct pe_rsrc_header hdr; |
||
1533 | Section *rsrc_section; |
||
1534 | int i, ret = -1; |
||
1535 | BYTE *ptr; |
||
1536 | unsigned offs; |
||
1537 | |||
1538 | if (!read_mem(fd, 0, &hdr, sizeof hdr)) |
||
1539 | goto quit; |
||
1540 | |||
1541 | if (hdr.filehdr.Machine != IMAGE_FILE_MACHINE |
||
1542 | || hdr.filehdr.NumberOfSections != 1 |
||
1543 | || strcmp(hdr.sectionhdr.Name, ".rsrc") != 0) |
||
1544 | goto quit; |
||
1545 | |||
1546 | rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC); |
||
1547 | ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData); |
||
1548 | offs = hdr.sectionhdr.PointerToRawData; |
||
1549 | if (!read_mem(fd, offs, ptr, hdr.sectionhdr.SizeOfRawData)) |
||
1550 | goto quit; |
||
1551 | offs = hdr.sectionhdr.PointerToRelocations; |
||
1552 | for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i) |
||
1553 | { |
||
1554 | struct pe_rsrc_reloc rel; |
||
1555 | if (!read_mem(fd, offs, &rel, sizeof rel)) |
||
1556 | goto quit; |
||
1557 | // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type); |
||
1558 | if (rel.type != RSRC_RELTYPE) |
||
1559 | goto quit; |
||
1560 | put_elf_reloc(symtab_section, rsrc_section, |
||
1561 | rel.offset, R_XXX_RELATIVE, 0); |
||
1562 | offs += sizeof rel; |
||
1563 | } |
||
1564 | ret = 0; |
||
1565 | quit: |
||
145 | halyavin | 1566 | return ret; |
1567 | } |
||
1568 | |||
1569 | /* ------------------------------------------------------------- */ |
||
9284 | Coldy | 1570 | #if !defined(TCC_TARGET_MEOS) || defined (TCC_TARGET_KX) |
6429 | siemargl | 1571 | static int pe_load_def(TCCState *s1, int fd) |
145 | halyavin | 1572 | { |
9305 | Coldy | 1573 | int state = 0, ret = -1, dllindex = 0, ord = 0; |
6429 | siemargl | 1574 | char line[400], dllname[80], *p, *x; |
1575 | FILE *fp; |
||
145 | halyavin | 1576 | |
9284 | Coldy | 1577 | #ifdef TCC_TARGET_KX |
1578 | fp = fopen(file->filename, "rb"); |
||
1579 | #else |
||
6429 | siemargl | 1580 | fp = fdopen(dup(fd), "rb"); |
9284 | Coldy | 1581 | #endif |
6429 | siemargl | 1582 | while (fgets(line, sizeof line, fp)) |
1583 | { |
||
1584 | p = trimfront(trimback(line, strchr(line, 0))); |
||
1585 | if (0 == *p || ';' == *p) |
||
1586 | continue; |
||
145 | halyavin | 1587 | |
6429 | siemargl | 1588 | switch (state) { |
1589 | case 0: |
||
1590 | if (0 != strnicmp(p, "LIBRARY", 7)) |
||
1591 | goto quit; |
||
1592 | pstrcpy(dllname, sizeof dllname, trimfront(p+7)); |
||
1593 | ++state; |
||
1594 | continue; |
||
145 | halyavin | 1595 | |
6429 | siemargl | 1596 | case 1: |
9305 | Coldy | 1597 | #ifdef TCC_TARGET_KX |
1598 | { |
||
1599 | char* p1 = strstr(p, "prefix"); |
||
1600 | if (p1) { |
||
1601 | p[p1 - p - 1] = 0; |
||
1602 | ord = -1; // All exports used prefix |
||
1603 | } |
||
1604 | } |
||
1605 | #endif |
||
6429 | siemargl | 1606 | if (0 != stricmp(p, "EXPORTS")) |
1607 | goto quit; |
||
1608 | ++state; |
||
1609 | continue; |
||
145 | halyavin | 1610 | |
6429 | siemargl | 1611 | case 2: |
1612 | dllindex = add_dllref(s1, dllname); |
||
1613 | ++state; |
||
9305 | Coldy | 1614 | #ifdef TCC_TARGET_KX |
1615 | if (ord == - 1) { |
||
1616 | char* tmp = strchr(dllname, '.'); |
||
1617 | int n = tmp - dllname; |
||
1618 | dllname[n] = '_'; |
||
1619 | dllname[n + 1] = 0; |
||
1620 | } |
||
1621 | #endif |
||
6429 | siemargl | 1622 | /* fall through */ |
1623 | default: |
||
9305 | Coldy | 1624 | #ifdef TCC_TARGET_KX |
1625 | if ((ord == -1) && p != strstr(p, dllname)) |
||
1626 | tcc_error_noabort("Wrong prefix for %s", p); |
||
1627 | #else |
||
6429 | siemargl | 1628 | /* get ordinal and will store in sym->st_value */ |
9305 | Coldy | 1629 | //ord = 0; // ord is assign in begining of function |
6429 | siemargl | 1630 | x = strchr(p, ' '); |
1631 | if (x) { |
||
1632 | *x = 0, x = strrchr(x + 1, '@'); |
||
1633 | if (x) { |
||
1634 | char *d; |
||
1635 | ord = (int)strtol(x + 1, &d, 10); |
||
1636 | if (*d) |
||
1637 | ord = 0; |
||
1638 | } |
||
1639 | } |
||
9305 | Coldy | 1640 | #endif |
6429 | siemargl | 1641 | pe_putimport(s1, dllindex, p, ord); |
1642 | continue; |
||
1643 | } |
||
145 | halyavin | 1644 | } |
6429 | siemargl | 1645 | ret = 0; |
1646 | quit: |
||
1647 | fclose(fp); |
||
1648 | return ret; |
||
1649 | } |
||
1650 | #else |
||
1651 | static int pe_load_def(TCCState *s1, int fd) |
||
1652 | { return 0; } |
||
1653 | #endif |
||
1654 | |||
1655 | /* ------------------------------------------------------------- */ |
||
1656 | #define TINY_IMPDEF_GET_EXPORT_NAMES_ONLY |
||
1657 | #include "win32/tools/tiny_impdef.c" |
||
1658 | |||
1659 | static int pe_load_dll(TCCState *s1, const char *dllname, int fd) |
||
1660 | { |
||
1661 | char *p, *q; |
||
1662 | int index; |
||
1663 | p = get_export_names(fd); |
||
1664 | if (!p) |
||
1665 | return -1; |
||
1666 | index = add_dllref(s1, dllname); |
||
1667 | for (q = p; *q; q += 1 + strlen(q)) |
||
1668 | pe_putimport(s1, index, q, 0); |
||
1669 | tcc_free(p); |
||
145 | halyavin | 1670 | return 0; |
1671 | } |
||
1672 | |||
1673 | /* ------------------------------------------------------------- */ |
||
6429 | siemargl | 1674 | ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) |
145 | halyavin | 1675 | { |
6429 | siemargl | 1676 | int ret = -1; |
1677 | char buf[10]; |
||
1678 | if (0 == strcmp(tcc_fileextension(filename), ".def")) |
||
1679 | ret = pe_load_def(s1, fd); |
||
1680 | else if (pe_load_res(s1, fd) == 0) |
||
1681 | ret = 0; |
||
1682 | else if (read_mem(fd, 0, buf, sizeof buf) && 0 == strncmp(buf, "MZ", 2)) |
||
1683 | ret = pe_load_dll(s1, tcc_basename(filename), fd); |
||
1684 | return ret; |
||
145 | halyavin | 1685 | } |
1686 | |||
1687 | /* ------------------------------------------------------------- */ |
||
6429 | siemargl | 1688 | #ifdef TCC_TARGET_X86_64 |
1689 | static unsigned pe_add_uwwind_info(TCCState *s1) |
||
145 | halyavin | 1690 | { |
6429 | siemargl | 1691 | if (NULL == s1->uw_pdata) { |
1692 | s1->uw_pdata = find_section(tcc_state, ".pdata"); |
||
1693 | s1->uw_pdata->sh_addralign = 4; |
||
1694 | s1->uw_sym = put_elf_sym(symtab_section, 0, 0, 0, 0, text_section->sh_num, NULL); |
||
1695 | } |
||
1696 | |||
1697 | if (0 == s1->uw_offs) { |
||
1698 | /* As our functions all have the same stackframe, we use one entry for all */ |
||
1699 | static const unsigned char uw_info[] = { |
||
1700 | 0x01, // UBYTE: 3 Version , UBYTE: 5 Flags |
||
1701 | 0x04, // UBYTE Size of prolog |
||
1702 | 0x02, // UBYTE Count of unwind codes |
||
1703 | 0x05, // UBYTE: 4 Frame Register (rbp), UBYTE: 4 Frame Register offset (scaled) |
||
1704 | // USHORT * n Unwind codes array |
||
1705 | // 0x0b, 0x01, 0xff, 0xff, // stack size |
||
1706 | 0x04, 0x03, // set frame ptr (mov rsp -> rbp) |
||
1707 | 0x01, 0x50 // push reg (rbp) |
||
1708 | }; |
||
1709 | |||
1710 | Section *s = text_section; |
||
1711 | unsigned char *p; |
||
1712 | |||
1713 | section_ptr_add(s, -s->data_offset & 3); /* align */ |
||
1714 | s1->uw_offs = s->data_offset; |
||
1715 | p = section_ptr_add(s, sizeof uw_info); |
||
1716 | memcpy(p, uw_info, sizeof uw_info); |
||
1717 | } |
||
1718 | |||
1719 | return s1->uw_offs; |
||
1720 | } |
||
1721 | |||
1722 | ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) |
||
1723 | { |
||
1724 | TCCState *s1 = tcc_state; |
||
1725 | Section *pd; |
||
1726 | unsigned o, n, d; |
||
1727 | struct /* _RUNTIME_FUNCTION */ { |
||
1728 | DWORD BeginAddress; |
||
1729 | DWORD EndAddress; |
||
1730 | DWORD UnwindData; |
||
1731 | } *p; |
||
1732 | |||
1733 | d = pe_add_uwwind_info(s1); |
||
1734 | pd = s1->uw_pdata; |
||
1735 | o = pd->data_offset; |
||
1736 | p = section_ptr_add(pd, sizeof *p); |
||
1737 | |||
1738 | /* record this function */ |
||
1739 | p->BeginAddress = start; |
||
1740 | p->EndAddress = end; |
||
1741 | p->UnwindData = d; |
||
1742 | |||
1743 | /* put relocations on it */ |
||
1744 | for (n = o + sizeof *p; o < n; o += sizeof p->BeginAddress) |
||
1745 | put_elf_reloc(symtab_section, pd, o, R_X86_64_RELATIVE, s1->uw_sym); |
||
1746 | } |
||
1747 | #endif |
||
1748 | /* ------------------------------------------------------------- */ |
||
1749 | #ifdef TCC_TARGET_X86_64 |
||
1750 | #define PE_STDSYM(n,s) n |
||
1751 | #else |
||
1752 | #define PE_STDSYM(n,s) "_" n s |
||
1753 | #endif |
||
1754 | |||
1755 | static void pe_add_runtime(TCCState *s1, struct pe_info *pe) |
||
1756 | { |
||
145 | halyavin | 1757 | const char *start_symbol; |
6429 | siemargl | 1758 | int pe_type = 0; |
145 | halyavin | 1759 | |
6429 | siemargl | 1760 | if (find_elf_sym(symtab_section, PE_STDSYM("WinMain","@16"))) |
1761 | pe_type = PE_GUI; |
||
145 | halyavin | 1762 | else |
6429 | siemargl | 1763 | if (TCC_OUTPUT_DLL == s1->output_type) { |
145 | halyavin | 1764 | pe_type = PE_DLL; |
6429 | siemargl | 1765 | /* need this for 'tccelf.c:relocate_section()' */ |
145 | halyavin | 1766 | s1->output_type = TCC_OUTPUT_EXE; |
1767 | } |
||
6429 | siemargl | 1768 | else |
1769 | pe_type = PE_EXE; |
||
145 | halyavin | 1770 | |
1771 | start_symbol = |
||
6429 | siemargl | 1772 | TCC_OUTPUT_MEMORY == s1->output_type |
1773 | ? PE_GUI == pe_type ? "__runwinmain" : "_main" |
||
1774 | : PE_DLL == pe_type ? PE_STDSYM("__dllstart","@12") |
||
1775 | : PE_GUI == pe_type ? "__winstart" : "__start" |
||
1776 | ; |
||
145 | halyavin | 1777 | |
6429 | siemargl | 1778 | if (!s1->leading_underscore || strchr(start_symbol, '@')) |
1779 | ++start_symbol; |
||
1780 | |||
145 | halyavin | 1781 | /* grab the startup code from libtcc1 */ |
6429 | siemargl | 1782 | if (TCC_OUTPUT_MEMORY != s1->output_type || PE_GUI == pe_type) |
1783 | add_elf_sym(symtab_section, |
||
1784 | 0, 0, |
||
1785 | ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, |
||
1786 | SHN_UNDEF, start_symbol); |
||
145 | halyavin | 1787 | |
6429 | siemargl | 1788 | tcc_add_pragma_libs(s1); |
1789 | |||
145 | halyavin | 1790 | if (0 == s1->nostdlib) { |
6429 | siemargl | 1791 | static const char *libs[] = { |
1792 | "tcc1", "msvcrt", "kernel32", "", "user32", "gdi32", NULL |
||
1793 | }; |
||
1794 | const char **pp, *p; |
||
1795 | for (pp = libs; 0 != (p = *pp); ++pp) { |
||
1796 | if (0 == *p) { |
||
1797 | if (PE_DLL != pe_type && PE_GUI != pe_type) |
||
1798 | break; |
||
1799 | } else if (tcc_add_library_err(s1, p) < 0) { |
||
1800 | break; |
||
1801 | } |
||
1802 | } |
||
145 | halyavin | 1803 | } |
1804 | |||
6429 | siemargl | 1805 | if (TCC_OUTPUT_MEMORY == s1->output_type) { |
1806 | pe_type = PE_RUN; |
||
1807 | #ifdef TCC_IS_NATIVE |
||
1808 | s1->runtime_main = start_symbol; |
||
1809 | #endif |
||
1810 | } else { |
||
1811 | pe->start_addr = (DWORD)(uintptr_t)tcc_get_symbol_err(s1, start_symbol); |
||
1812 | } |
||
145 | halyavin | 1813 | |
6429 | siemargl | 1814 | pe->type = pe_type; |
145 | halyavin | 1815 | } |
1816 | |||
6429 | siemargl | 1817 | ST_FUNC int pe_output_file(TCCState * s1, const char *filename) |
145 | halyavin | 1818 | { |
1819 | int ret; |
||
1820 | struct pe_info pe; |
||
1821 | int i; |
||
6429 | siemargl | 1822 | |
145 | halyavin | 1823 | memset(&pe, 0, sizeof pe); |
1824 | pe.filename = filename; |
||
1825 | pe.s1 = s1; |
||
1826 | |||
6429 | siemargl | 1827 | pe_add_runtime(s1, &pe); |
1828 | tcc_add_bcheck(s1); |
||
1829 | relocate_common_syms(); /* assign bss adresses */ |
||
1830 | tcc_add_linker_symbols(s1); |
||
1831 | |||
145 | halyavin | 1832 | ret = pe_check_symbols(&pe); |
6429 | siemargl | 1833 | if (ret) |
1834 | ; |
||
1835 | else if (filename) { |
||
1836 | if (PE_DLL == pe.type) { |
||
1837 | pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0); |
||
1838 | /* XXX: check if is correct for arm-pe target */ |
||
1839 | pe.imagebase = 0x10000000; |
||
1840 | } else { |
||
1841 | #if defined(TCC_TARGET_ARM) |
||
1842 | pe.imagebase = 0x00010000; |
||
1843 | #else |
||
1844 | pe.imagebase = 0x00400000; |
||
1845 | #endif |
||
1846 | } |
||
1847 | |||
1848 | #if defined(TCC_TARGET_ARM) |
||
1849 | /* we use "console" subsystem by default */ |
||
1850 | pe.subsystem = 9; |
||
1851 | #else |
||
1852 | if (PE_DLL == pe.type || PE_GUI == pe.type) |
||
1853 | pe.subsystem = 2; |
||
1854 | else |
||
1855 | pe.subsystem = 3; |
||
1856 | #endif |
||
1857 | /* Allow override via -Wl,-subsystem=... option */ |
||
1858 | if (s1->pe_subsystem != 0) |
||
1859 | pe.subsystem = s1->pe_subsystem; |
||
1860 | |||
1861 | /* set default file/section alignment */ |
||
1862 | if (pe.subsystem == 1) { |
||
1863 | pe.section_align = 0x20; |
||
1864 | pe.file_align = 0x20; |
||
1865 | } else { |
||
1866 | pe.section_align = 0x1000; |
||
1867 | pe.file_align = 0x200; |
||
145 | halyavin | 1868 | } |
6429 | siemargl | 1869 | |
1870 | if (s1->section_align != 0) |
||
1871 | pe.section_align = s1->section_align; |
||
1872 | if (s1->pe_file_align != 0) |
||
1873 | pe.file_align = s1->pe_file_align; |
||
1874 | |||
1875 | if ((pe.subsystem >= 10) && (pe.subsystem <= 12)) |
||
1876 | pe.imagebase = 0; |
||
1877 | |||
1878 | if (s1->has_text_addr) |
||
1879 | pe.imagebase = s1->text_addr; |
||
1880 | |||
1881 | pe_assign_addresses(&pe); |
||
1882 | relocate_syms(s1, 0); |
||
1883 | for (i = 1; i < s1->nb_sections; ++i) { |
||
1884 | Section *s = s1->sections[i]; |
||
1885 | if (s->reloc) { |
||
1886 | relocate_section(s1, s); |
||
1887 | pe_relocate_rva(&pe, s); |
||
1888 | } |
||
1889 | } |
||
1890 | if (s1->nb_errors) |
||
1891 | ret = -1; |
||
1892 | else |
||
1893 | ret = pe_write(&pe); |
||
1894 | tcc_free(pe.sec_info); |
||
1895 | } else { |
||
1896 | #ifdef TCC_IS_NATIVE |
||
1897 | pe.thunk = data_section; |
||
1898 | pe_build_imports(&pe); |
||
1899 | #endif |
||
145 | halyavin | 1900 | } |
6429 | siemargl | 1901 | |
145 | halyavin | 1902 | #ifdef PE_PRINT_SECTIONS |
6429 | siemargl | 1903 | pe_print_sections(s1, "tcc.log"); |
145 | halyavin | 1904 | #endif |
1905 | return ret; |
||
1906 | } |
||
1907 | |||
6429 | siemargl | 1908 | /* ------------------------------------------------------------- */>=>>>>>>>>>>>>>>>>>>>>>>12; |