1 /*
2  *  TCCPE.C - PE file output for the Tiny C Compiler
3  *
4  *  Copyright (c) 2005-2007 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 #ifdef TCC_TARGET_PE
22 
23 #define ST_FN static
24 #define ST_DATA static
25 #define PUB_FN
26 
27 #ifndef _WIN32
28 #define stricmp strcasecmp
29 #define strnicmp strncasecmp
30 #endif
31 
32 #ifndef MAX_PATH
33 #define MAX_PATH 260
34 #endif
35 
36 #define PE_MERGE_DATA
37 // #define PE_PRINT_SECTIONS
38 
39 /* ----------------------------------------------------------- */
40 #ifndef IMAGE_NT_SIGNATURE
41 /* ----------------------------------------------------------- */
42 /* definitions below are from winnt.h */
43 
44 typedef unsigned char BYTE;
45 typedef unsigned short WORD;
46 typedef unsigned long DWORD;
47 #pragma pack(push, 1)
48 
49 typedef struct _IMAGE_DOS_HEADER {  /* DOS .EXE header */
50     WORD e_magic;         /* Magic number */
51     WORD e_cblp;          /* Bytes on last page of file */
52     WORD e_cp;            /* Pages in file */
53     WORD e_crlc;          /* Relocations */
54     WORD e_cparhdr;       /* Size of header in paragraphs */
55     WORD e_minalloc;      /* Minimum extra paragraphs needed */
56     WORD e_maxalloc;      /* Maximum extra paragraphs needed */
57     WORD e_ss;            /* Initial (relative) SS value */
58     WORD e_sp;            /* Initial SP value */
59     WORD e_csum;          /* Checksum */
60     WORD e_ip;            /* Initial IP value */
61     WORD e_cs;            /* Initial (relative) CS value */
62     WORD e_lfarlc;        /* File address of relocation table */
63     WORD e_ovno;          /* Overlay number */
64     WORD e_res[4];        /* Reserved words */
65     WORD e_oemid;         /* OEM identifier (for e_oeminfo) */
66     WORD e_oeminfo;       /* OEM information; e_oemid specific */
67     WORD e_res2[10];      /* Reserved words */
68     DWORD e_lfanew;        /* File address of new exe header */
69 } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
70 
71 #define IMAGE_NT_SIGNATURE  0x00004550  /* PE00 */
72 #define SIZE_OF_NT_SIGNATURE 4
73 
74 typedef struct _IMAGE_FILE_HEADER {
75     WORD    Machine;
76     WORD    NumberOfSections;
77     DWORD   TimeDateStamp;
78     DWORD   PointerToSymbolTable;
79     DWORD   NumberOfSymbols;
80     WORD    SizeOfOptionalHeader;
81     WORD    Characteristics;
82 } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
83 
84 
85 #define IMAGE_SIZEOF_FILE_HEADER 20
86 
87 typedef struct _IMAGE_DATA_DIRECTORY {
88     DWORD   VirtualAddress;
89     DWORD   Size;
90 } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
91 
92 
93 typedef struct _IMAGE_OPTIONAL_HEADER {
94     /* Standard fields. */
95     WORD    Magic;
96     BYTE    MajorLinkerVersion;
97     BYTE    MinorLinkerVersion;
98     DWORD   SizeOfCode;
99     DWORD   SizeOfInitializedData;
100     DWORD   SizeOfUninitializedData;
101     DWORD   AddressOfEntryPoint;
102     DWORD   BaseOfCode;
103     DWORD   BaseOfData;
104 
105     /* NT additional fields. */
106     DWORD   ImageBase;
107     DWORD   SectionAlignment;
108     DWORD   FileAlignment;
109     WORD    MajorOperatingSystemVersion;
110     WORD    MinorOperatingSystemVersion;
111     WORD    MajorImageVersion;
112     WORD    MinorImageVersion;
113     WORD    MajorSubsystemVersion;
114     WORD    MinorSubsystemVersion;
115     DWORD   Win32VersionValue;
116     DWORD   SizeOfImage;
117     DWORD   SizeOfHeaders;
118     DWORD   CheckSum;
119     WORD    Subsystem;
120     WORD    DllCharacteristics;
121     DWORD   SizeOfStackReserve;
122     DWORD   SizeOfStackCommit;
123     DWORD   SizeOfHeapReserve;
124     DWORD   SizeOfHeapCommit;
125     DWORD   LoaderFlags;
126     DWORD   NumberOfRvaAndSizes;
127     IMAGE_DATA_DIRECTORY DataDirectory[16];
128 
129 } IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
130 
131 
132 #define IMAGE_DIRECTORY_ENTRY_EXPORT          0   /* Export Directory */
133 #define IMAGE_DIRECTORY_ENTRY_IMPORT          1   /* Import Directory */
134 #define IMAGE_DIRECTORY_ENTRY_RESOURCE        2   /* Resource Directory */
135 #define IMAGE_DIRECTORY_ENTRY_EXCEPTION       3   /* Exception Directory */
136 #define IMAGE_DIRECTORY_ENTRY_SECURITY        4   /* Security Directory */
137 #define IMAGE_DIRECTORY_ENTRY_BASERELOC       5   /* Base Relocation Table */
138 #define IMAGE_DIRECTORY_ENTRY_DEBUG           6   /* Debug Directory */
139 /*      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7      (X86 usage) */
140 #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE    7   /* Architecture Specific Data */
141 #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR       8   /* RVA of GP */
142 #define IMAGE_DIRECTORY_ENTRY_TLS             9   /* TLS Directory */
143 #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    10   /* Load Configuration Directory */
144 #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   11   /* Bound Import Directory in headers */
145 #define IMAGE_DIRECTORY_ENTRY_IAT            12   /* Import Address Table */
146 #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   13   /* Delay Load Import Descriptors */
147 #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14   /* COM Runtime descriptor */
148 
149 /* Section header format. */
150 #define IMAGE_SIZEOF_SHORT_NAME         8
151 
152 typedef struct _IMAGE_SECTION_HEADER {
153     BYTE    Name[IMAGE_SIZEOF_SHORT_NAME];
154     union {
155             DWORD   PhysicalAddress;
156             DWORD   VirtualSize;
157     } Misc;
158     DWORD   VirtualAddress;
159     DWORD   SizeOfRawData;
160     DWORD   PointerToRawData;
161     DWORD   PointerToRelocations;
162     DWORD   PointerToLinenumbers;
163     WORD    NumberOfRelocations;
164     WORD    NumberOfLinenumbers;
165     DWORD   Characteristics;
166 } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
167 
168 #define IMAGE_SIZEOF_SECTION_HEADER     40
169 
170 typedef struct _IMAGE_BASE_RELOCATION {
171     DWORD   VirtualAddress;
172     DWORD   SizeOfBlock;
173 //  WORD    TypeOffset[1];
174 } IMAGE_BASE_RELOCATION;
175 
176 #define IMAGE_SIZEOF_BASE_RELOCATION     8
177 
178 #define IMAGE_REL_BASED_ABSOLUTE         0
179 #define IMAGE_REL_BASED_HIGH             1
180 #define IMAGE_REL_BASED_LOW              2
181 #define IMAGE_REL_BASED_HIGHLOW          3
182 #define IMAGE_REL_BASED_HIGHADJ          4
183 #define IMAGE_REL_BASED_MIPS_JMPADDR     5
184 #define IMAGE_REL_BASED_SECTION          6
185 #define IMAGE_REL_BASED_REL32            7
186 
187 #pragma pack(pop)
188 
189 /* ----------------------------------------------------------- */
190 #endif /* ndef IMAGE_NT_SIGNATURE */
191 /* ----------------------------------------------------------- */
192 
193 #pragma pack(push, 1)
194 
195 struct pe_header
196 {
197     IMAGE_DOS_HEADER doshdr;
198     BYTE dosstub[0x40];
199     DWORD nt_sig;
200     IMAGE_FILE_HEADER filehdr;
201     IMAGE_OPTIONAL_HEADER opthdr;
202 };
203 
204 struct pe_import_header {
205     DWORD first_entry;
206     DWORD time_date;
207     DWORD forwarder;
208     DWORD lib_name_offset;
209     DWORD first_thunk;
210 };
211 
212 struct pe_export_header {
213     DWORD Characteristics;
214     DWORD TimeDateStamp;
215     DWORD Version;
216     DWORD Name;
217     DWORD Base;
218     DWORD NumberOfFunctions;
219     DWORD NumberOfNames;
220     DWORD AddressOfFunctions;
221     DWORD AddressOfNames;
222     DWORD AddressOfNameOrdinals;
223 };
224 
225 struct pe_reloc_header {
226     DWORD offset;
227     DWORD size;
228 };
229 
230 struct pe_rsrc_header {
231     struct _IMAGE_FILE_HEADER filehdr;
232     struct _IMAGE_SECTION_HEADER sectionhdr;
233 };
234 
235 struct pe_rsrc_reloc {
236     DWORD offset;
237     DWORD size;
238     WORD type;
239 };
240 
241 #pragma pack(pop)
242 
243 /* ----------------------------------------------------------- */
244 ST_DATA struct pe_header pe_header = {
245 {
246     /* IMAGE_DOS_HEADER doshdr */
247     0x5A4D, /*WORD e_magic;         Magic number */
248     0x0090, /*WORD e_cblp;          Bytes on last page of file */
249     0x0003, /*WORD e_cp;            Pages in file */
250     0x0000, /*WORD e_crlc;          Relocations */
251 
252     0x0004, /*WORD e_cparhdr;       Size of header in paragraphs */
253     0x0000, /*WORD e_minalloc;      Minimum extra paragraphs needed */
254     0xFFFF, /*WORD e_maxalloc;      Maximum extra paragraphs needed */
255     0x0000, /*WORD e_ss;            Initial (relative) SS value */
256 
257     0x00B8, /*WORD e_sp;            Initial SP value */
258     0x0000, /*WORD e_csum;          Checksum */
259     0x0000, /*WORD e_ip;            Initial IP value */
260     0x0000, /*WORD e_cs;            Initial (relative) CS value */
261     0x0040, /*WORD e_lfarlc;        File address of relocation table */
262     0x0000, /*WORD e_ovno;          Overlay number */
263     {0,0,0,0}, /*WORD e_res[4];     Reserved words */
264     0x0000, /*WORD e_oemid;         OEM identifier (for e_oeminfo) */
265     0x0000, /*WORD e_oeminfo;       OEM information; e_oemid specific */
266     {0,0,0,0,0,0,0,0,0,0}, /*WORD e_res2[10];      Reserved words */
267     0x00000080  /*DWORD   e_lfanew;        File address of new exe header */
268 },{
269     /* BYTE dosstub[0x40] */
270     /* 14 code bytes + "This program cannot be run in DOS mode.\r\r\n$" + 6 * 0x00 */
271     0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd,0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,
272     0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,
273     0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,
274     0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
275 },
276     0x00004550, /* DWORD nt_sig = IMAGE_NT_SIGNATURE */
277 {
278     /* IMAGE_FILE_HEADER filehdr */
279     0x014C, /*WORD    Machine; */
280     0x0003, /*WORD    NumberOfSections; */
281     0x00000000, /*DWORD   TimeDateStamp; */
282     0x00000000, /*DWORD   PointerToSymbolTable; */
283     0x00000000, /*DWORD   NumberOfSymbols; */
284     0x00E0, /*WORD    SizeOfOptionalHeader; */
285     0x030F  /*WORD    Characteristics; */
286 },{
287     /* IMAGE_OPTIONAL_HEADER opthdr */
288     /* Standard fields. */
289     0x010B, /*WORD    Magic; */
290     0x06, /*BYTE    MajorLinkerVersion; */
291     0x00, /*BYTE    MinorLinkerVersion; */
292     0x00000000, /*DWORD   SizeOfCode; */
293     0x00000000, /*DWORD   SizeOfInitializedData; */
294     0x00000000, /*DWORD   SizeOfUninitializedData; */
295     0x00000000, /*DWORD   AddressOfEntryPoint; */
296     0x00000000, /*DWORD   BaseOfCode; */
297     0x00000000, /*DWORD   BaseOfData; */
298 
299     /* NT additional fields. */
300     0x00400000, /*DWORD   ImageBase; */
301     0x00001000, /*DWORD   SectionAlignment; */
302     0x00000200, /*DWORD   FileAlignment; */
303     0x0004, /*WORD    MajorOperatingSystemVersion; */
304     0x0000, /*WORD    MinorOperatingSystemVersion; */
305     0x0000, /*WORD    MajorImageVersion; */
306     0x0000, /*WORD    MinorImageVersion; */
307     0x0004, /*WORD    MajorSubsystemVersion; */
308     0x0000, /*WORD    MinorSubsystemVersion; */
309     0x00000000, /*DWORD   Win32VersionValue; */
310     0x00000000, /*DWORD   SizeOfImage; */
311     0x00000200, /*DWORD   SizeOfHeaders; */
312     0x00000000, /*DWORD   CheckSum; */
313     0x0002, /*WORD    Subsystem; */
314     0x0000, /*WORD    DllCharacteristics; */
315     0x00100000, /*DWORD   SizeOfStackReserve; */
316     0x00001000, /*DWORD   SizeOfStackCommit; */
317     0x00100000, /*DWORD   SizeOfHeapReserve; */
318     0x00001000, /*DWORD   SizeOfHeapCommit; */
319     0x00000000, /*DWORD   LoaderFlags; */
320     0x00000010, /*DWORD   NumberOfRvaAndSizes; */
321 
322     /* IMAGE_DATA_DIRECTORY DataDirectory[16]; */
323     {{0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0},
324      {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}}
325 }};
326 
327 /* ------------------------------------------------------------- */
328 /* internal temporary structures */
329 
330 /*
331 #define IMAGE_SCN_CNT_CODE                  0x00000020
332 #define IMAGE_SCN_CNT_INITIALIZED_DATA      0x00000040
333 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA    0x00000080
334 #define IMAGE_SCN_MEM_DISCARDABLE           0x02000000
335 #define IMAGE_SCN_MEM_SHARED                0x10000000
336 #define IMAGE_SCN_MEM_EXECUTE               0x20000000
337 #define IMAGE_SCN_MEM_READ                  0x40000000
338 #define IMAGE_SCN_MEM_WRITE                 0x80000000
339 */
340 
341 enum {
342     sec_text = 0,
343     sec_data ,
344     sec_bss ,
345     sec_idata ,
346     sec_rsrc ,
347     sec_stab ,
348     sec_reloc ,
349 
350     sec_last
351 };
352 
353 ST_DATA DWORD pe_sec_flags[] = {
354     0x60000020, /* ".text"     , */
355     0xC0000040, /* ".data"     , */
356     0xC0000080, /* ".bss"      , */
357     0x40000040, /* ".idata"    , */
358     0x40000040, /* ".rsrc"     , */
359     0x42000802, /* ".stab"     , */
360     0x42000040, /* ".reloc"    , */
361 };
362 
363 struct section_info {
364     int cls, ord;
365     char name[32];
366     DWORD sh_addr;
367     DWORD sh_size;
368     DWORD sh_flags;
369     unsigned char *data;
370     DWORD data_size;
371     IMAGE_SECTION_HEADER ish;
372 };
373 
374 struct import_symbol {
375     int sym_index;
376     int iat_index;
377     int thk_offset;
378 };
379 
380 struct pe_import_info {
381     int dll_index;
382     int sym_count;
383     struct import_symbol **symbols;
384 };
385 
386 struct pe_info {
387     TCCState *s1;
388     Section *reloc;
389     Section *thunk;
390     const char *filename;
391     int type;
392     DWORD sizeofheaders;
393     DWORD imagebase;
394     DWORD start_addr;
395     DWORD imp_offs;
396     DWORD imp_size;
397     DWORD iat_offs;
398     DWORD iat_size;
399     DWORD exp_offs;
400     DWORD exp_size;
401     struct section_info *sec_info;
402     int sec_count;
403     struct pe_import_info **imp_info;
404     int imp_count;
405 };
406 
407 /* ------------------------------------------------------------- */
408 
409 #define PE_NUL 0
410 #define PE_DLL 1
411 #define PE_GUI 2
412 #define PE_EXE 3
413 
414 void error_noabort(const char *, ...);
415 
416 #ifdef _WIN32
dbg_printf(const char * fmt,...)417 void dbg_printf (const char *fmt, ...)
418 {
419     char buffer[4000];
420     va_list arg;
421     int x;
422     va_start(arg, fmt);
423     x = vsprintf (buffer, fmt, arg);
424     strcpy(buffer+x, "\n");
425     OutputDebugString(buffer);
426 }
427 #endif
428 
429 /* --------------------------------------------*/
430 
get_alt_symbol(char * buffer,const char * symbol)431 ST_FN const char* get_alt_symbol(char *buffer, const char *symbol)
432 {
433     const char *p;
434     p = strrchr(symbol, '@');
435     if (p && isnum(p[1]) && symbol[0] == '_') { /* stdcall decor */
436         strcpy(buffer, symbol+1)[p-symbol-1] = 0;
437     } else if (symbol[0] != '_') { /* try non-ansi function */
438         buffer[0] = '_', strcpy(buffer + 1, symbol);
439     } else if (0 == memcmp(symbol, "__imp__", 7)) { /* mingw 2.0 */
440         strcpy(buffer, symbol + 6);
441     } else if (0 == memcmp(symbol, "_imp___", 7)) { /* mingw 3.7 */
442         strcpy(buffer, symbol + 6);
443     } else {
444         return symbol;
445     }
446     return buffer;
447 }
448 
pe_find_import(TCCState * s1,const char * symbol)449 ST_FN int pe_find_import(TCCState * s1, const char *symbol)
450 {
451     char buffer[200];
452     const char *s;
453     int sym_index, n = 0;
454     do {
455         s = n ? get_alt_symbol(buffer, symbol) : symbol;
456         sym_index = find_elf_sym(s1->dynsymtab_section, s);
457         // printf("find %d %s\n", sym_index, s);
458     } while (0 == sym_index && ++n < 2);
459     return sym_index;
460 }
461 
462 #if defined _WIN32 || defined __CYGWIN__
463 
464 #ifdef __CYGWIN__
465 # include <dlfcn.h>
466 # define LoadLibrary(s) dlopen(s, RTLD_NOW)
467 # define GetProcAddress(h,s) dlsym(h, s)
468 #endif
469 
470 /* for the -run option: dynamically load symbol from dll */
resolve_sym(struct TCCState * s1,const char * symbol,int type)471 void *resolve_sym(struct TCCState *s1, const char *symbol, int type)
472 {
473     char buffer[100];
474     int sym_index, dll_index;
475     void *hModule, *addr, **m;
476 
477     sym_index = pe_find_import(s1, symbol);
478     if (0 == sym_index)
479         return NULL;
480     dll_index = ((Elf32_Sym *)s1->dynsymtab_section->data + sym_index)->st_value;
481     hModule = LoadLibrary(s1->loaded_dlls[dll_index-1]->name);
482     addr = GetProcAddress(hModule, symbol);
483     if (NULL == addr)
484         addr = GetProcAddress(hModule, get_alt_symbol(buffer, symbol));
485 
486     if (addr && STT_OBJECT == type) {
487         /* need to return a pointer to the address for data objects */
488         m = (void**)tcc_malloc(sizeof addr), *m = addr, addr = m;
489 #ifdef MEM_DEBUG
490         /* yep, we don't free it */
491         mem_cur_size -= sizeof (void*);
492 #endif
493     }
494     return addr;
495 }
496 #endif
497 
498 /*----------------------------------------------------------------------------*/
499 
dynarray_assoc(void ** pp,int n,int key)500 ST_FN int dynarray_assoc(void **pp, int n, int key)
501 {
502     int i;
503     for (i = 0; i < n; ++i, ++pp)
504     if (key == **(int **) pp)
505         return i;
506     return -1;
507 }
508 
509 #if 0
510 ST_FN DWORD umin(DWORD a, DWORD b)
511 {
512     return a < b ? a : b;
513 }
514 #endif
515 
umax(DWORD a,DWORD b)516 ST_FN DWORD umax(DWORD a, DWORD b)
517 {
518     return a < b ? b : a;
519 }
520 
pe_fpad(FILE * fp,DWORD new_pos)521 ST_FN void pe_fpad(FILE *fp, DWORD new_pos)
522 {
523     DWORD pos = ftell(fp);
524     while (++pos <= new_pos)
525         fputc(0, fp);
526 }
527 
pe_file_align(DWORD n)528 ST_FN DWORD pe_file_align(DWORD n)
529 {
530     return (n + (0x200 - 1)) & ~(0x200 - 1);
531 }
532 
pe_virtual_align(DWORD n)533 ST_FN DWORD pe_virtual_align(DWORD n)
534 {
535     return (n + (0x1000 - 1)) & ~(0x1000 - 1);
536 }
537 
pe_align_section(Section * s,int a)538 ST_FN void pe_align_section(Section *s, int a)
539 {
540     int i = s->data_offset & (a-1);
541     if (i)
542         section_ptr_add(s, a - i);
543 }
544 
pe_set_datadir(int dir,DWORD addr,DWORD size)545 ST_FN void pe_set_datadir(int dir, DWORD addr, DWORD size)
546 {
547     pe_header.opthdr.DataDirectory[dir].VirtualAddress = addr;
548     pe_header.opthdr.DataDirectory[dir].Size = size;
549 }
550 
551 /*----------------------------------------------------------------------------*/
pe_write(struct pe_info * pe)552 ST_FN int pe_write(struct pe_info *pe)
553 {
554     int i;
555     FILE *op;
556     DWORD file_offset, r;
557 
558     op = fopen(pe->filename, "wb");
559     if (NULL == op) {
560         error_noabort("could not write '%s': %s", pe->filename, strerror(errno));
561         return 1;
562     }
563 
564     pe->sizeofheaders = pe_file_align(
565         sizeof pe_header
566         + pe->sec_count * sizeof (IMAGE_SECTION_HEADER)
567         );
568 
569     file_offset = pe->sizeofheaders;
570     pe_fpad(op, file_offset);
571 
572     if (2 == verbose)
573         printf("-------------------------------"
574                "\n  virt   file   size  section" "\n");
575 
576     for (i = 0; i < pe->sec_count; ++i) {
577         struct section_info *si = pe->sec_info + i;
578         const char *sh_name = si->name;
579         unsigned long addr = si->sh_addr - pe->imagebase;
580         unsigned long size = si->sh_size;
581         IMAGE_SECTION_HEADER *psh = &si->ish;
582 
583         if (2 == verbose)
584             printf("%6lx %6lx %6lx  %s\n",
585                 addr, file_offset, size, sh_name);
586 
587         switch (si->cls) {
588             case sec_text:
589                 pe_header.opthdr.BaseOfCode = addr;
590                 pe_header.opthdr.AddressOfEntryPoint = addr + pe->start_addr;
591                 break;
592 
593             case sec_data:
594                 pe_header.opthdr.BaseOfData = addr;
595                 break;
596 
597             case sec_bss:
598                 break;
599 
600             case sec_reloc:
601                 pe_set_datadir(IMAGE_DIRECTORY_ENTRY_BASERELOC, addr, size);
602                 break;
603 
604             case sec_rsrc:
605                 pe_set_datadir(IMAGE_DIRECTORY_ENTRY_RESOURCE, addr, size);
606                 break;
607 
608             case sec_stab:
609                 break;
610         }
611 
612         if (pe->thunk == pe->s1->sections[si->ord]) {
613             if (pe->imp_size) {
614                 pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IMPORT,
615                     pe->imp_offs + addr, pe->imp_size);
616                 pe_set_datadir(IMAGE_DIRECTORY_ENTRY_IAT,
617                     pe->iat_offs + addr, pe->iat_size);
618             }
619             if (pe->exp_size) {
620                 pe_set_datadir(IMAGE_DIRECTORY_ENTRY_EXPORT,
621                     pe->exp_offs + addr, pe->exp_size);
622             }
623         }
624 
625         strcpy((char*)psh->Name, sh_name);
626 
627         psh->Characteristics = pe_sec_flags[si->cls];
628         psh->VirtualAddress = addr;
629         psh->Misc.VirtualSize = size;
630         pe_header.opthdr.SizeOfImage =
631             umax(pe_virtual_align(size + addr), pe_header.opthdr.SizeOfImage);
632 
633         if (si->data_size) {
634             psh->PointerToRawData = r = file_offset;
635             fwrite(si->data, 1, si->data_size, op);
636             file_offset = pe_file_align(file_offset + si->data_size);
637             psh->SizeOfRawData = file_offset - r;
638             pe_fpad(op, file_offset);
639         }
640     }
641 
642     // pe_header.filehdr.TimeDateStamp = time(NULL);
643     pe_header.filehdr.NumberOfSections = pe->sec_count;
644     pe_header.opthdr.SizeOfHeaders = pe->sizeofheaders;
645     pe_header.opthdr.ImageBase = pe->imagebase;
646     if (PE_DLL == pe->type)
647         pe_header.filehdr.Characteristics = 0x230E;
648     else if (PE_GUI != pe->type)
649         pe_header.opthdr.Subsystem = 3;
650 
651     fseek(op, SEEK_SET, 0);
652     fwrite(&pe_header,  1, sizeof pe_header, op);
653     for (i = 0; i < pe->sec_count; ++i)
654         fwrite(&pe->sec_info[i].ish, 1, sizeof(IMAGE_SECTION_HEADER), op);
655     fclose (op);
656 
657     if (2 == verbose)
658         printf("-------------------------------\n");
659     if (verbose)
660         printf("<- %s (%lu bytes)\n", pe->filename, file_offset);
661 
662     return 0;
663 }
664 
665 /*----------------------------------------------------------------------------*/
666 
pe_add_import(struct pe_info * pe,int sym_index)667 ST_FN struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index)
668 {
669     int i;
670     int dll_index;
671     struct pe_import_info *p;
672     struct import_symbol *s;
673 
674     dll_index = ((Elf32_Sym *)pe->s1->dynsymtab_section->data + sym_index)->st_value;
675     if (0 == dll_index)
676         return NULL;
677 
678     i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index);
679     if (-1 != i) {
680         p = pe->imp_info[i];
681         goto found_dll;
682     }
683     p = tcc_mallocz(sizeof *p);
684     p->dll_index = dll_index;
685     dynarray_add((void***)&pe->imp_info, &pe->imp_count, p);
686 
687 found_dll:
688     i = dynarray_assoc ((void**)p->symbols, p->sym_count, sym_index);
689     if (-1 != i)
690         return p->symbols[i];
691 
692     s = tcc_mallocz(sizeof *s);
693     dynarray_add((void***)&p->symbols, &p->sym_count, s);
694     s->sym_index = sym_index;
695     return s;
696 }
697 
698 /*----------------------------------------------------------------------------*/
pe_build_imports(struct pe_info * pe)699 ST_FN void pe_build_imports(struct pe_info *pe)
700 {
701     int thk_ptr, ent_ptr, dll_ptr, sym_cnt, i;
702     DWORD rva_base = pe->thunk->sh_addr - pe->imagebase;
703     int ndlls = pe->imp_count;
704 
705     for (sym_cnt = i = 0; i < ndlls; ++i)
706         sym_cnt += pe->imp_info[i]->sym_count;
707 
708     if (0 == sym_cnt)
709         return;
710 
711     pe_align_section(pe->thunk, 16);
712 
713     pe->imp_offs = dll_ptr = pe->thunk->data_offset;
714     pe->imp_size = (ndlls + 1) * sizeof(struct pe_import_header);
715     pe->iat_offs = dll_ptr + pe->imp_size;
716     pe->iat_size = (sym_cnt + ndlls) * sizeof(DWORD);
717     section_ptr_add(pe->thunk, pe->imp_size + 2*pe->iat_size);
718 
719     thk_ptr = pe->iat_offs;
720     ent_ptr = pe->iat_offs + pe->iat_size;
721 
722     for (i = 0; i < pe->imp_count; ++i) {
723         struct pe_import_header *hdr;
724         int k, n, v;
725         struct pe_import_info *p = pe->imp_info[i];
726         const char *name = pe->s1->loaded_dlls[p->dll_index-1]->name;
727 
728         /* put the dll name into the import header */
729         v = put_elf_str(pe->thunk, name);
730 
731         hdr = (struct pe_import_header*)(pe->thunk->data + dll_ptr);
732         hdr->first_thunk     = thk_ptr + rva_base;
733         hdr->first_entry     = ent_ptr + rva_base;
734         hdr->lib_name_offset = v + rva_base;
735 
736         for (k = 0, n = p->sym_count; k <= n; ++k) {
737             if (k < n) {
738                 DWORD iat_index = p->symbols[k]->iat_index;
739                 int sym_index = p->symbols[k]->sym_index;
740                 Elf32_Sym *imp_sym = (Elf32_Sym *)pe->s1->dynsymtab_section->data + sym_index;
741                 Elf32_Sym *org_sym = (Elf32_Sym *)symtab_section->data + iat_index;
742                 const char *name = pe->s1->dynsymtab_section->link->data + imp_sym->st_name;
743 
744                 org_sym->st_value = thk_ptr;
745                 org_sym->st_shndx = pe->thunk->sh_num;
746                 v = pe->thunk->data_offset + rva_base;
747                 section_ptr_add(pe->thunk, sizeof(WORD)); /* hint, not used */
748                 put_elf_str(pe->thunk, name);
749 
750             } else {
751                 v = 0; /* last entry is zero */
752             }
753             *(DWORD*)(pe->thunk->data+thk_ptr) =
754             *(DWORD*)(pe->thunk->data+ent_ptr) = v;
755             thk_ptr += sizeof (DWORD);
756             ent_ptr += sizeof (DWORD);
757         }
758         dll_ptr += sizeof(struct pe_import_header);
759         dynarray_reset(&p->symbols, &p->sym_count);
760     }
761     dynarray_reset(&pe->imp_info, &pe->imp_count);
762 }
763 
764 /* ------------------------------------------------------------- */
765 /*
766     For now only functions are exported. Export of data
767     would work, but import requires compiler support to
768     do an additional indirection.
769 
770     For instance:
771         __declspec(dllimport) extern int something;
772 
773     needs to be translated to:
774 
775         *(int*)something
776 */
777 
sym_cmp(const void * va,const void * vb)778 ST_FN int sym_cmp(const void *va, const void *vb)
779 {
780     const char *ca = ((const char **)va)[1];
781     const char *cb = ((const char **)vb)[1];
782     return strcmp(ca, cb);
783 }
784 
pe_build_exports(struct pe_info * pe)785 ST_FN void pe_build_exports(struct pe_info *pe)
786 {
787     Elf32_Sym *sym;
788     int sym_index, sym_end;
789     DWORD rva_base, func_o, name_o, ord_o, str_o;
790     struct pe_export_header *hdr;
791     int sym_count, n, ord, *sorted, *sp;
792 
793     FILE *op;
794     char buf[MAX_PATH];
795     const char *dllname;
796     const char *name;
797 
798     rva_base = pe->thunk->sh_addr - pe->imagebase;
799     sym_count = 0, n = 1, sorted = NULL, op = NULL;
800 
801     sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
802     for (sym_index = 1; sym_index < sym_end; ++sym_index) {
803         sym = (Elf32_Sym*)symtab_section->data + sym_index;
804         name = symtab_section->link->data + sym->st_name;
805         if ((sym->st_other & 1)
806             /* export only symbols from actually written sections */
807             && pe->s1->sections[sym->st_shndx]->sh_addr) {
808             dynarray_add((void***)&sorted, &sym_count, (void*)n);
809             dynarray_add((void***)&sorted, &sym_count, (void*)name);
810         }
811         ++n;
812 #if 0
813         if (sym->st_other & 1)
814             printf("export: %s\n", name);
815         if (sym->st_other & 2)
816             printf("stdcall: %s\n", name);
817 #endif
818     }
819 
820     if (0 == sym_count)
821         return;
822     sym_count /= 2;
823 
824     qsort (sorted, sym_count, 2 * sizeof sorted[0], sym_cmp);
825     pe_align_section(pe->thunk, 16);
826     dllname = tcc_basename(pe->filename);
827 
828     pe->exp_offs = pe->thunk->data_offset;
829     func_o = pe->exp_offs + sizeof(struct pe_export_header);
830     name_o = func_o + sym_count * sizeof (DWORD);
831     ord_o = name_o + sym_count * sizeof (DWORD);
832     str_o = ord_o + sym_count * sizeof(WORD);
833 
834     hdr = section_ptr_add(pe->thunk, str_o - pe->exp_offs);
835     hdr->Characteristics        = 0;
836     hdr->Base                   = 1;
837     hdr->NumberOfFunctions      = sym_count;
838     hdr->NumberOfNames          = sym_count;
839     hdr->AddressOfFunctions     = func_o + rva_base;
840     hdr->AddressOfNames         = name_o + rva_base;
841     hdr->AddressOfNameOrdinals  = ord_o + rva_base;
842     hdr->Name                   = str_o + rva_base;
843     put_elf_str(pe->thunk, dllname);
844 
845 #if 1
846     /* automatically write exports to <output-filename>.def */
847     strcpy(buf, pe->filename);
848     strcpy(tcc_fileextension(buf), ".def");
849     op = fopen(buf, "w");
850     if (NULL == op) {
851         error_noabort("could not create '%s': %s", buf, strerror(errno));
852     } else {
853         fprintf(op, "LIBRARY %s\n\nEXPORTS\n", dllname);
854         if (verbose)
855             printf("<- %s (%d symbols)\n", buf, sym_count);
856     }
857 #endif
858 
859     for (sp = sorted, ord = 0; ord < sym_count; ++ord, sp += 2)
860     {
861         sym_index = sp[0], name = (const char *)sp[1];
862         /* insert actual address later in pe_relocate_rva */
863         put_elf_reloc(symtab_section, pe->thunk,
864             func_o, R_386_RELATIVE, sym_index);
865         *(DWORD*)(pe->thunk->data + name_o)
866             = pe->thunk->data_offset + rva_base;
867         *(WORD*)(pe->thunk->data + ord_o)
868             = ord;
869         put_elf_str(pe->thunk, name);
870         func_o += sizeof (DWORD);
871         name_o += sizeof (DWORD);
872         ord_o += sizeof (WORD);
873 
874         if (op)
875             fprintf(op, "%s\n", name);
876     }
877     pe->exp_size = pe->thunk->data_offset - pe->exp_offs;
878     tcc_free(sorted);
879 }
880 
881 /* ------------------------------------------------------------- */
pe_build_reloc(struct pe_info * pe)882 ST_FN void pe_build_reloc (struct pe_info *pe)
883 {
884     DWORD offset, block_ptr, addr;
885     int count, i;
886     Elf32_Rel *rel, *rel_end;
887     Section *s = NULL, *sr;
888 
889     offset = addr = block_ptr = count = i = 0;
890     rel = rel_end = NULL;
891 
892     for(;;) {
893         if (rel < rel_end) {
894             int type = ELF32_R_TYPE(rel->r_info);
895             addr = rel->r_offset + s->sh_addr;
896             ++ rel;
897             if (type != R_386_32)
898                 continue;
899             if (count == 0) { /* new block */
900                 block_ptr = pe->reloc->data_offset;
901                 section_ptr_add(pe->reloc, sizeof(struct pe_reloc_header));
902                 offset = addr & 0xFFFFFFFF<<12;
903             }
904             if ((addr -= offset)  < (1<<12)) { /* one block spans 4k addresses */
905                 WORD *wp = section_ptr_add(pe->reloc, sizeof (WORD));
906                 *wp = addr | IMAGE_REL_BASED_HIGHLOW<<12;
907                 ++count;
908                 continue;
909             }
910             -- rel;
911 
912         } else if (i < pe->sec_count) {
913             sr = (s = pe->s1->sections[pe->sec_info[i++].ord])->reloc;
914             if (sr) {
915                 rel = (Elf32_Rel *)sr->data;
916                 rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
917             }
918             continue;
919         }
920 
921         if (count) {
922             /* store the last block and ready for a new one */
923             struct pe_reloc_header *hdr;
924             if (count & 1) /* align for DWORDS */
925                 section_ptr_add(pe->reloc, sizeof(WORD)), ++count;
926             hdr = (struct pe_reloc_header *)(pe->reloc->data + block_ptr);
927             hdr -> offset = offset - pe->imagebase;
928             hdr -> size = count * sizeof(WORD) + sizeof(struct pe_reloc_header);
929             count = 0;
930         }
931 
932         if (rel >= rel_end)
933             break;
934     }
935 }
936 
937 /* ------------------------------------------------------------- */
pe_section_class(Section * s)938 ST_FN int pe_section_class(Section *s)
939 {
940     int type, flags;
941     const char *name;
942 
943     type = s->sh_type;
944     flags = s->sh_flags;
945     name = s->name;
946     if (flags & SHF_ALLOC) {
947         if (type == SHT_PROGBITS) {
948             if (flags & SHF_EXECINSTR)
949                 return sec_text;
950             if (flags & SHF_WRITE)
951                 return sec_data;
952             if (0 == strcmp(name, ".rsrc"))
953                 return sec_rsrc;
954             if (0 == strcmp(name, ".iedat"))
955                 return sec_idata;
956         } else if (type == SHT_NOBITS) {
957             if (flags & SHF_WRITE)
958                 return sec_bss;
959         }
960     } else {
961         if (0 == strcmp(name, ".reloc"))
962             return sec_reloc;
963         if (0 == strncmp(name, ".stab", 5)) /* .stab and .stabstr */
964             return sec_stab;
965     }
966     return -1;
967 }
968 
pe_assign_addresses(struct pe_info * pe)969 ST_FN int pe_assign_addresses (struct pe_info *pe)
970 {
971     int i, k, o, c;
972     DWORD addr;
973     int *section_order;
974     struct section_info *si;
975     Section *s;
976 
977     // pe->thunk = new_section(pe->s1, ".iedat", SHT_PROGBITS, SHF_ALLOC);
978 
979     section_order = tcc_malloc(pe->s1->nb_sections * sizeof (int));
980     for (o = k = 0 ; k < sec_last; ++k) {
981         for (i = 1; i < pe->s1->nb_sections; ++i) {
982             s = pe->s1->sections[i];
983             if (k == pe_section_class(s)) {
984                 // printf("%s %d\n", s->name, k);
985                 s->sh_addr = pe->imagebase;
986                 section_order[o++] = i;
987             }
988         }
989     }
990 
991     pe->sec_info = tcc_mallocz(o * sizeof (struct section_info));
992     addr = pe->imagebase + 1;
993 
994     for (i = 0; i < o; ++i)
995     {
996         k = section_order[i];
997         s = pe->s1->sections[k];
998         c = pe_section_class(s);
999         si = &pe->sec_info[pe->sec_count];
1000 
1001 #ifdef PE_MERGE_DATA
1002         if (c == sec_bss && pe->sec_count && si[-1].cls == sec_data) {
1003             /* append .bss to .data */
1004             s->sh_addr = addr = ((addr-1) | 15) + 1;
1005             addr += s->data_offset;
1006             si[-1].sh_size = addr - si[-1].sh_addr;
1007             continue;
1008         }
1009 #endif
1010         strcpy(si->name, s->name);
1011         si->cls = c;
1012         si->ord = k;
1013         si->sh_addr = s->sh_addr = addr = pe_virtual_align(addr);
1014         si->sh_flags = s->sh_flags;
1015 
1016         if (c == sec_data && NULL == pe->thunk)
1017             pe->thunk = s;
1018 
1019         if (s == pe->thunk) {
1020             pe_build_imports(pe);
1021             pe_build_exports(pe);
1022         }
1023 
1024         if (c == sec_reloc)
1025             pe_build_reloc (pe);
1026 
1027         if (s->data_offset)
1028         {
1029             if (s->sh_type != SHT_NOBITS) {
1030                 si->data = s->data;
1031                 si->data_size = s->data_offset;
1032             }
1033 
1034             addr += s->data_offset;
1035             si->sh_size = s->data_offset;
1036             ++pe->sec_count;
1037         }
1038         // printf("%08x %05x %s\n", si->sh_addr, si->sh_size, si->name);
1039     }
1040 
1041 #if 0
1042     for (i = 1; i < pe->s1->nb_sections; ++i) {
1043         Section *s = pe->s1->sections[i];
1044         int type = s->sh_type;
1045         int flags = s->sh_flags;
1046         printf("section %-16s %-10s %5x %s,%s,%s\n",
1047             s->name,
1048             type == SHT_PROGBITS ? "progbits" :
1049             type == SHT_NOBITS ? "nobits" :
1050             type == SHT_SYMTAB ? "symtab" :
1051             type == SHT_STRTAB ? "strtab" :
1052             type == SHT_REL ? "rel" : "???",
1053             s->data_offset,
1054             flags & SHF_ALLOC ? "alloc" : "",
1055             flags & SHF_WRITE ? "write" : "",
1056             flags & SHF_EXECINSTR ? "exec" : ""
1057             );
1058     }
1059     verbose = 2;
1060 #endif
1061 
1062     tcc_free(section_order);
1063     return 0;
1064 }
1065 
1066 /* ------------------------------------------------------------- */
pe_relocate_rva(struct pe_info * pe,Section * s)1067 ST_FN void pe_relocate_rva (struct pe_info *pe, Section *s)
1068 {
1069     Section *sr = s->reloc;
1070     Elf32_Rel *rel, *rel_end;
1071     rel_end = (Elf32_Rel *)(sr->data + sr->data_offset);
1072     for(rel = (Elf32_Rel *)sr->data; rel < rel_end; rel++)
1073         if (ELF32_R_TYPE(rel->r_info) == R_386_RELATIVE) {
1074             int sym_index = ELF32_R_SYM(rel->r_info);
1075             DWORD addr = s->sh_addr;
1076             if (sym_index) {
1077                 Elf32_Sym *sym = (Elf32_Sym *)symtab_section->data + sym_index;
1078                 addr = sym->st_value;
1079             }
1080             *(DWORD*)(s->data + rel->r_offset) += addr - pe->imagebase;
1081         }
1082 }
1083 
1084 /*----------------------------------------------------------------------------*/
pe_check_symbols(struct pe_info * pe)1085 ST_FN int pe_check_symbols(struct pe_info *pe)
1086 {
1087     Elf32_Sym *sym;
1088     int sym_index, sym_end;
1089     int ret = 0;
1090 
1091     pe_align_section(text_section, 8);
1092 
1093     sym_end = symtab_section->data_offset / sizeof(Elf32_Sym);
1094     for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1095 
1096         sym = (Elf32_Sym*)symtab_section->data + sym_index;
1097         if (sym->st_shndx == SHN_UNDEF) {
1098 
1099             const char *name = symtab_section->link->data + sym->st_name;
1100             unsigned type = ELF32_ST_TYPE(sym->st_info);
1101             int imp_sym = pe_find_import(pe->s1, name);
1102             struct import_symbol *is;
1103 
1104             if (0 == imp_sym)
1105                 goto not_found;
1106             is = pe_add_import(pe, imp_sym);
1107             if (!is)
1108                 goto not_found;
1109 
1110             if (type == STT_FUNC) {
1111                 unsigned long offset = is->thk_offset;
1112                 if (offset) {
1113                     /* got aliased symbol, like stricmp and _stricmp */
1114 
1115                 } else {
1116                     char buffer[100];
1117 
1118                     offset = text_section->data_offset;
1119                     /* add the 'jmp IAT[x]' instruction */
1120                     *(WORD*)section_ptr_add(text_section, 8) = 0x25FF;
1121 
1122                     /* add a helper symbol, will be patched later in
1123                        pe_build_imports */
1124                     sprintf(buffer, "IAT.%s", name);
1125                     is->iat_index = put_elf_sym(
1126                         symtab_section, 0, sizeof(DWORD),
1127                         ELF32_ST_INFO(STB_GLOBAL, STT_OBJECT),
1128                         0, SHN_UNDEF, buffer);
1129                     put_elf_reloc(symtab_section, text_section,
1130                         offset + 2, R_386_32, is->iat_index);
1131                     is->thk_offset = offset;
1132                 }
1133 
1134                 /* tcc_realloc might have altered sym's address */
1135                 sym = (Elf32_Sym*)symtab_section->data + sym_index;
1136 
1137                 /* patch the original symbol */
1138                 sym->st_value = offset;
1139                 sym->st_shndx = text_section->sh_num;
1140                 sym->st_other &= ~1; /* do not export */
1141                 continue;
1142             }
1143 
1144             if (type == STT_OBJECT) { /* data, ptr to that should be */
1145                 if (0 == is->iat_index) {
1146                     /* original symbol will be patched later in pe_build_imports */
1147                     is->iat_index = sym_index;
1148                     continue;
1149                 }
1150             }
1151 
1152         not_found:
1153             error_noabort("undefined symbol '%s'", name);
1154             ret = 1;
1155 
1156         } else if (pe->s1->rdynamic
1157                    && ELF32_ST_BIND(sym->st_info) != STB_LOCAL) {
1158             /* if -rdynamic option, then export all non local symbols */
1159             sym->st_other |= 1;
1160         }
1161     }
1162     return ret;
1163 }
1164 
1165 /*----------------------------------------------------------------------------*/
1166 #ifdef PE_PRINT_SECTIONS
pe_print_section(FILE * f,Section * s)1167 ST_FN void pe_print_section(FILE * f, Section * s)
1168 {
1169     /* just if you'r curious */
1170     BYTE *p, *e, b;
1171     int i, n, l, m;
1172     p = s->data;
1173     e = s->data + s->data_offset;
1174     l = e - p;
1175 
1176     fprintf(f, "section  \"%s\"", s->name);
1177     if (s->link)
1178         fprintf(f, "\nlink     \"%s\"", s->link->name);
1179     if (s->reloc)
1180         fprintf(f, "\nreloc    \"%s\"", s->reloc->name);
1181     fprintf(f, "\nv_addr   %08X", s->sh_addr);
1182     fprintf(f, "\ncontents %08X", l);
1183     fprintf(f, "\n\n");
1184 
1185     if (s->sh_type == SHT_NOBITS)
1186         return;
1187 
1188     if (0 == l)
1189         return;
1190 
1191     if (s->sh_type == SHT_SYMTAB)
1192         m = sizeof(Elf32_Sym);
1193     if (s->sh_type == SHT_REL)
1194         m = sizeof(Elf32_Rel);
1195     else
1196         m = 16;
1197 
1198     fprintf(f, "%-8s", "offset");
1199     for (i = 0; i < m; ++i)
1200         fprintf(f, " %02x", i);
1201     n = 56;
1202 
1203     if (s->sh_type == SHT_SYMTAB || s->sh_type == SHT_REL) {
1204         const char *fields1[] = {
1205             "name",
1206             "value",
1207             "size",
1208             "bind",
1209             "type",
1210             "other",
1211             "shndx",
1212             NULL
1213         };
1214 
1215         const char *fields2[] = {
1216             "offs",
1217             "type",
1218             "symb",
1219             NULL
1220         };
1221 
1222         const char **p;
1223 
1224         if (s->sh_type == SHT_SYMTAB)
1225             p = fields1, n = 106;
1226         else
1227             p = fields2, n = 58;
1228 
1229         for (i = 0; p[i]; ++i)
1230             fprintf(f, "%6s", p[i]);
1231         fprintf(f, "  symbol");
1232     }
1233 
1234     fprintf(f, "\n");
1235     for (i = 0; i < n; ++i)
1236         fprintf(f, "-");
1237     fprintf(f, "\n");
1238 
1239     for (i = 0; i < l;)
1240     {
1241         fprintf(f, "%08X", i);
1242         for (n = 0; n < m; ++n) {
1243             if (n + i < l)
1244                 fprintf(f, " %02X", p[i + n]);
1245             else
1246                 fprintf(f, "   ");
1247         }
1248 
1249         if (s->sh_type == SHT_SYMTAB) {
1250             Elf32_Sym *sym = (Elf32_Sym *) (p + i);
1251             const char *name = s->link->data + sym->st_name;
1252             fprintf(f, "  %04X  %04X  %04X   %02X    %02X    %02X   %04X  \"%s\"",
1253                     sym->st_name,
1254                     sym->st_value,
1255                     sym->st_size,
1256                     ELF32_ST_BIND(sym->st_info),
1257                     ELF32_ST_TYPE(sym->st_info),
1258                     sym->st_other, sym->st_shndx, name);
1259 
1260         } else if (s->sh_type == SHT_REL) {
1261             Elf32_Rel *rel = (Elf32_Rel *) (p + i);
1262             Elf32_Sym *sym =
1263                 (Elf32_Sym *) s->link->data + ELF32_R_SYM(rel->r_info);
1264             const char *name = s->link->link->data + sym->st_name;
1265             fprintf(f, "  %04X   %02X   %04X  \"%s\"",
1266                     rel->r_offset,
1267                     ELF32_R_TYPE(rel->r_info),
1268                     ELF32_R_SYM(rel->r_info), name);
1269         } else {
1270             fprintf(f, "   ");
1271             for (n = 0; n < m; ++n) {
1272                 if (n + i < l) {
1273                     b = p[i + n];
1274                     if (b < 32 || b >= 127)
1275                         b = '.';
1276                     fprintf(f, "%c", b);
1277                 }
1278             }
1279         }
1280         i += m;
1281         fprintf(f, "\n");
1282     }
1283     fprintf(f, "\n\n");
1284 }
1285 
pe_print_sections(TCCState * s1,const char * fname)1286 ST_FN void pe_print_sections(TCCState *s1, const char *fname)
1287 {
1288     Section *s;
1289     FILE *f;
1290     int i;
1291     f = fopen(fname, "wt");
1292     for (i = 1; i < s1->nb_sections; ++i) {
1293         s = s1->sections[i];
1294         pe_print_section(f, s);
1295     }
1296     pe_print_section(f, s1->dynsymtab_section);
1297     fclose(f);
1298 }
1299 #endif
1300 
1301 /* -------------------------------------------------------------
1302  *  This is for compiled windows resources in 'coff' format
1303  *  as generated by 'windres.exe -O coff ...'.
1304  */
1305 
pe_test_res_file(void * v,int size)1306 PUB_FN int pe_test_res_file(void *v, int size)
1307 {
1308     struct pe_rsrc_header *p = (struct pe_rsrc_header *)v;
1309     return
1310         size >= IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_SHORT_NAME /* = 28 */
1311         && p->filehdr.Machine == 0x014C
1312         && 1 == p->filehdr.NumberOfSections
1313         && 0 == strcmp(p->sectionhdr.Name, ".rsrc")
1314         ;
1315 }
1316 
read_n(int fd,void * ptr,unsigned size)1317 ST_FN int read_n(int fd, void *ptr, unsigned size)
1318 {
1319     return size == read(fd, ptr, size);
1320 }
1321 
pe_load_res_file(TCCState * s1,int fd)1322 PUB_FN int pe_load_res_file(TCCState *s1, int fd)
1323 {
1324     struct pe_rsrc_header hdr;
1325     Section *rsrc_section;
1326     int i, ret = -1;
1327     BYTE *ptr;
1328 
1329     lseek (fd, 0, SEEK_SET);
1330     if (!read_n(fd, &hdr, sizeof hdr))
1331         goto quit;
1332     if (!pe_test_res_file(&hdr, sizeof hdr))
1333         goto quit;
1334 
1335     rsrc_section = new_section(s1, ".rsrc", SHT_PROGBITS, SHF_ALLOC);
1336     ptr = section_ptr_add(rsrc_section, hdr.sectionhdr.SizeOfRawData);
1337     lseek (fd, hdr.sectionhdr.PointerToRawData, SEEK_SET);
1338     if (!read_n(fd, ptr, hdr.sectionhdr.SizeOfRawData))
1339         goto quit;
1340 
1341     lseek (fd, hdr.sectionhdr.PointerToRelocations, SEEK_SET);
1342     for (i = 0; i < hdr.sectionhdr.NumberOfRelocations; ++i)
1343     {
1344         struct pe_rsrc_reloc rel;
1345         if (!read_n(fd, &rel, sizeof rel))
1346             goto quit;
1347         // printf("rsrc_reloc: %x %x %x\n", rel.offset, rel.size, rel.type);
1348         if (rel.type != 7) /* DIR32NB */
1349             goto quit;
1350         put_elf_reloc(symtab_section, rsrc_section,
1351             rel.offset, R_386_RELATIVE, 0);
1352     }
1353     ret = 0;
1354 quit:
1355     if (ret)
1356         error_noabort("unrecognized resource file format");
1357     return ret;
1358 }
1359 
1360 /* ------------------------------------------------------------- */
trimfront(char * p)1361 ST_FN char *trimfront(char *p)
1362 {
1363     while (*p && (unsigned char)*p <= ' ')
1364         ++p;
1365     return p;
1366 }
1367 
trimback(char * a,char * e)1368 ST_FN char *trimback(char *a, char *e)
1369 {
1370     while (e > a && (unsigned char)e[-1] <= ' ')
1371         --e;
1372     *e = 0;;
1373     return a;
1374 }
1375 
get_line(char * line,int size,FILE * fp)1376 ST_FN char *get_line(char *line, int size, FILE *fp)
1377 {
1378     if (NULL == fgets(line, size, fp))
1379         return NULL;
1380     trimback(line, strchr(line, 0));
1381     return trimfront(line);
1382 }
1383 
1384 /* ------------------------------------------------------------- */
pe_load_def_file(TCCState * s1,int fd)1385 PUB_FN int pe_load_def_file(TCCState *s1, int fd)
1386 {
1387     DLLReference *dllref;
1388     int state = 0, ret = -1;
1389     char line[400], dllname[80], *p;
1390     FILE *fp = fdopen(dup(fd), "rb");
1391 
1392     if (NULL == fp)
1393         goto quit;
1394 
1395     for (;;) {
1396         p = get_line(line, sizeof line, fp);
1397         if (NULL == p)
1398             break;
1399         if (0 == *p || ';' == *p)
1400             continue;
1401         switch (state) {
1402         case 0:
1403             if (0 != strnicmp(p, "LIBRARY", 7))
1404                 goto quit;
1405             strcpy(dllname, trimfront(p+7));
1406             ++state;
1407             continue;
1408 
1409         case 1:
1410             if (0 != stricmp(p, "EXPORTS"))
1411                 goto quit;
1412             ++state;
1413             continue;
1414 
1415         case 2:
1416             dllref = tcc_malloc(sizeof(DLLReference) + strlen(dllname));
1417             strcpy(dllref->name, dllname);
1418             dllref->level = 0;
1419             dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
1420             ++state;
1421 
1422         default:
1423             add_elf_sym(s1->dynsymtab_section,
1424                 s1->nb_loaded_dlls, 0,
1425                 ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), 0,
1426                 text_section->sh_num, p);
1427             continue;
1428         }
1429     }
1430     ret = 0;
1431 quit:
1432     if (fp)
1433         fclose(fp);
1434     if (ret)
1435         error_noabort("unrecognized export definition file format");
1436     return ret;
1437 }
1438 
1439 /* ------------------------------------------------------------- */
1440 
pe_add_runtime_ex(TCCState * s1,struct pe_info * pe)1441 ST_FN void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe)
1442 {
1443     const char *start_symbol;
1444     unsigned long addr = 0;
1445     int pe_type = 0;
1446 
1447     if (find_elf_sym(symtab_section, "_WinMain@16"))
1448         pe_type = PE_GUI;
1449     else
1450     if (TCC_OUTPUT_DLL == s1->output_type) {
1451         pe_type = PE_DLL;
1452         /* need this for 'tccelf.c:relocate_section()' */
1453         s1->output_type = TCC_OUTPUT_EXE;
1454     }
1455 
1456     start_symbol =
1457         TCC_OUTPUT_MEMORY == s1->output_type
1458         ? PE_GUI == pe_type ? "_runwinmain" : NULL
1459         : PE_DLL == pe_type ? "__dllstart@12"
1460         : PE_GUI == pe_type ? "_winstart" : "_start"
1461         ;
1462 
1463     /* grab the startup code from libtcc1 */
1464     if (start_symbol)
1465         add_elf_sym(symtab_section,
1466             0, 0,
1467             ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
1468             SHN_UNDEF, start_symbol);
1469 
1470     if (0 == s1->nostdlib) {
1471         tcc_add_library(s1, "tcc1");
1472 #ifdef __CYGWIN__
1473         tcc_add_library(s1, "cygwin1");
1474 #else
1475         tcc_add_library(s1, "msvcrt");
1476 #endif
1477         tcc_add_library(s1, "kernel32");
1478         if (PE_DLL == pe_type || PE_GUI == pe_type) {
1479             tcc_add_library(s1, "user32");
1480             tcc_add_library(s1, "gdi32");
1481         }
1482     }
1483 
1484     if (start_symbol) {
1485         addr = (unsigned long)tcc_get_symbol_err(s1, start_symbol);
1486         if (s1->output_type == TCC_OUTPUT_MEMORY && addr)
1487             /* for -run GUI's, put '_runwinmain' instead of 'main' */
1488             add_elf_sym(symtab_section,
1489                     addr, 0,
1490                     ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0,
1491                     text_section->sh_num, "main");
1492     }
1493 
1494     if (pe) {
1495         pe->type = pe_type;
1496         pe->start_addr = addr;
1497     }
1498 }
1499 
pe_add_runtime(TCCState * s1)1500 PUB_FN void pe_add_runtime(TCCState *s1)
1501 {
1502     pe_add_runtime_ex(s1, NULL);
1503 }
1504 
pe_output_file(TCCState * s1,const char * filename)1505 PUB_FN int pe_output_file(TCCState * s1, const char *filename)
1506 {
1507     int ret;
1508     struct pe_info pe;
1509     int i;
1510 
1511     memset(&pe, 0, sizeof pe);
1512     pe.filename = filename;
1513     pe.s1 = s1;
1514 
1515     pe_add_runtime_ex(s1, &pe);
1516     relocate_common_syms(); /* assign bss adresses */
1517     tcc_add_linker_symbols(s1);
1518 
1519     ret = pe_check_symbols(&pe);
1520     if (0 == ret) {
1521         if (PE_DLL == pe.type) {
1522             pe.reloc = new_section(pe.s1, ".reloc", SHT_PROGBITS, 0);
1523             pe.imagebase = 0x10000000;
1524         } else {
1525             pe.imagebase = 0x00400000;
1526         }
1527         pe_assign_addresses(&pe);
1528         relocate_syms(s1, 0);
1529         for (i = 1; i < s1->nb_sections; ++i) {
1530             Section *s = s1->sections[i];
1531             if (s->reloc) {
1532                 relocate_section(s1, s);
1533                 pe_relocate_rva(&pe, s);
1534             }
1535         }
1536         if (s1->nb_errors)
1537             ret = 1;
1538         else
1539             ret = pe_write(&pe);
1540         tcc_free(pe.sec_info);
1541     }
1542 
1543 #ifdef PE_PRINT_SECTIONS
1544     pe_print_sections(s1, "tcc.log");
1545 #endif
1546     return ret;
1547 }
1548 
1549 /* ------------------------------------------------------------- */
1550 #endif /* def TCC_TARGET_PE */
1551 /* ------------------------------------------------------------- */
1552