Rev 145 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
145 | halyavin | 1 | /* |
2 | * TCCPE.C - PE file output for the TinyC Compiler |
||
3 | * |
||
4 | * Copyright (c) 2005 grischka |
||
5 | * |
||
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 | |||
21 | typedef unsigned char BYTE; |
||
22 | typedef unsigned short WORD; |
||
23 | typedef unsigned long DWORD; |
||
24 | #define ST static |
||
25 | |||
26 | /* XXX: move that to TCC ? */ |
||
27 | int verbose = 0; |
||
28 | |||
29 | /* definitions below are from winnt.h */ |
||
30 | |||
31 | typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header */ |
||
32 | WORD e_magic; /* Magic number */ |
||
33 | WORD e_cblp; /* Bytes on last page of file */ |
||
34 | WORD e_cp; /* Pages in file */ |
||
35 | WORD e_crlc; /* Relocations */ |
||
36 | WORD e_cparhdr; /* Size of header in paragraphs */ |
||
37 | WORD e_minalloc; /* Minimum extra paragraphs needed */ |
||
38 | WORD e_maxalloc; /* Maximum extra paragraphs needed */ |
||
39 | WORD e_ss; /* Initial (relative) SS value */ |
||
40 | WORD e_sp; /* Initial SP value */ |
||
41 | WORD e_csum; /* Checksum */ |
||
42 | WORD e_ip; /* Initial IP value */ |
||
43 | WORD e_cs; /* Initial (relative) CS value */ |
||
44 | WORD e_lfarlc; /* File address of relocation table */ |
||
45 | WORD e_ovno; /* Overlay number */ |
||
46 | WORD e_res[4]; /* Reserved words */ |
||
47 | WORD e_oemid; /* OEM identifier (for e_oeminfo) */ |
||
48 | WORD e_oeminfo; /* OEM information; e_oemid specific */ |
||
49 | WORD e_res2[10]; /* Reserved words */ |
||
50 | DWORD e_lfanew; /* File address of new exe header */ |
||
51 | BYTE e_code[0x40]; |
||
52 | |||
53 | } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; |
||
54 | |||
55 | #define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */ |
||
56 | #define SIZE_OF_NT_SIGNATURE 4 |
||
57 | |||
58 | typedef struct _IMAGE_FILE_HEADER { |
||
59 | WORD Machine; |
||
60 | WORD NumberOfSections; |
||
61 | DWORD TimeDateStamp; |
||
62 | DWORD PointerToSymbolTable; |
||
63 | DWORD NumberOfSymbols; |
||
64 | WORD SizeOfOptionalHeader; |
||
65 | WORD Characteristics; |
||
66 | } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; |
||
67 | |||
68 | |||
69 | #define IMAGE_SIZEOF_FILE_HEADER 20 |
||
70 | |||
71 | typedef struct _IMAGE_DATA_DIRECTORY { |
||
72 | DWORD VirtualAddress; |
||
73 | DWORD Size; |
||
74 | } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; |
||
75 | |||
76 | |||
77 | typedef struct _IMAGE_OPTIONAL_HEADER { |
||
78 | /* Standard fields. */ |
||
79 | WORD Magic; |
||
80 | BYTE MajorLinkerVersion; |
||
81 | BYTE MinorLinkerVersion; |
||
82 | DWORD SizeOfCode; |
||
83 | DWORD SizeOfInitializedData; |
||
84 | DWORD SizeOfUninitializedData; |
||
85 | DWORD AddressOfEntryPoint; |
||
86 | DWORD BaseOfCode; |
||
87 | DWORD BaseOfData; |
||
88 | |||
89 | /* NT additional fields. */ |
||
90 | DWORD ImageBase; |
||
91 | DWORD SectionAlignment; |
||
92 | DWORD FileAlignment; |
||
93 | WORD MajorOperatingSystemVersion; |
||
94 | WORD MinorOperatingSystemVersion; |
||
95 | WORD MajorImageVersion; |
||
96 | WORD MinorImageVersion; |
||
97 | WORD MajorSubsystemVersion; |
||
98 | WORD MinorSubsystemVersion; |
||
99 | DWORD Win32VersionValue; |
||
100 | DWORD SizeOfImage; |
||
101 | DWORD SizeOfHeaders; |
||
102 | DWORD CheckSum; |
||
103 | WORD Subsystem; |
||
104 | WORD DllCharacteristics; |
||
105 | DWORD SizeOfStackReserve; |
||
106 | DWORD SizeOfStackCommit; |
||
107 | DWORD SizeOfHeapReserve; |
||
108 | DWORD SizeOfHeapCommit; |
||
109 | DWORD LoaderFlags; |
||
110 | DWORD NumberOfRvaAndSizes; |
||
111 | IMAGE_DATA_DIRECTORY DataDirectory[16]; |
||
112 | |||
113 | } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; |
||
114 | |||
115 | |||
116 | #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 /* Export Directory */ |
||
117 | #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 /* Import Directory */ |
||
118 | #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 /* Resource Directory */ |
||
119 | #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 /* Exception Directory */ |
||
120 | #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 /* Security Directory */ |
||
121 | #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 /* Base Relocation Table */ |
||
122 | #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 /* Debug Directory */ |
||
123 | /* IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 (X86 usage) */ |
||
124 | #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 /* Architecture Specific Data */ |
||
125 | #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 /* RVA of GP */ |
||
126 | #define IMAGE_DIRECTORY_ENTRY_TLS 9 /* TLS Directory */ |
||
127 | #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 /* Load Configuration Directory */ |
||
128 | #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 /* Bound Import Directory in headers */ |
||
129 | #define IMAGE_DIRECTORY_ENTRY_IAT 12 /* Import Address Table */ |
||
130 | #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 /* Delay Load Import Descriptors */ |
||
131 | #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 /* COM Runtime descriptor */ |
||
132 | |||
133 | /* Section header format. */ |
||
134 | #define IMAGE_SIZEOF_SHORT_NAME 8 |
||
135 | |||
136 | typedef struct _IMAGE_SECTION_HEADER { |
||
137 | BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; |
||
138 | union { |
||
139 | DWORD PhysicalAddress; |
||
140 | DWORD VirtualSize; |
||
141 | } Misc; |
||
142 | DWORD VirtualAddress; |
||
143 | DWORD SizeOfRawData; |
||
144 | DWORD PointerToRawData; |
||
145 | DWORD PointerToRelocations; |
||
146 | DWORD PointerToLinenumbers; |
||
147 | WORD NumberOfRelocations; |
||
148 | WORD NumberOfLinenumbers; |
||
149 | DWORD Characteristics; |
||
150 | } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; |
||
151 | |||
152 | #define IMAGE_SIZEOF_SECTION_HEADER 40 |
||
153 | |||
154 | /* ----------------------------------------------------------- */ |
||
155 | typedef struct _IMAGE_BASE_RELOCATION { |
||
156 | DWORD VirtualAddress; |
||
157 | DWORD SizeOfBlock; |
||
158 | // WORD TypeOffset[1]; |
||
159 | } IMAGE_BASE_RELOCATION; |
||
160 | |||
161 | #define IMAGE_SIZEOF_BASE_RELOCATION 8 |
||
162 | |||
163 | #define IMAGE_REL_BASED_ABSOLUTE 0 |
||
164 | #define IMAGE_REL_BASED_HIGH 1 |
||
165 | #define IMAGE_REL_BASED_LOW 2 |
||
166 | #define IMAGE_REL_BASED_HIGHLOW 3 |
||
167 | #define IMAGE_REL_BASED_HIGHADJ 4 |
||
168 | #define IMAGE_REL_BASED_MIPS_JMPADDR 5 |
||
169 | #define IMAGE_REL_BASED_SECTION 6 |
||
170 | #define IMAGE_REL_BASED_REL32 7 |
||
171 | |||
172 | /* ----------------------------------------------------------- */ |
||
173 | |||
174 | /* ----------------------------------------------------------- */ |
||
175 | IMAGE_DOS_HEADER pe_dos_hdr = { |
||
176 | 0x5A4D, /*WORD e_magic; Magic number */ |
||
177 | 0x0090, /*WORD e_cblp; Bytes on last page of file */ |
||
178 | 0x0003, /*WORD e_cp; Pages in file */ |
||
179 | 0x0000, /*WORD e_crlc; Relocations */ |
||
180 | |||
181 | 0x0004, /*WORD e_cparhdr; Size of header in paragraphs */ |
||
182 | 0x0000, /*WORD e_minalloc; Minimum extra paragraphs needed */ |
||
183 | 0xFFFF, /*WORD e_maxalloc; Maximum extra paragraphs needed */ |
||
184 | 0x0000, /*WORD e_ss; Initial (relative) SS value */ |
||
185 | |||
186 | 0x00B8, /*WORD e_sp; Initial SP value */ |
||
187 | 0x0000, /*WORD e_csum; Checksum */ |
||
188 | 0x0000, /*WORD e_ip; Initial IP value */ |
||
189 | 0x0000, /*WORD e_cs; Initial (relative) CS value */ |
||
190 | 0x0040, /*WORD e_lfarlc; File address of relocation table */ |
||
191 | 0x0000, /*WORD e_ovno; Overlay number */ |
||
192 | {0, 0, 0, 0}, /*WORD e_res[4]; Reserved words */ |
||
193 | 0x0000, /*WORD e_oemid; OEM identifier (for e_oeminfo) */ |
||
194 | 0x0000, /*WORD e_oeminfo; OEM information; e_oemid specific */ |
||
195 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /*WORD e_res2[10]; Reserved words */ |
||
196 | 0x00000080, /*DWORD e_lfanew; File address of new exe header */ |
||
197 | { /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */ |
||
198 | /*0040 */ 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, |
||
199 | 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68, |
||
200 | /*0050 */ 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, |
||
201 | 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, |
||
202 | /*0060 */ 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, |
||
203 | 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, |
||
204 | /*0070 */ 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a, 0x24, 0x00, |
||
205 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
||
206 | /*0080 */ |
||
207 | } |
||
208 | }; |
||
209 | |||
210 | DWORD pe_magic = IMAGE_NT_SIGNATURE; |
||
211 | |||
212 | IMAGE_FILE_HEADER pe_file_hdr = { |
||
213 | 0x014C, /*WORD Machine; */ |
||
214 | 0x0003, /*WORD NumberOfSections; */ |
||
215 | 0x00000000, /*DWORD TimeDateStamp; */ |
||
216 | 0x00000000, /*DWORD PointerToSymbolTable; */ |
||
217 | 0x00000000, /*DWORD NumberOfSymbols; */ |
||
218 | 0x00E0, /*WORD SizeOfOptionalHeader; */ |
||
219 | 0x030F /*WORD Characteristics; */ |
||
220 | }; |
||
221 | |||
222 | IMAGE_OPTIONAL_HEADER32 pe_opt_hdr = { |
||
223 | /* Standard fields. */ |
||
224 | 0x010B, /*WORD Magic; */ |
||
225 | 0x06, /*BYTE MajorLinkerVersion; */ |
||
226 | 0x00, /*BYTE MinorLinkerVersion; */ |
||
227 | 0x00000000, /*DWORD SizeOfCode; */ |
||
228 | 0x00000000, /*DWORD SizeOfInitializedData; */ |
||
229 | 0x00000000, /*DWORD SizeOfUninitializedData; */ |
||
230 | 0x00000000, /*DWORD AddressOfEntryPoint; */ |
||
231 | 0x00000000, /*DWORD BaseOfCode; */ |
||
232 | 0x00000000, /*DWORD BaseOfData; */ |
||
233 | |||
234 | /* NT additional fields. */ |
||
235 | 0x00400000, /*DWORD ImageBase; */ |
||
236 | 0x00001000, /*DWORD SectionAlignment; */ |
||
237 | 0x00000200, /*DWORD FileAlignment; */ |
||
238 | 0x0004, /*WORD MajorOperatingSystemVersion; */ |
||
239 | 0x0000, /*WORD MinorOperatingSystemVersion; */ |
||
240 | 0x0000, /*WORD MajorImageVersion; */ |
||
241 | 0x0000, /*WORD MinorImageVersion; */ |
||
242 | 0x0004, /*WORD MajorSubsystemVersion; */ |
||
243 | 0x0000, /*WORD MinorSubsystemVersion; */ |
||
244 | 0x00000000, /*DWORD Win32VersionValue; */ |
||
245 | 0x00000000, /*DWORD SizeOfImage; */ |
||
246 | 0x00000200, /*DWORD SizeOfHeaders; */ |
||
247 | 0x00000000, /*DWORD CheckSum; */ |
||
248 | 0x0002, /*WORD Subsystem; */ |
||
249 | 0x0000, /*WORD DllCharacteristics; */ |
||
250 | 0x00100000, /*DWORD SizeOfStackReserve; */ |
||
251 | 0x00001000, /*DWORD SizeOfStackCommit; */ |
||
252 | 0x00100000, /*DWORD SizeOfHeapReserve; */ |
||
253 | 0x00001000, /*DWORD SizeOfHeapCommit; */ |
||
254 | 0x00000000, /*DWORD LoaderFlags; */ |
||
255 | 0x00000010, /*DWORD NumberOfRvaAndSizes; */ |
||
256 | |||
257 | /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */ |
||
258 | {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, |
||
259 | {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}} |
||
260 | }; |
||
261 | |||
262 | /*----------------------------------------------------------------------------*/ |
||
263 | |||
264 | /*----------------------------------------------------------------------------*/ |
||
265 | |||
266 | struct pe_import_header { |
||
267 | DWORD first_entry; |
||
268 | DWORD time_date; |
||
269 | DWORD forwarder; |
||
270 | DWORD lib_name_offset; |
||
271 | DWORD first_thunk; |
||
272 | }; |
||
273 | |||
274 | struct pe_export_header { |
||
275 | DWORD Characteristics; |
||
276 | DWORD TimeDateStamp; |
||
277 | DWORD Version; |
||
278 | DWORD Name; |
||
279 | DWORD Base; |
||
280 | DWORD NumberOfFunctions; |
||
281 | DWORD NumberOfNames; |
||
282 | DWORD AddressOfFunctions; |
||
283 | DWORD AddressOfNames; |
||
284 | DWORD AddressOfNameOrdinals; |
||
285 | }; |
||
286 | |||
287 | struct pe_reloc_header { |
||
288 | DWORD offset; |
||
289 | DWORD size; |
||
290 | }; |
||
291 | |||
292 | /* ------------------------------------------------------------- */ |
||
293 | /* internal temporary structures */ |
||
294 | |||
295 | ST const char *pe_sec_names[] = { |
||
296 | ".text", |
||
297 | ".data", |
||
298 | ".bss", |
||
299 | ".rsrc", |
||
300 | ".reloc", |
||
301 | ".stab", |
||
302 | ".stabstr" |
||
303 | }; |
||
304 | |||
305 | enum { |
||
306 | sec_text = 0, |
||
307 | sec_data, |
||
308 | sec_bss, |
||
309 | sec_rsrc, |
||
310 | sec_reloc, |
||
311 | sec_stab, |
||
312 | sec_stabstr, |
||
313 | pe_sec_number |
||
314 | }; |
||
315 | |||
316 | ST DWORD pe_flags[] = { |
||
317 | 0x60000020, /* ".text", */ |
||
318 | 0xC0000040, /* ".data", */ |
||
319 | 0xC0000080, /* ".bss", */ |
||
320 | 0x40000040, /* ".rsrc", */ |
||
321 | 0x42000040, /* ".reloc", */ |
||
322 | 0x42000802, /* ".stab", */ |
||
323 | 0x42000802 /* ".stabstr", */ |
||
324 | }; |
||
325 | |||
326 | struct section_info { |
||
327 | struct section_info *next; |
||
328 | int id; |
||
329 | DWORD sh_addr; |
||
330 | DWORD sh_size; |
||
331 | unsigned char *data; |
||
332 | DWORD data_size; |
||
333 | }; |
||
334 | |||
335 | struct import_symbol { |
||
336 | int sym_index; |
||
337 | int offset; |
||
338 | }; |
||
339 | |||
340 | struct pe_import_info { |
||
341 | int dll_index; |
||
342 | int sym_count; |
||
343 | struct import_symbol **symbols; |
||
344 | }; |
||
345 | |||
346 | struct pe_info { |
||
347 | const char *filename; |
||
348 | DWORD sizeofheaders; |
||
349 | DWORD imagebase; |
||
350 | DWORD start_addr; |
||
351 | DWORD imp_offs; |
||
352 | DWORD imp_size; |
||
353 | DWORD iat_offs; |
||
354 | DWORD iat_size; |
||
355 | DWORD exp_offs; |
||
356 | DWORD exp_size; |
||
357 | struct section_info sh_info[pe_sec_number]; |
||
358 | int sec_count; |
||
359 | struct pe_import_info **imp_info; |
||
360 | int imp_count; |
||
361 | Section *reloc; |
||
362 | Section *thunk; |
||
363 | TCCState *s1; |
||
364 | }; |
||
365 | |||
366 | /* ------------------------------------------------------------- */ |
||
367 | #define PE_MERGE_DATA |
||
368 | // #define PE_PRINT_SECTIONS |
||
369 | |||
370 | #ifndef MAX_PATH |
||
371 | #define MAX_PATH 260 |
||
372 | #endif |
||
373 | |||
374 | void error_noabort(const char *, ...); |
||
375 | |||
376 | ST char pe_type; |
||
377 | |||
378 | #define PE_NUL 0 |
||
379 | #define PE_DLL 1 |
||
380 | #define PE_GUI 2 |
||
381 | #define PE_EXE 3 |
||
382 | |||
383 | ST int pe_find_import(TCCState * s1, const char *symbol, char *ret) |
||
384 | { |
||
385 | int sym_index = find_elf_sym(s1->dynsymtab_section, symbol); |
||
386 | if (0 == sym_index) { |
||
387 | /* Hm, maybe it's '_symbol' instead of 'symbol' or '__imp__symbol' */ |
||
388 | char buffer[100]; |
||
389 | if (0 == memcmp(symbol, "__imp__", 7)) |
||
390 | symbol += 6; |
||
391 | else |
||
392 | buffer[0] = '_', strcpy(buffer + 1, symbol), symbol = buffer; |
||
393 | sym_index = find_elf_sym(s1->dynsymtab_section, symbol); |
||
394 | } |
||
395 | if (ret) |
||
396 | strcpy(ret, symbol); |
||
397 | return sym_index; |
||
398 | } |
||
399 | |||
400 | #ifdef WIN32 |
||
401 | ST void **pe_imp; |
||
402 | ST int nb_pe_imp; |
||
403 | |||
404 | void *resolve_sym(struct TCCState *s1, const char *symbol, int type) |
||
405 | { |
||
406 | char buffer[100], *p = buffer; |
||
407 | void *a = NULL; |
||
408 | int sym_index = pe_find_import(s1, symbol, p); |
||
409 | int dll_index; |
||
410 | const char *dll_name; |
||
411 | void *hm; |
||
412 | |||
413 | if (sym_index) { |
||
414 | dll_index = ((Elf32_Sym *) s1->dynsymtab_section->data)[sym_index]. |
||
415 | st_other; |
||
416 | dll_name = s1->loaded_dlls[dll_index]->name; |
||
417 | hm = GetModuleHandleA(dll_name); |
||
418 | if (NULL == hm) |
||
419 | hm = LoadLibraryA(dll_name); |
||
420 | if (hm) { |
||
421 | a = GetProcAddress(hm, buffer); |
||
422 | if (a && STT_OBJECT == type) { |
||
423 | // need to return a pointer to the address for data objects |
||
424 | dynarray_add(&pe_imp, &nb_pe_imp, a); |
||
425 | a = &pe_imp[nb_pe_imp - 1]; |
||
426 | } |
||
427 | } |
||
428 | } |
||
429 | return a; |
||
430 | } |
||
431 | #endif |
||
432 | |||
433 | #define for_sym_in_symtab(sym) \ |
||
434 | for (sym = (Elf32_Sym *)symtab_section->data + 1; \ |
||
435 | sym < (Elf32_Sym *)(symtab_section->data + \ |
||
436 | symtab_section->data_offset); \ |
||
437 | ++sym) |
||
438 | |||
439 | #define pe_set_datadir(dir,addr,size) \ |
||
440 | pe_opt_hdr.DataDirectory[dir].VirtualAddress = addr, \ |
||
441 | pe_opt_hdr.DataDirectory[dir].Size = size |
||
442 | |||
443 | /*----------------------------------------------------------------------------*/ |
||
444 | ST void dynarray_reset(void ***pp, int *n) |
||
445 | { |
||
446 | int i; |
||
447 | for (i = 0; i < *n; ++i) |
||
448 | tcc_free((*pp)[i]); |
||
449 | tcc_free(*pp); |
||
450 | *pp = NULL; |
||
451 | *n = 0; |
||
452 | } |
||
453 | |||
454 | ST int dynarray_assoc(void **pp, int n, int key) |
||
455 | { |
||
456 | int i; |
||
457 | for (i = 0; i < n; ++i, ++pp) |
||
458 | if (key == **(int **) pp) |
||
459 | return i; |
||
460 | return -1; |
||
461 | } |
||
462 | |||
463 | #if 0 |
||
464 | ST DWORD umin(DWORD a, DWORD b) |
||
465 | { |
||
466 | return a < b ? a : b; |
||
467 | } |
||
468 | #endif |
||
469 | |||
470 | ST DWORD umax(DWORD a, DWORD b) |
||
471 | { |
||
472 | return a < b ? b : a; |
||
473 | } |
||
474 | |||
475 | ST void pe_fpad(FILE * fp, DWORD new_pos) |
||
476 | { |
||
477 | DWORD pos = ftell(fp); |
||
478 | while (++pos <= new_pos) |
||
479 | fputc(0, fp); |
||
480 | } |
||
481 | |||
482 | ST DWORD pe_file_align(DWORD n) |
||
483 | { |
||
484 | return (n + (0x200 - 1)) & ~(0x200 - 1); |
||
485 | } |
||
486 | |||
487 | ST DWORD pe_virtual_align(DWORD n) |
||
488 | { |
||
489 | return (n + (0x1000 - 1)) & ~(0x1000 - 1); |
||
490 | } |
||
491 | |||
492 | ST void pe_align_section(Section * s, int a) |
||
493 | { |
||
494 | int i = s->data_offset & (a - 1); |
||
495 | if (i) |
||
496 | section_ptr_add(s, a - i); |
||
497 | } |
||
498 | |||
499 | |||
500 | /*----------------------------------------------------------------------------*/ |
||
501 | ST int pe_write_pe(struct pe_info *pe) |
||
502 | { |
||
503 | int i; |
||
504 | FILE *op; |
||
505 | DWORD file_offset; |
||
506 | IMAGE_SECTION_HEADER ish[pe_sec_number], *psh; |
||
507 | int sec_index = 0; |
||
508 | |||
509 | op = fopen(pe->filename, "wb"); |
||
510 | if (NULL == op) { |
||
511 | error_noabort("could not create file: %s", pe->filename); |
||
512 | return 1; |
||
513 | } |
||
514 | |||
515 | memset(&ish, 0, sizeof ish); |
||
516 | |||
517 | pe->sizeofheaders = pe_file_align(sizeof pe_dos_hdr |
||
518 | + sizeof pe_magic |
||
519 | + sizeof pe_file_hdr |
||
520 | + sizeof pe_opt_hdr |
||
521 | + |
||
522 | pe->sec_count * |
||
523 | sizeof(IMAGE_SECTION_HEADER) |
||
524 | ); |
||
525 | |||
526 | file_offset = pe->sizeofheaders; |
||
527 | pe_fpad(op, file_offset); |
||
528 | |||
529 | if (2 == verbose) |
||
530 | printf("-------------------------------" |
||
531 | "\n virt file size section" "\n"); |
||
532 | |||
533 | for (i = 0; i < pe->sec_count; ++i) { |
||
534 | struct section_info *si = pe->sh_info + i; |
||
535 | const char *sh_name = pe_sec_names[si->id]; |
||
536 | unsigned long addr = si->sh_addr - pe->imagebase; |
||
537 | unsigned long size = si->sh_size; |
||
538 | |||
539 | if (2 == verbose) |
||
540 | printf("%6lx %6lx %6lx %s\n", |
||
541 | addr, file_offset, size, sh_name); |
||
542 | |||
543 | switch (si->id) { |
||
544 | case sec_text: |
||
545 | pe_opt_hdr.BaseOfCode = addr; |
||
546 | pe_opt_hdr.AddressOfEntryPoint = addr + pe->start_addr; |
||
547 | break; |
||
548 | |||
549 | case sec_data: |
||
550 | pe_opt_hdr.BaseOfData = addr; |
||
551 | if (pe->imp_size) { |
||
552 | pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT, |
||
553 | pe->imp_offs + addr, pe->imp_size); |
||
554 | pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT, |
||
555 | pe->iat_offs + addr, pe->iat_size); |
||
556 | } |
||
557 | if (pe->exp_size) { |
||
558 | pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT, |
||
559 | pe->exp_offs + addr, pe->exp_size); |
||
560 | } |
||
561 | break; |
||
562 | |||
563 | case sec_bss: |
||
564 | break; |
||
565 | |||
566 | case sec_reloc: |
||
567 | pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size); |
||
568 | break; |
||
569 | |||
570 | case sec_rsrc: |
||
571 | pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size); |
||
572 | break; |
||
573 | |||
574 | case sec_stab: |
||
575 | break; |
||
576 | |||
577 | case sec_stabstr: |
||
578 | break; |
||
579 | } |
||
580 | |||
581 | psh = &ish[sec_index++]; |
||
582 | strcpy((char *) psh->Name, sh_name); |
||
583 | |||
584 | psh->Characteristics = pe_flags[si->id]; |
||
585 | psh->VirtualAddress = addr; |
||
586 | psh->Misc.VirtualSize = size; |
||
587 | pe_opt_hdr.SizeOfImage = |
||
588 | umax(psh->VirtualAddress + psh->Misc.VirtualSize, |
||
589 | pe_opt_hdr.SizeOfImage); |
||
590 | |||
591 | if (si->data_size) { |
||
592 | psh->PointerToRawData = file_offset; |
||
593 | fwrite(si->data, 1, si->data_size, op); |
||
594 | file_offset = pe_file_align(file_offset + si->data_size); |
||
595 | psh->SizeOfRawData = file_offset - psh->PointerToRawData; |
||
596 | pe_fpad(op, file_offset); |
||
597 | } |
||
598 | } |
||
599 | |||
600 | /*----------------------------------------------------- */ |
||
601 | |||
602 | pe_file_hdr.NumberOfSections = sec_index; |
||
603 | pe_opt_hdr.SizeOfHeaders = pe->sizeofheaders; |
||
604 | pe_opt_hdr.ImageBase = pe->imagebase; |
||
605 | if (PE_DLL == pe_type) |
||
606 | pe_file_hdr.Characteristics = 0x230E; |
||
607 | else if (PE_GUI != pe_type) |
||
608 | pe_opt_hdr.Subsystem = 3; |
||
609 | |||
610 | fseek(op, SEEK_SET, 0); |
||
611 | fwrite(&pe_dos_hdr, 1, sizeof pe_dos_hdr, op); |
||
612 | fwrite(&pe_magic, 1, sizeof pe_magic, op); |
||
613 | fwrite(&pe_file_hdr, 1, sizeof pe_file_hdr, op); |
||
614 | fwrite(&pe_opt_hdr, 1, sizeof pe_opt_hdr, op); |
||
615 | for (i = 0; i < sec_index; ++i) |
||
616 | fwrite(&ish[i], 1, sizeof(IMAGE_SECTION_HEADER), op); |
||
617 | fclose(op); |
||
618 | |||
619 | if (2 == verbose) |
||
620 | printf("-------------------------------\n"); |
||
621 | if (verbose) |
||
622 | printf("<-- %s (%lu bytes)\n", pe->filename, file_offset); |
||
623 | |||
624 | return 0; |
||
625 | } |
||
626 | |||
627 | /*----------------------------------------------------------------------------*/ |
||
628 | ST int pe_add_import(struct pe_info *pe, int sym_index, DWORD offset) |
||
629 | { |
||
630 | int i; |
||
631 | int dll_index; |
||
632 | struct pe_import_info *p; |
||
633 | struct import_symbol *s; |
||
634 | |||
635 | dll_index = |
||
636 | ((Elf32_Sym *) pe->s1->dynsymtab_section->data)[sym_index]. |
||
637 | st_other; |
||
638 | i = dynarray_assoc((void **) pe->imp_info, pe->imp_count, dll_index); |
||
639 | if (-1 != i) { |
||
640 | p = pe->imp_info[i]; |
||
641 | goto found_dll; |
||
642 | } |
||
643 | p = tcc_mallocz(sizeof *p); |
||
644 | p->dll_index = dll_index; |
||
645 | dynarray_add((void ***) &pe->imp_info, &pe->imp_count, p); |
||
646 | |||
647 | found_dll: |
||
648 | i = dynarray_assoc((void **) p->symbols, p->sym_count, sym_index); |
||
649 | if (-1 != i) |
||
650 | goto found_sym; |
||
651 | s = tcc_mallocz(sizeof *s); |
||
652 | s->sym_index = sym_index; |
||
653 | s->offset = offset; |
||
654 | dynarray_add((void ***) &p->symbols, &p->sym_count, s); |
||
655 | |||
656 | found_sym: |
||
657 | return 1; |
||
658 | } |
||
659 | |||
660 | /*----------------------------------------------------------------------------*/ |
||
661 | ST void pe_build_imports(struct pe_info *pe) |
||
662 | { |
||
663 | int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i; |
||
664 | DWORD voffset = pe->thunk->sh_addr - pe->imagebase; |
||
665 | int ndlls = pe->imp_count; |
||
666 | |||
667 | for (sym_cnt = i = 0; i < ndlls; ++i) |
||
668 | sym_cnt += pe->imp_info[i]->sym_count; |
||
669 | |||
670 | if (0 == sym_cnt) |
||
671 | return; |
||
672 | |||
673 | pe_align_section(pe->thunk, 16); |
||
674 | |||
675 | pe->imp_offs = dll_ptr = pe->thunk->data_offset; |
||
676 | pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header); |
||
677 | pe->iat_offs = dll_ptr + pe->imp_size; |
||
678 | pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD); |
||
679 | section_ptr_add(pe->thunk, pe->imp_size + 2 * pe->iat_size); |
||
680 | |||
681 | thk_ptr = pe->iat_offs; |
||
682 | ent_ptr = pe->iat_offs + pe->iat_size; |
||
683 | for (i = 0; i < pe->imp_count; ++i) { |
||
684 | struct pe_import_header *hdr; |
||
685 | int k, n, v; |
||
686 | struct pe_import_info *p = pe->imp_info[i]; |
||
687 | const char *name = pe->s1->loaded_dlls[p->dll_index]->name; |
||
688 | |||
689 | /* put the dll name into the import header */ |
||
690 | if (0 == strncmp(name, "lib", 3)) |
||
691 | name += 3; |
||
692 | v = put_elf_str(pe->thunk, name); |
||
693 | |||
694 | hdr = (struct pe_import_header *) (pe->thunk->data + dll_ptr); |
||
695 | hdr->first_thunk = thk_ptr + voffset; |
||
696 | hdr->first_entry = ent_ptr + voffset; |
||
697 | hdr->lib_name_offset = v + voffset; |
||
698 | |||
699 | for (k = 0, n = p->sym_count; k <= n; ++k) { |
||
700 | if (k < n) { |
||
701 | DWORD offset = p->symbols[k]->offset; |
||
702 | int sym_index = p->symbols[k]->sym_index; |
||
703 | Elf32_Sym *sym = |
||
704 | (Elf32_Sym *) pe->s1->dynsymtab_section->data + |
||
705 | sym_index; |
||
706 | const char *name = |
||
707 | pe->s1->dynsymtab_section->link->data + sym->st_name; |
||
708 | |||
709 | if (offset & 0x80000000) { /* ref to data */ |
||
710 | Elf32_Sym *sym = |
||
711 | &((Elf32_Sym *) symtab_section-> |
||
712 | data)[offset & 0x7FFFFFFF]; |
||
713 | sym->st_value = thk_ptr; |
||
714 | sym->st_shndx = pe->thunk->sh_num; |
||
715 | } else { /* ref to function */ |
||
716 | |||
717 | char buffer[100]; |
||
718 | sprintf(buffer, "IAT.%s", name); |
||
719 | sym_index = |
||
720 | put_elf_sym(symtab_section, thk_ptr, sizeof(DWORD), |
||
721 | ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT), |
||
722 | 0, pe->thunk->sh_num, buffer); |
||
723 | |||
724 | put_elf_reloc(symtab_section, text_section, offset, R_386_32, /*R_JMP_SLOT, */ |
||
725 | sym_index); |
||
726 | } |
||
727 | v = pe->thunk->data_offset + voffset; |
||
728 | section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */ |
||
729 | put_elf_str(pe->thunk, name); |
||
730 | } else { |
||
731 | v = 0; // last entry is zero |
||
732 | } |
||
733 | *(DWORD *) (pe->thunk->data + thk_ptr) = |
||
734 | *(DWORD *) (pe->thunk->data + ent_ptr) = v; |
||
735 | thk_ptr += sizeof(DWORD); |
||
736 | ent_ptr += sizeof(DWORD); |
||
737 | } |
||
738 | dll_ptr += sizeof(struct pe_import_header); |
||
739 | dynarray_reset((void ***) &p->symbols, &p->sym_count); |
||
740 | } |
||
741 | dynarray_reset((void ***) &pe->imp_info, &pe->imp_count); |
||
742 | } |
||
743 | |||
744 | /* ------------------------------------------------------------- */ |
||
745 | ST int sym_cmp(const void *va, const void *vb) |
||
746 | { |
||
747 | Elf32_Sym *sa = (Elf32_Sym *)symtab_section->data + *(int*)va; |
||
748 | Elf32_Sym *sb = (Elf32_Sym *)symtab_section->data + *(int*)vb; |
||
749 | const char *ca = symtab_section->link->data + sa->st_name; |
||
750 | const char *cb = symtab_section->link->data + sb->st_name; |
||
751 | return strcmp(ca, cb); |
||
752 | } |
||
753 | |||
754 | ST void pe_build_exports(struct pe_info *pe) |
||
755 | { |
||
756 | Elf32_Sym *sym; |
||
757 | DWORD func_offset, voffset; |
||
758 | struct pe_export_header *hdr; |
||
759 | int sym_count, n, ord, *sorted; |
||
760 | |||
761 | voffset = pe->thunk->sh_addr - pe->imagebase; |
||
762 | sym_count = 0, n = 1, sorted = NULL; |
||
763 | |||
764 | // for simplicity only functions are exported |
||
765 | for_sym_in_symtab(sym) |
||
766 | { |
||
767 | if ((sym->st_other & 1) |
||
768 | && sym->st_shndx == text_section->sh_num) |
||
769 | dynarray_add((void***)&sorted, &sym_count, (void*)n); |
||
770 | ++n; |
||
771 | } |
||
772 | |||
773 | if (0 == sym_count) |
||
774 | return; |
||
775 | |||
776 | qsort (sorted, sym_count, sizeof sorted[0], sym_cmp); |
||
777 | pe_align_section(pe->thunk, 16); |
||
778 | |||
779 | pe->exp_offs = pe->thunk->data_offset; |
||
780 | hdr = section_ptr_add(pe->thunk, |
||
781 | sizeof(struct pe_export_header) + |
||
782 | sym_count * (2 * sizeof(DWORD) + sizeof(WORD))); |
||
783 | |||
784 | func_offset = pe->exp_offs + sizeof(struct pe_export_header); |
||
785 | |||
786 | hdr->Characteristics = 0; |
||
787 | hdr->Base = 1; |
||
788 | hdr->NumberOfFunctions = sym_count; |
||
789 | hdr->NumberOfNames = sym_count; |
||
790 | hdr->AddressOfFunctions = func_offset + voffset; |
||
791 | hdr->AddressOfNames = hdr->AddressOfFunctions + sym_count * sizeof(DWORD); |
||
792 | hdr->AddressOfNameOrdinals = hdr->AddressOfNames + sym_count * sizeof(DWORD); |
||
793 | hdr->Name = pe->thunk->data_offset + voffset; |
||
794 | put_elf_str(pe->thunk, tcc_basename(pe->filename)); |
||
795 | |||
796 | for (ord = 0; ord < sym_count; ++ord) |
||
797 | { |
||
798 | char *name; DWORD *p, *pfunc, *pname; WORD *pord; |
||
799 | sym = (Elf32_Sym *)symtab_section->data + sorted[ord]; |
||
800 | name = symtab_section->link->data + sym->st_name; |
||
801 | p = (DWORD*)(pe->thunk->data + func_offset); |
||
802 | pfunc = p + ord; |
||
803 | pname = p + sym_count + ord; |
||
804 | pord = (WORD *)(p + 2*sym_count) + ord; |
||
805 | *pfunc = sym->st_value + pe->s1->sections[sym->st_shndx]->sh_addr - pe->imagebase; |
||
806 | *pname = pe->thunk->data_offset + voffset; |
||
807 | *pord = ord; |
||
808 | put_elf_str(pe->thunk, name); |
||
809 | /* printf("export: %s\n", name); */ |
||
810 | } |
||
811 | pe->exp_size = pe->thunk->data_offset - pe->exp_offs; |
||
812 | tcc_free(sorted); |
||
813 | } |
||
814 | |||
815 | /* ------------------------------------------------------------- */ |
||
816 | ST void pe_build_reloc(struct pe_info *pe, int *section_order, |
||
817 | int section_count) |
||
818 | { |
||
819 | DWORD offset, block_ptr, addr; |
||
820 | int count, i; |
||
821 | Elf32_Rel *rel, *rel_end; |
||
822 | Section *s = NULL, *sr; |
||
823 | offset = addr = block_ptr = count = i = 0; |
||
824 | rel = rel_end = NULL; |
||
825 | for (;;) { |
||
826 | if (rel < rel_end) { |
||
827 | int type = ELF32_R_TYPE(rel->r_info); |
||
828 | addr = rel->r_offset + s->sh_addr; |
||
829 | ++rel; |
||
830 | if (type != R_386_32) |
||
831 | continue; |
||
832 | if (count == 0) { /* new block */ |
||
833 | block_ptr = pe->reloc->data_offset; |
||
834 | section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header)); |
||
835 | offset = addr & 0xFFFFFFFF << 12; |
||
836 | } |
||
837 | if ((addr -= offset) < (1 << 12)) { /* one block spans 4k addresses */ |
||
838 | WORD *wp = section_ptr_add(pe->reloc, sizeof(WORD)); |
||
839 | *wp = addr | IMAGE_REL_BASED_HIGHLOW << 12; |
||
840 | ++count; |
||
841 | continue; |
||
842 | } |
||
843 | --rel; |
||
844 | } else if (i < section_count) { |
||
845 | sr = (s = pe->s1->sections[section_order[i++]])->reloc; |
||
846 | if (sr) { |
||
847 | rel = (Elf32_Rel *) sr->data; |
||
848 | rel_end = (Elf32_Rel *) (sr->data + sr->data_offset); |
||
849 | } |
||
850 | continue; |
||
851 | } |
||
852 | |||
853 | if (count) { /* store the last block and ready for a new one */ |
||
854 | struct pe_reloc_header *hdr; |
||
855 | if (count & 1) |
||
856 | section_ptr_add(pe->reloc, 2), ++count; |
||
857 | hdr = (struct pe_reloc_header *) (pe->reloc->data + block_ptr); |
||
858 | hdr->offset = offset - pe->imagebase; |
||
859 | hdr->size = |
||
860 | count * sizeof(WORD) + sizeof(struct pe_reloc_header); |
||
861 | count = 0; |
||
862 | } |
||
863 | if (rel >= rel_end) |
||
864 | break; |
||
865 | } |
||
866 | } |
||
867 | |||
868 | /* ------------------------------------------------------------- */ |
||
869 | ST int pe_assign_addresses(struct pe_info *pe) |
||
870 | { |
||
871 | int i, k, n; |
||
872 | DWORD addr; |
||
873 | int section_order[pe_sec_number]; |
||
874 | struct section_info *si_data = NULL; |
||
875 | |||
876 | pe->imagebase = PE_DLL == pe_type ? 0x10000000 : 0x00400000; |
||
877 | addr = pe->imagebase + 1; |
||
878 | |||
879 | if (PE_DLL == pe_type) |
||
880 | pe->reloc = new_section(pe->s1, ".reloc", SHT_DYNAMIC, SHF_ALLOC); |
||
881 | |||
882 | for (n = k = 0; n < pe_sec_number; ++n) { |
||
883 | for (i = 1; i < pe->s1->nb_sections; ++i) { |
||
884 | Section *s = pe->s1->sections[i]; |
||
885 | if (0 == strcmp(s->name, pe_sec_names[n])) { |
||
886 | struct section_info *si = &pe->sh_info[pe->sec_count]; |
||
887 | #ifdef PE_MERGE_DATA |
||
888 | if (n == sec_bss && si_data) { |
||
889 | /* append .bss to .data */ |
||
890 | s->sh_addr = addr = ((addr - 1) | 15) + 1; |
||
891 | addr += s->data_offset; |
||
892 | si_data->sh_size = addr - si_data->sh_addr; |
||
893 | } else |
||
894 | #endif |
||
895 | { |
||
896 | si->sh_addr = s->sh_addr = addr = |
||
897 | pe_virtual_align(addr); |
||
898 | si->id = n; |
||
899 | |||
900 | if (n == sec_data) { |
||
901 | pe->thunk = s; |
||
902 | si_data = si; |
||
903 | pe_build_imports(pe); |
||
904 | pe_build_exports(pe); |
||
905 | } else if (n == sec_reloc) { |
||
906 | pe_build_reloc(pe, section_order, k); |
||
907 | } |
||
908 | |||
909 | if (s->data_offset) { |
||
910 | if (n != sec_bss) { |
||
911 | si->data = s->data; |
||
912 | si->data_size = s->data_offset; |
||
913 | } |
||
914 | |||
915 | addr += s->data_offset; |
||
916 | si->sh_size = s->data_offset; |
||
917 | ++pe->sec_count; |
||
918 | } |
||
919 | //printf("Section %08X %04X %s\n", si->sh_addr, si->data_size, s->name); |
||
920 | } |
||
921 | section_order[k] = i, ++k; |
||
922 | } |
||
923 | } |
||
924 | } |
||
925 | return 0; |
||
926 | } |
||
927 | |||
928 | /*----------------------------------------------------------------------------*/ |
||
929 | ST int pe_check_symbols(struct pe_info *pe) |
||
930 | { |
||
931 | Elf32_Sym *sym; |
||
932 | int ret = 0; |
||
933 | |||
934 | pe_align_section(text_section, 8); |
||
935 | |||
936 | for_sym_in_symtab(sym) { |
||
937 | if (sym->st_shndx == SHN_UNDEF) { |
||
938 | const char *symbol = symtab_section->link->data + sym->st_name; |
||
939 | unsigned type = ELF32_ST_TYPE(sym->st_info); |
||
940 | int sym_index = pe_find_import(pe->s1, symbol, NULL); |
||
941 | if (sym_index) { |
||
942 | if (type == STT_FUNC) { |
||
943 | unsigned long offset = text_section->data_offset; |
||
944 | if (pe_add_import(pe, sym_index, offset + 2)) { |
||
945 | /* add the 'jmp IAT[x]' instruction */ |
||
946 | *(WORD *) section_ptr_add(text_section, 8) = |
||
947 | 0x25FF; |
||
948 | /* patch the symbol */ |
||
949 | sym->st_shndx = text_section->sh_num; |
||
950 | sym->st_value = offset; |
||
951 | continue; |
||
952 | } |
||
953 | } else if (type == STT_OBJECT) { /* data, ptr to that should be */ |
||
954 | if (pe_add_import(pe, sym_index, |
||
955 | (sym - |
||
956 | (Elf32_Sym *) symtab_section->data) | |
||
957 | 0x80000000)) |
||
958 | continue; |
||
959 | } |
||
960 | } |
||
961 | error_noabort("undefined symbol '%s'", symbol); |
||
962 | ret = 1; |
||
963 | } else |
||
964 | if (pe->s1->rdynamic |
||
965 | && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) { |
||
966 | /* if -rdynamic option, then export all non local symbols */ |
||
967 | sym->st_other |= 1; |
||
968 | } |
||
969 | } |
||
970 | return ret; |
||
971 | } |
||
972 | |||
973 | /*----------------------------------------------------------------------------*/ |
||
974 | #ifdef PE_PRINT_SECTIONS |
||
975 | ST void pe_print_section(FILE * f, Section * s) |
||
976 | { /* just if you'r curious */ |
||
977 | BYTE *p, *e, b; |
||
978 | int i, n, l, m; |
||
979 | p = s->data; |
||
980 | e = s->data + s->data_offset; |
||
981 | l = e - p; |
||
982 | |||
983 | fprintf(f, "section \"%s\"", s->name); |
||
984 | if (s->link) |
||
985 | fprintf(f, "\nlink \"%s\"", s->link->name); |
||
986 | if (s->reloc) |
||
987 | fprintf(f, "\nreloc \"%s\"", s->reloc->name); |
||
988 | fprintf(f, "\nv_addr %08X", s->sh_addr); |
||
989 | fprintf(f, "\ncontents %08X", l); |
||
990 | fprintf(f, "\n\n"); |
||
991 | |||
992 | if (s->sh_type == SHT_NOBITS) |
||
993 | return; |
||
994 | |||
995 | if (s->sh_type == SHT_SYMTAB) |
||
996 | m = sizeof(Elf32_Sym); |
||
997 | if (s->sh_type == SHT_REL) |
||
998 | m = sizeof(Elf32_Rel); |
||
999 | else |
||
1000 | m = 16; |
||
1001 | |||
1002 | for (i = 0; i < l;) { |
||
1003 | fprintf(f, "%08X", i); |
||
1004 | for (n = 0; n < m; ++n) { |
||
1005 | if (n + i < l) |
||
1006 | fprintf(f, " %02X", p[i + n]); |
||
1007 | else |
||
1008 | fprintf(f, " "); |
||
1009 | } |
||
1010 | |||
1011 | if (s->sh_type == SHT_SYMTAB) { |
||
1012 | Elf32_Sym *sym = (Elf32_Sym *) (p + i); |
||
1013 | const char *name = s->link->data + sym->st_name; |
||
1014 | fprintf(f, |
||
1015 | " name:%04X" |
||
1016 | " value:%04X" |
||
1017 | " size:%04X" |
||
1018 | " bind:%02X" |
||
1019 | " type:%02X" |
||
1020 | " other:%02X" |
||
1021 | " shndx:%04X" |
||
1022 | " \"%s\"", |
||
1023 | sym->st_name, |
||
1024 | sym->st_value, |
||
1025 | sym->st_size, |
||
1026 | ELF32_ST_BIND(sym->st_info), |
||
1027 | ELF32_ST_TYPE(sym->st_info), |
||
1028 | sym->st_other, sym->st_shndx, name); |
||
1029 | } else if (s->sh_type == SHT_REL) { |
||
1030 | Elf32_Rel *rel = (Elf32_Rel *) (p + i); |
||
1031 | Elf32_Sym *sym = |
||
1032 | (Elf32_Sym *) s->link->data + ELF32_R_SYM(rel->r_info); |
||
1033 | const char *name = s->link->link->data + sym->st_name; |
||
1034 | fprintf(f, |
||
1035 | " offset:%04X" |
||
1036 | " type:%02X" |
||
1037 | " symbol:%04X" |
||
1038 | " \"%s\"", |
||
1039 | rel->r_offset, |
||
1040 | ELF32_R_TYPE(rel->r_info), |
||
1041 | ELF32_R_SYM(rel->r_info), name); |
||
1042 | } else { |
||
1043 | fprintf(f, " "); |
||
1044 | for (n = 0; n < m; ++n) { |
||
1045 | if (n + i < l) { |
||
1046 | b = p[i + n]; |
||
1047 | if (b < 32 || b >= 127) |
||
1048 | b = '.'; |
||
1049 | fprintf(f, "%c", b); |
||
1050 | } |
||
1051 | } |
||
1052 | } |
||
1053 | i += m; |
||
1054 | fprintf(f, "\n"); |
||
1055 | } |
||
1056 | fprintf(f, "\n\n"); |
||
1057 | } |
||
1058 | #endif |
||
1059 | |||
1060 | static int pe_test_cmd(const char **pp, const char *cmd) |
||
1061 | { |
||
1062 | const char *p; |
||
1063 | char *q, buf[16]; |
||
1064 | int ret; |
||
1065 | |||
1066 | p = *pp; |
||
1067 | q = buf; |
||
1068 | while (*p != '\0' && !is_space(*p)) { |
||
1069 | if ((q - buf) < sizeof(buf) - 1) |
||
1070 | *q++ = toup(*p); |
||
1071 | p++; |
||
1072 | } |
||
1073 | *q = '\0'; |
||
1074 | ret = !strcmp(buf, cmd); |
||
1075 | *pp = p; |
||
1076 | return ret; |
||
1077 | } |
||
1078 | |||
1079 | /* ------------------------------------------------------------- */ |
||
1080 | int pe_load_def_file(TCCState * s1, FILE * fp) |
||
1081 | { |
||
1082 | DLLReference *dllref; |
||
1083 | int f = 0, sym_index; |
||
1084 | char *p, line[120], dllname[40]; |
||
1085 | while (fgets(line, sizeof line, fp)) { |
||
609 | andrew_pro | 1086 | //p = strchr(line, 0); |
145 | halyavin | 1087 | while (p > line && p[-1] <= ' ') |
1088 | --p; |
||
1089 | *p = 0; |
||
1090 | p = line; |
||
1091 | while (*p && *p <= ' ') |
||
1092 | ++p; |
||
1093 | |||
1094 | if (*p && ';' != *p) |
||
1095 | switch (f) { |
||
1096 | case 0: |
||
1097 | if (!pe_test_cmd((const char **)&p, "LIBRARY")) |
||
1098 | return -1; |
||
1099 | while (is_space(*p)) |
||
1100 | p++; |
||
1101 | pstrcpy(dllname, sizeof(dllname), p); |
||
1102 | ++f; |
||
1103 | continue; |
||
1104 | |||
1105 | case 1: |
||
1106 | if (!pe_test_cmd((const char **)&p, "EXPORTS")) |
||
1107 | return -1; |
||
1108 | ++f; |
||
1109 | continue; |
||
1110 | |||
1111 | case 2: |
||
1112 | dllref = |
||
1113 | tcc_malloc(sizeof(DLLReference) + strlen(dllname)); |
||
1114 | strcpy(dllref->name, dllname); |
||
1115 | dllref->level = 0; |
||
1116 | dynarray_add((void ***) &s1->loaded_dlls, |
||
1117 | &s1->nb_loaded_dlls, dllref); |
||
1118 | ++f; |
||
1119 | |||
1120 | default: |
||
1121 | /* tccpe needs to know from what dll it should import |
||
1122 | the sym */ |
||
1123 | sym_index = add_elf_sym(s1->dynsymtab_section, |
||
1124 | 0, 0, ELF32_ST_INFO(STB_GLOBAL, |
||
1125 | STT_FUNC), |
||
1126 | s1->nb_loaded_dlls - 1, |
||
1127 | text_section->sh_num, p); |
||
1128 | continue; |
||
1129 | } |
||
1130 | } |
||
1131 | return 0; |
||
1132 | } |
||
1133 | |||
1134 | /* ------------------------------------------------------------- */ |
||
1135 | void pe_guess_outfile(char *objfilename, int output_type) |
||
1136 | { |
||
1137 | char *ext = strrchr(objfilename, '.'); |
||
1138 | if (NULL == ext) |
||
609 | andrew_pro | 1139 | //ext = strchr(objfilename, 0); |
145 | halyavin | 1140 | if (output_type == TCC_OUTPUT_DLL) |
1141 | strcpy(ext, ".dll"); |
||
1142 | else |
||
1143 | if (output_type == TCC_OUTPUT_EXE) |
||
1144 | strcpy(ext, ".exe"); |
||
1145 | else |
||
1146 | if (output_type == TCC_OUTPUT_OBJ && strcmp(ext, ".o")) |
||
1147 | strcpy(ext, ".o"); |
||
1148 | else |
||
1149 | error("no outputfile given"); |
||
1150 | } |
||
1151 | |||
1152 | /* ------------------------------------------------------------- */ |
||
1153 | unsigned long pe_add_runtime(TCCState * s1) |
||
1154 | { |
||
1155 | const char *start_symbol; |
||
1156 | unsigned long addr; |
||
1157 | |||
1158 | if (find_elf_sym(symtab_section, "WinMain")) |
||
1159 | pe_type = PE_GUI; |
||
1160 | else |
||
1161 | if (TCC_OUTPUT_DLL == s1->output_type) |
||
1162 | { |
||
1163 | pe_type = PE_DLL; |
||
1164 | // need this for 'tccelf.c:relocate_section()' |
||
1165 | s1->output_type = TCC_OUTPUT_EXE; |
||
1166 | } |
||
1167 | |||
1168 | start_symbol = |
||
1169 | TCC_OUTPUT_MEMORY == s1->output_type |
||
1170 | ? PE_GUI == pe_type ? "_runwinmain" : NULL |
||
1171 | : PE_DLL == pe_type ? "_dllstart" |
||
1172 | : PE_GUI == pe_type ? "_winstart" : "_start"; |
||
1173 | |||
1174 | /* grab the startup code from libtcc1 */ |
||
1175 | if (start_symbol) |
||
1176 | add_elf_sym(symtab_section, |
||
1177 | 0, 0, |
||
1178 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
||
1179 | SHN_UNDEF, start_symbol); |
||
1180 | |||
1181 | if (0 == s1->nostdlib) { |
||
1182 | tcc_add_library(s1, "tcc1"); |
||
1183 | tcc_add_library(s1, "msvcrt"); |
||
1184 | if (PE_DLL == pe_type || PE_GUI == pe_type) { |
||
1185 | tcc_add_library(s1, "kernel32"); |
||
1186 | tcc_add_library(s1, "user32"); |
||
1187 | tcc_add_library(s1, "gdi32"); |
||
1188 | } |
||
1189 | } |
||
1190 | |||
1191 | addr = start_symbol ? |
||
1192 | (unsigned long) tcc_get_symbol_err(s1, start_symbol) : 0; |
||
1193 | |||
1194 | if (s1->output_type == TCC_OUTPUT_MEMORY && addr) { |
||
1195 | /* for -run GUI's, put '_runwinmain' instead of 'main' */ |
||
1196 | add_elf_sym(symtab_section, |
||
1197 | addr, 0, |
||
1198 | ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, |
||
1199 | text_section->sh_num, "main"); |
||
1200 | |||
1201 | /* FreeConsole(); */ |
||
1202 | } |
||
1203 | return addr; |
||
1204 | } |
||
1205 | |||
1206 | int tcc_output_pe(TCCState * s1, const char *filename) |
||
1207 | { |
||
1208 | int ret; |
||
1209 | struct pe_info pe; |
||
1210 | int i; |
||
1211 | memset(&pe, 0, sizeof pe); |
||
1212 | pe.filename = filename; |
||
1213 | pe.s1 = s1; |
||
1214 | pe.start_addr = pe_add_runtime(s1); |
||
1215 | |||
1216 | relocate_common_syms(); /* assign bss adresses */ |
||
1217 | ret = pe_check_symbols(&pe); |
||
1218 | if (0 == ret) { |
||
1219 | pe_assign_addresses(&pe); |
||
1220 | relocate_syms(s1, 0); |
||
1221 | for (i = 1; i < s1->nb_sections; ++i) { |
||
1222 | Section *s = s1->sections[i]; |
||
1223 | if (s->reloc) |
||
1224 | relocate_section(s1, s); |
||
1225 | } |
||
1226 | ret = pe_write_pe(&pe); |
||
1227 | } |
||
1228 | #ifdef PE_PRINT_SECTIONS |
||
1229 | { |
||
1230 | Section *s; |
||
1231 | FILE *f; |
||
1232 | f = fopen("tccpe.log", "wt"); |
||
1233 | for (i = 1; i < s1->nb_sections; ++i) { |
||
1234 | s = s1->sections[i]; |
||
1235 | pe_print_section(f, s); |
||
1236 | } |
||
1237 | pe_print_section(f, s1->dynsymtab_section); |
||
1238 | fclose(f); |
||
1239 | } |
||
1240 | #endif |
||
1241 | return ret; |
||
1242 | } |
||
1243 | |||
1244 | /*----------------------------------------------------------------------------*/>>=>=>>>>>>>>>>>><>><>>><>>>>=>>>-->>>=>>>>>> |