Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/elftoolchain/libpe/libpe_coff.c
39478 views
1
/*-
2
* Copyright (c) 2015 Kai Wang
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <assert.h>
29
#include <errno.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include <time.h>
33
#include <unistd.h>
34
35
#include "_libpe.h"
36
37
ELFTC_VCSID("$Id: libpe_coff.c 3326 2016-01-16 17:46:17Z kaiwang27 $");
38
39
int
40
libpe_parse_coff_header(PE *pe, char *hdr)
41
{
42
char tmp[128];
43
PE_CoffHdr *ch;
44
PE_OptHdr *oh;
45
PE_DataDir *dd;
46
unsigned p, r, s;
47
int i;
48
49
if ((ch = malloc(sizeof(PE_CoffHdr))) == NULL) {
50
errno = ENOMEM;
51
return (-1);
52
}
53
54
PE_READ16(hdr, ch->ch_machine);
55
PE_READ16(hdr, ch->ch_nsec);
56
PE_READ32(hdr, ch->ch_timestamp);
57
PE_READ32(hdr, ch->ch_symptr);
58
PE_READ32(hdr, ch->ch_nsym);
59
PE_READ16(hdr, ch->ch_optsize);
60
PE_READ16(hdr, ch->ch_char);
61
62
pe->pe_ch = ch;
63
64
/*
65
* The Optional header is omitted for object files.
66
*/
67
if (ch->ch_optsize == 0)
68
return (libpe_parse_section_headers(pe));
69
70
if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
71
errno = ENOMEM;
72
return (-1);
73
}
74
pe->pe_oh = oh;
75
76
#define READ_OPT(n) \
77
do { \
78
/* \
79
* Since the Optional Header size is variable, we must \
80
* check if the requested read size will overrun the \
81
* remaining header bytes. \
82
*/ \
83
if (p + (n) > ch->ch_optsize) { \
84
/* Consume the "extra" bytes */ \
85
r = ch->ch_optsize - p; \
86
if (read(pe->pe_fd, tmp, r) != (ssize_t) r) { \
87
pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;\
88
return (0); \
89
} \
90
return (libpe_parse_section_headers(pe)); \
91
} \
92
if (read(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) { \
93
pe->pe_flags |= LIBPE_F_BAD_OPT_HEADER; \
94
return (0); \
95
} \
96
p += (n); \
97
} while (0)
98
#define READ_OPT8(v) do { READ_OPT(1); (v) = *tmp; } while(0)
99
#define READ_OPT16(v) do { READ_OPT(2); (v) = le16dec(tmp); } while(0)
100
#define READ_OPT32(v) do { READ_OPT(4); (v) = le32dec(tmp); } while(0)
101
#define READ_OPT64(v) do { READ_OPT(8); (v) = le64dec(tmp); } while(0)
102
103
/*
104
* Read in the Optional header. Size of some fields are depending
105
* on the PE format specified by the oh_magic field. (PE32 or PE32+)
106
*/
107
108
p = 0;
109
READ_OPT16(oh->oh_magic);
110
if (oh->oh_magic == PE_FORMAT_32P)
111
pe->pe_obj = PE_O_PE32P;
112
READ_OPT8(oh->oh_ldvermajor);
113
READ_OPT8(oh->oh_ldverminor);
114
READ_OPT32(oh->oh_textsize);
115
READ_OPT32(oh->oh_datasize);
116
READ_OPT32(oh->oh_bsssize);
117
READ_OPT32(oh->oh_entry);
118
READ_OPT32(oh->oh_textbase);
119
if (oh->oh_magic != PE_FORMAT_32P) {
120
READ_OPT32(oh->oh_database);
121
READ_OPT32(oh->oh_imgbase);
122
} else
123
READ_OPT64(oh->oh_imgbase);
124
READ_OPT32(oh->oh_secalign);
125
READ_OPT32(oh->oh_filealign);
126
READ_OPT16(oh->oh_osvermajor);
127
READ_OPT16(oh->oh_osverminor);
128
READ_OPT16(oh->oh_imgvermajor);
129
READ_OPT16(oh->oh_imgverminor);
130
READ_OPT16(oh->oh_subvermajor);
131
READ_OPT16(oh->oh_subverminor);
132
READ_OPT32(oh->oh_win32ver);
133
READ_OPT32(oh->oh_imgsize);
134
READ_OPT32(oh->oh_hdrsize);
135
READ_OPT32(oh->oh_checksum);
136
READ_OPT16(oh->oh_subsystem);
137
READ_OPT16(oh->oh_dllchar);
138
if (oh->oh_magic != PE_FORMAT_32P) {
139
READ_OPT32(oh->oh_stacksizer);
140
READ_OPT32(oh->oh_stacksizec);
141
READ_OPT32(oh->oh_heapsizer);
142
READ_OPT32(oh->oh_heapsizec);
143
} else {
144
READ_OPT64(oh->oh_stacksizer);
145
READ_OPT64(oh->oh_stacksizec);
146
READ_OPT64(oh->oh_heapsizer);
147
READ_OPT64(oh->oh_heapsizec);
148
}
149
READ_OPT32(oh->oh_ldrflags);
150
READ_OPT32(oh->oh_ndatadir);
151
152
/*
153
* Read in the Data Directories.
154
*/
155
156
if (oh->oh_ndatadir > 0) {
157
if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
158
errno = ENOMEM;
159
return (-1);
160
}
161
pe->pe_dd = dd;
162
163
dd->dd_total = oh->oh_ndatadir < PE_DD_MAX ? oh->oh_ndatadir :
164
PE_DD_MAX;
165
166
for (i = 0; (uint32_t) i < dd->dd_total; i++) {
167
READ_OPT32(dd->dd_e[i].de_addr);
168
READ_OPT32(dd->dd_e[i].de_size);
169
}
170
}
171
172
/* Consume the remaining bytes in the Optional header, if any. */
173
if (ch->ch_optsize > p) {
174
r = ch->ch_optsize - p;
175
for (; r > 0; r -= s) {
176
s = r > sizeof(tmp) ? sizeof(tmp) : r;
177
if (read(pe->pe_fd, tmp, s) != (ssize_t) s) {
178
pe->pe_flags |= LIBPE_F_BAD_SEC_HEADER;
179
return (0);
180
}
181
}
182
}
183
184
return (libpe_parse_section_headers(pe));
185
}
186
187
off_t
188
libpe_write_pe_header(PE *pe, off_t off)
189
{
190
char tmp[4];
191
192
if (pe->pe_cmd == PE_C_RDWR &&
193
(pe->pe_flags & LIBPE_F_BAD_PE_HEADER) == 0) {
194
assert(pe->pe_dh != NULL);
195
off = lseek(pe->pe_fd, (off_t) pe->pe_dh->dh_lfanew + 4,
196
SEEK_SET);
197
return (off);
198
}
199
200
/*
201
* PE Header should to be aligned on 8-byte boundary according to
202
* the PE/COFF specification.
203
*/
204
if ((off = libpe_align(pe, off, 8)) < 0)
205
return (-1);
206
207
le32enc(tmp, PE_SIGNATURE);
208
if (write(pe->pe_fd, tmp, sizeof(tmp)) != (ssize_t) sizeof(tmp)) {
209
errno = EIO;
210
return (-1);
211
}
212
213
off += 4;
214
215
pe->pe_flags &= ~LIBPE_F_BAD_PE_HEADER;
216
217
/* Trigger rewrite for the following headers. */
218
pe->pe_flags |= LIBPE_F_DIRTY_COFF_HEADER;
219
pe->pe_flags |= LIBPE_F_DIRTY_OPT_HEADER;
220
221
return (off);
222
}
223
224
off_t
225
libpe_write_coff_header(PE *pe, off_t off)
226
{
227
char tmp[128], *hdr;
228
PE_CoffHdr *ch;
229
PE_DataDir *dd;
230
PE_OptHdr *oh;
231
PE_Scn *ps;
232
PE_SecHdr *sh;
233
unsigned p;
234
uint32_t reloc_rva, reloc_sz;
235
int i, reloc;
236
237
reloc = 0;
238
reloc_rva = reloc_sz = 0;
239
240
if (pe->pe_cmd == PE_C_RDWR) {
241
assert((pe->pe_flags & LIBPE_F_SPECIAL_FILE) == 0);
242
243
if ((pe->pe_flags & LIBPE_F_DIRTY_COFF_HEADER) == 0 &&
244
(pe->pe_flags & LIBPE_F_BAD_COFF_HEADER) == 0) {
245
if (lseek(pe->pe_fd, (off_t) sizeof(PE_CoffHdr),
246
SEEK_CUR) < 0) {
247
errno = EIO;
248
return (-1);
249
}
250
off += sizeof(PE_CoffHdr);
251
assert(pe->pe_ch != NULL);
252
ch = pe->pe_ch;
253
goto coff_done;
254
}
255
256
/* lseek(2) to the offset of the COFF header. */
257
if (lseek(pe->pe_fd, off, SEEK_SET) < 0) {
258
errno = EIO;
259
return (-1);
260
}
261
}
262
263
if (pe->pe_ch == NULL) {
264
if ((ch = calloc(1, sizeof(PE_CoffHdr))) == NULL) {
265
errno = ENOMEM;
266
return (-1);
267
}
268
pe->pe_ch = ch;
269
270
/*
271
* Default value for ch_machine if not provided by the
272
* application.
273
*/
274
if (pe->pe_obj == PE_O_PE32P)
275
ch->ch_machine = IMAGE_FILE_MACHINE_AMD64;
276
else
277
ch->ch_machine = IMAGE_FILE_MACHINE_I386;
278
279
} else
280
ch = pe->pe_ch;
281
282
if (!ch->ch_timestamp)
283
ch->ch_timestamp = time(NULL);
284
285
if (pe->pe_obj == PE_O_PE32) {
286
if (!ch->ch_optsize)
287
ch->ch_optsize = PE_COFF_OPT_SIZE_32;
288
ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
289
IMAGE_FILE_32BIT_MACHINE;
290
} else if (pe->pe_obj == PE_O_PE32P) {
291
if (!ch->ch_optsize)
292
ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
293
ch->ch_char |= IMAGE_FILE_EXECUTABLE_IMAGE |
294
IMAGE_FILE_LARGE_ADDRESS_AWARE;
295
} else
296
ch->ch_optsize = 0;
297
298
/*
299
* COFF line number is deprecated by the PE/COFF
300
* specification. COFF symbol table is deprecated
301
* for executables.
302
*/
303
ch->ch_char |= IMAGE_FILE_LINE_NUMS_STRIPPED;
304
if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P)
305
ch->ch_char |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;
306
307
ch->ch_nsec = pe->pe_nscn;
308
309
STAILQ_FOREACH(ps, &pe->pe_scn, ps_next) {
310
sh = &ps->ps_sh;
311
312
if (ps->ps_ndx == 0xFFFFFFFFU) {
313
ch->ch_symptr = sh->sh_rawptr;
314
ch->ch_nsym = pe->pe_nsym;
315
}
316
317
if (pe->pe_obj == PE_O_PE32 || pe->pe_obj == PE_O_PE32P) {
318
if (ps->ps_ndx == (0xFFFF0000 | PE_DD_BASERELOC) ||
319
strncmp(sh->sh_name, ".reloc", strlen(".reloc")) ==
320
0) {
321
reloc = 1;
322
reloc_rva = sh->sh_addr;
323
reloc_sz = sh->sh_virtsize;
324
}
325
}
326
}
327
328
if (!reloc)
329
ch->ch_char |= IMAGE_FILE_RELOCS_STRIPPED;
330
331
if (pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) {
332
if (pe->pe_obj == PE_O_PE32)
333
ch->ch_optsize = PE_COFF_OPT_SIZE_32;
334
else if (pe->pe_obj == PE_O_PE32P)
335
ch->ch_optsize = PE_COFF_OPT_SIZE_32P;
336
else
337
ch->ch_optsize = 0;
338
}
339
340
/*
341
* Write the COFF header.
342
*/
343
hdr = tmp;
344
PE_WRITE16(hdr, ch->ch_machine);
345
PE_WRITE16(hdr, ch->ch_nsec);
346
PE_WRITE32(hdr, ch->ch_timestamp);
347
PE_WRITE32(hdr, ch->ch_symptr);
348
PE_WRITE32(hdr, ch->ch_nsym);
349
PE_WRITE16(hdr, ch->ch_optsize);
350
PE_WRITE16(hdr, ch->ch_char);
351
if (write(pe->pe_fd, tmp, sizeof(PE_CoffHdr)) !=
352
(ssize_t) sizeof(PE_CoffHdr)) {
353
errno = EIO;
354
return (-1);
355
}
356
357
coff_done:
358
off += sizeof(PE_CoffHdr);
359
pe->pe_flags &= ~LIBPE_F_DIRTY_COFF_HEADER;
360
pe->pe_flags &= ~LIBPE_F_BAD_COFF_HEADER;
361
pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
362
363
if (ch->ch_optsize == 0)
364
return (off);
365
366
/*
367
* Write the Optional header.
368
*/
369
370
if (pe->pe_cmd == PE_C_RDWR) {
371
if ((pe->pe_flags & LIBPE_F_DIRTY_OPT_HEADER) == 0 &&
372
(pe->pe_flags & LIBPE_F_BAD_OPT_HEADER) == 0) {
373
if (lseek(pe->pe_fd, (off_t) ch->ch_optsize,
374
SEEK_CUR) < 0) {
375
errno = EIO;
376
return (-1);
377
}
378
off += ch->ch_optsize;
379
return (off);
380
}
381
382
}
383
384
if (pe->pe_oh == NULL) {
385
if ((oh = calloc(1, sizeof(PE_OptHdr))) == NULL) {
386
errno = ENOMEM;
387
return (-1);
388
}
389
pe->pe_oh = oh;
390
} else
391
oh = pe->pe_oh;
392
393
if (pe->pe_obj == PE_O_PE32)
394
oh->oh_magic = PE_FORMAT_32;
395
else
396
oh->oh_magic = PE_FORMAT_32P;
397
398
/*
399
* LinkerVersion should not be less than 2.5, which will cause
400
* Windows to complain the executable is invalid in some case.
401
* By default we set LinkerVersion to 2.22 (binutils 2.22)
402
*/
403
if (!oh->oh_ldvermajor && !oh->oh_ldverminor) {
404
oh->oh_ldvermajor = 2;
405
oh->oh_ldverminor = 22;
406
}
407
408
/*
409
* The library always tries to write out all 16 data directories
410
* but the actual data dir written will depend on ch_optsize.
411
*/
412
oh->oh_ndatadir = PE_DD_MAX;
413
414
if (!oh->oh_filealign)
415
oh->oh_filealign = 0x200;
416
if (!oh->oh_secalign)
417
oh->oh_secalign = 0x1000;
418
oh->oh_hdrsize = roundup(off + ch->ch_optsize + pe->pe_nscn *
419
sizeof(PE_SecHdr), oh->oh_filealign);
420
oh->oh_imgsize = roundup(pe->pe_rvamax, oh->oh_secalign);
421
422
#define WRITE_OPT(n) \
423
do { \
424
/* \
425
* Since the Optional Header size is variable, we must \
426
* check if the requested write size will overrun the \
427
* remaining header bytes. \
428
*/ \
429
if (p + (n) > ch->ch_optsize) { \
430
/* Pad the "extra" bytes */ \
431
if (libpe_pad(pe, ch->ch_optsize - p) < 0) { \
432
errno = EIO; \
433
return (-1); \
434
} \
435
goto opt_done; \
436
} \
437
if (write(pe->pe_fd, tmp, (n)) != (ssize_t) (n)) { \
438
errno = EIO; \
439
return (-1); \
440
} \
441
p += (n); \
442
} while (0)
443
#define WRITE_OPT8(v) do { *tmp = (v); WRITE_OPT(1); } while(0)
444
#define WRITE_OPT16(v) do { le16enc(tmp, (v)); WRITE_OPT(2); } while(0)
445
#define WRITE_OPT32(v) do { le32enc(tmp, (v)); WRITE_OPT(4); } while(0)
446
#define WRITE_OPT64(v) do { le64enc(tmp, (v)); WRITE_OPT(8); } while(0)
447
448
p = 0;
449
WRITE_OPT16(oh->oh_magic);
450
if (oh->oh_magic == PE_FORMAT_32P)
451
pe->pe_obj = PE_O_PE32P;
452
WRITE_OPT8(oh->oh_ldvermajor);
453
WRITE_OPT8(oh->oh_ldverminor);
454
WRITE_OPT32(oh->oh_textsize);
455
WRITE_OPT32(oh->oh_datasize);
456
WRITE_OPT32(oh->oh_bsssize);
457
WRITE_OPT32(oh->oh_entry);
458
WRITE_OPT32(oh->oh_textbase);
459
if (oh->oh_magic != PE_FORMAT_32P) {
460
WRITE_OPT32(oh->oh_database);
461
WRITE_OPT32(oh->oh_imgbase);
462
} else
463
WRITE_OPT64(oh->oh_imgbase);
464
WRITE_OPT32(oh->oh_secalign);
465
WRITE_OPT32(oh->oh_filealign);
466
WRITE_OPT16(oh->oh_osvermajor);
467
WRITE_OPT16(oh->oh_osverminor);
468
WRITE_OPT16(oh->oh_imgvermajor);
469
WRITE_OPT16(oh->oh_imgverminor);
470
WRITE_OPT16(oh->oh_subvermajor);
471
WRITE_OPT16(oh->oh_subverminor);
472
WRITE_OPT32(oh->oh_win32ver);
473
WRITE_OPT32(oh->oh_imgsize);
474
WRITE_OPT32(oh->oh_hdrsize);
475
WRITE_OPT32(oh->oh_checksum);
476
WRITE_OPT16(oh->oh_subsystem);
477
WRITE_OPT16(oh->oh_dllchar);
478
if (oh->oh_magic != PE_FORMAT_32P) {
479
WRITE_OPT32(oh->oh_stacksizer);
480
WRITE_OPT32(oh->oh_stacksizec);
481
WRITE_OPT32(oh->oh_heapsizer);
482
WRITE_OPT32(oh->oh_heapsizec);
483
} else {
484
WRITE_OPT64(oh->oh_stacksizer);
485
WRITE_OPT64(oh->oh_stacksizec);
486
WRITE_OPT64(oh->oh_heapsizer);
487
WRITE_OPT64(oh->oh_heapsizec);
488
}
489
WRITE_OPT32(oh->oh_ldrflags);
490
WRITE_OPT32(oh->oh_ndatadir);
491
492
/*
493
* Write the Data Directories.
494
*/
495
496
if (oh->oh_ndatadir > 0) {
497
if (pe->pe_dd == NULL) {
498
if ((dd = calloc(1, sizeof(PE_DataDir))) == NULL) {
499
errno = ENOMEM;
500
return (-1);
501
}
502
pe->pe_dd = dd;
503
dd->dd_total = PE_DD_MAX;
504
} else
505
dd = pe->pe_dd;
506
507
assert(oh->oh_ndatadir <= PE_DD_MAX);
508
509
if (reloc) {
510
dd->dd_e[PE_DD_BASERELOC].de_addr = reloc_rva;
511
dd->dd_e[PE_DD_BASERELOC].de_size = reloc_sz;
512
}
513
514
for (i = 0; (uint32_t) i < dd->dd_total; i++) {
515
WRITE_OPT32(dd->dd_e[i].de_addr);
516
WRITE_OPT32(dd->dd_e[i].de_size);
517
}
518
}
519
520
/* Pad the remaining bytes in the Optional header, if any. */
521
if (ch->ch_optsize > p) {
522
if (libpe_pad(pe, ch->ch_optsize - p) < 0) {
523
errno = EIO;
524
return (-1);
525
}
526
}
527
528
opt_done:
529
off += ch->ch_optsize;
530
pe->pe_flags &= ~LIBPE_F_DIRTY_OPT_HEADER;
531
pe->pe_flags &= ~LIBPE_F_BAD_OPT_HEADER;
532
pe->pe_flags |= LIBPE_F_DIRTY_SEC_HEADER;
533
534
return (off);
535
}
536
537