Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/elftoolchain/elfcopy/ascii.c
39534 views
1
/*-
2
* Copyright (c) 2010,2011 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 <ctype.h>
29
#include <err.h>
30
#include <gelf.h>
31
#include <stdint.h>
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
#include <unistd.h>
36
37
#include "elfcopy.h"
38
39
ELFTC_VCSID("$Id: ascii.c 3757 2019-06-28 01:15:28Z emaste $");
40
41
static void append_data(struct section *s, const void *buf, size_t sz);
42
static char hex_digit(uint8_t n);
43
static int hex_value(int x);
44
static void finalize_data_section(struct section *s);
45
static int ishexdigit(int x);
46
static int ihex_read(const char *line, char *type, uint64_t *addr,
47
uint64_t *num, uint8_t *data, size_t *sz);
48
static void ihex_write(int ofd, int type, uint64_t addr, uint64_t num,
49
const void *buf, size_t sz);
50
static void ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz);
51
static void ihex_write_01(int ofd);
52
static void ihex_write_04(int ofd, uint16_t addr);
53
static void ihex_write_05(int ofd, uint64_t e_entry);
54
static struct section *new_data_section(struct elfcopy *ecp, int sec_index,
55
uint64_t off, uint64_t addr);
56
static int read_num(const char *line, int *len, uint64_t *num, size_t sz,
57
int *checksum);
58
static int srec_read(const char *line, char *type, uint64_t *addr,
59
uint8_t *data, size_t *sz);
60
static void srec_write(int ofd, char type, uint64_t addr, const void *buf,
61
size_t sz);
62
static void srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn,
63
GElf_Shdr *sh);
64
static void srec_write_S0(int ofd, const char *ofn);
65
static void srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf,
66
size_t sz, size_t rlen);
67
static void srec_write_Se(int ofd, uint64_t e_entry, int forceS3);
68
static void write_num(char *line, int *len, uint64_t num, size_t sz,
69
int *checksum);
70
71
#define _LINE_BUFSZ 1024
72
#define _DATA_BUFSZ 256
73
74
/*
75
* Convert ELF object to S-Record.
76
*/
77
void
78
create_srec(struct elfcopy *ecp, int ifd, int ofd, const char *ofn)
79
{
80
Elf *e;
81
Elf_Scn *scn;
82
Elf_Data *d;
83
GElf_Ehdr eh;
84
GElf_Shdr sh;
85
uint64_t max_addr;
86
size_t rlen;
87
int elferr, addr_sz;
88
char dr;
89
90
if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
91
errx(EXIT_FAILURE, "elf_begin() failed: %s",
92
elf_errmsg(-1));
93
94
/* Output a symbol table for `symbolsrec' target. */
95
if (!strncmp(ecp->otgt, "symbolsrec", strlen("symbolsrec"))) {
96
scn = NULL;
97
while ((scn = elf_nextscn(e, scn)) != NULL) {
98
if (gelf_getshdr(scn, &sh) == NULL) {
99
warnx("gelf_getshdr failed: %s",
100
elf_errmsg(-1));
101
(void) elf_errno();
102
continue;
103
}
104
if (sh.sh_type != SHT_SYMTAB)
105
continue;
106
srec_write_symtab(ofd, ofn, e, scn, &sh);
107
break;
108
}
109
}
110
111
if (ecp->flags & SREC_FORCE_S3)
112
dr = '3';
113
else {
114
/*
115
* Find maximum address size in the first iteration.
116
*/
117
max_addr = 0;
118
scn = NULL;
119
while ((scn = elf_nextscn(e, scn)) != NULL) {
120
if (gelf_getshdr(scn, &sh) == NULL) {
121
warnx("gelf_getshdr failed: %s",
122
elf_errmsg(-1));
123
(void) elf_errno();
124
continue;
125
}
126
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
127
sh.sh_type == SHT_NOBITS ||
128
sh.sh_size == 0)
129
continue;
130
if ((uint64_t) sh.sh_addr > max_addr)
131
max_addr = sh.sh_addr;
132
}
133
elferr = elf_errno();
134
if (elferr != 0)
135
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
136
137
if (max_addr <= 0xFFFF)
138
dr = '1';
139
else if (max_addr <= 0xFFFFFF)
140
dr = '2';
141
else
142
dr = '3';
143
}
144
145
if (ecp->flags & SREC_FORCE_LEN) {
146
addr_sz = dr - '0' + 1;
147
if (ecp->srec_len < 1)
148
rlen = 1;
149
else if (ecp->srec_len + addr_sz + 1 > 255)
150
rlen = 255 - (addr_sz + 1);
151
else
152
rlen = ecp->srec_len;
153
} else
154
rlen = 16;
155
156
/* Generate S0 record which contains the output filename. */
157
srec_write_S0(ofd, ofn);
158
159
/* Generate S{1,2,3} data records for section data. */
160
scn = NULL;
161
while ((scn = elf_nextscn(e, scn)) != NULL) {
162
if (gelf_getshdr(scn, &sh) == NULL) {
163
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
164
(void) elf_errno();
165
continue;
166
}
167
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
168
sh.sh_type == SHT_NOBITS ||
169
sh.sh_size == 0)
170
continue;
171
if (sh.sh_addr > 0xFFFFFFFF) {
172
warnx("address space too big for S-Record file");
173
continue;
174
}
175
(void) elf_errno();
176
if ((d = elf_getdata(scn, NULL)) == NULL) {
177
elferr = elf_errno();
178
if (elferr != 0)
179
warnx("elf_getdata failed: %s", elf_errmsg(-1));
180
continue;
181
}
182
if (d->d_buf == NULL || d->d_size == 0)
183
continue;
184
srec_write_Sd(ofd, dr, sh.sh_addr, d->d_buf, d->d_size, rlen);
185
}
186
elferr = elf_errno();
187
if (elferr != 0)
188
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
189
190
/* Generate S{7,8,9} end of block record. */
191
if (gelf_getehdr(e, &eh) == NULL)
192
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
193
elf_errmsg(-1));
194
srec_write_Se(ofd, eh.e_entry, ecp->flags & SREC_FORCE_S3);
195
}
196
197
void
198
create_elf_from_srec(struct elfcopy *ecp, int ifd)
199
{
200
char line[_LINE_BUFSZ], name[_LINE_BUFSZ];
201
uint8_t data[_DATA_BUFSZ];
202
GElf_Ehdr oeh;
203
struct section *s, *shtab;
204
FILE *ifp;
205
uint64_t addr, entry, off, sec_addr;
206
uintmax_t st_value;
207
size_t sz;
208
int _ifd, first, sec_index, in_symtab, symtab_created;
209
char *rlt;
210
char type;
211
212
if ((_ifd = dup(ifd)) < 0)
213
err(EXIT_FAILURE, "dup failed");
214
if ((ifp = fdopen(_ifd, "r")) == NULL)
215
err(EXIT_FAILURE, "fdopen failed");
216
217
/* Create EHDR for output .o file. */
218
if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
219
errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
220
elf_errmsg(-1));
221
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
222
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
223
elf_errmsg(-1));
224
225
/* Initialise e_ident fields. */
226
oeh.e_ident[EI_CLASS] = ecp->oec;
227
oeh.e_ident[EI_DATA] = ecp->oed;
228
/*
229
* TODO: Set OSABI according to the OS platform where elfcopy(1)
230
* was build. (probably)
231
*/
232
oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
233
oeh.e_machine = ecp->oem;
234
oeh.e_type = ET_REL;
235
oeh.e_entry = 0;
236
237
ecp->flags |= RELOCATABLE;
238
239
/* Create .shstrtab section */
240
init_shstrtab(ecp);
241
ecp->shstrtab->off = 0;
242
243
/* Data sections are inserted after EHDR. */
244
off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
245
if (off == 0)
246
errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
247
248
/* Create data sections. */
249
s = NULL;
250
first = 1;
251
sec_index = 1;
252
sec_addr = entry = 0;
253
while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
254
sz = 0;
255
if (line[0] == '\r' || line[0] == '\n')
256
continue;
257
if (line[0] == '$' && line[1] == '$') {
258
ecp->flags |= SYMTAB_EXIST;
259
while ((rlt = fgets(line, _LINE_BUFSZ, ifp)) != NULL) {
260
if (line[0] == '$' && line[1] == '$')
261
break;
262
}
263
if (rlt == NULL)
264
break;
265
continue;
266
}
267
if (line[0] != 'S' || line[1] < '0' || line[1] > '9') {
268
warnx("Invalid srec record");
269
continue;
270
}
271
if (srec_read(line, &type, &addr, data, &sz) < 0) {
272
warnx("Invalid srec record or mismatched checksum");
273
continue;
274
}
275
switch (type) {
276
case '1':
277
case '2':
278
case '3':
279
if (sz == 0)
280
break;
281
if (first || sec_addr != addr) {
282
if (s != NULL)
283
finalize_data_section(s);
284
s = new_data_section(ecp, sec_index, off,
285
addr);
286
if (s == NULL) {
287
warnx("new_data_section failed");
288
break;
289
}
290
sec_index++;
291
sec_addr = addr;
292
first = 0;
293
}
294
append_data(s, data, sz);
295
off += sz;
296
sec_addr += sz;
297
break;
298
case '7':
299
case '8':
300
case '9':
301
entry = addr;
302
break;
303
default:
304
break;
305
}
306
}
307
if (s != NULL)
308
finalize_data_section(s);
309
if (ferror(ifp))
310
warn("fgets failed");
311
312
/* Insert .shstrtab after data sections. */
313
if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
314
errx(EXIT_FAILURE, "elf_newscn failed: %s",
315
elf_errmsg(-1));
316
insert_to_sec_list(ecp, ecp->shstrtab, 1);
317
318
/* Insert section header table here. */
319
shtab = insert_shtab(ecp, 1);
320
321
/*
322
* Rescan and create symbol table if we found '$$' section in
323
* the first scan.
324
*/
325
symtab_created = 0;
326
in_symtab = 0;
327
if (ecp->flags & SYMTAB_EXIST) {
328
if (fseek(ifp, 0, SEEK_SET) < 0) {
329
warn("fseek failed");
330
ecp->flags &= ~SYMTAB_EXIST;
331
goto done;
332
}
333
while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
334
if (in_symtab) {
335
if (line[0] == '$' && line[1] == '$') {
336
in_symtab = 0;
337
continue;
338
}
339
if (sscanf(line, "%s $%jx", name,
340
&st_value) != 2) {
341
warnx("Invalid symbolsrec record");
342
continue;
343
}
344
if (!symtab_created) {
345
create_external_symtab(ecp);
346
symtab_created = 1;
347
}
348
add_to_symtab(ecp, name, st_value, 0, SHN_ABS,
349
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
350
}
351
if (line[0] == '$' && line[1] == '$') {
352
in_symtab = 1;
353
continue;
354
}
355
}
356
}
357
if (ferror(ifp))
358
warn("fgets failed");
359
if (symtab_created) {
360
finalize_external_symtab(ecp);
361
create_symtab_data(ecp);
362
/* Count in .symtab and .strtab section headers. */
363
shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT);
364
} else
365
ecp->flags &= ~SYMTAB_EXIST;
366
367
done:
368
fclose(ifp);
369
370
/* Set entry point. */
371
oeh.e_entry = entry;
372
373
/*
374
* Write the underlying ehdr. Note that it should be called
375
* before elf_setshstrndx() since it will overwrite e->e_shstrndx.
376
*/
377
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
378
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
379
elf_errmsg(-1));
380
381
/* Update sh_name pointer for each section header entry. */
382
update_shdr(ecp, 0);
383
384
/* Renew oeh to get the updated e_shstrndx. */
385
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
386
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
387
elf_errmsg(-1));
388
389
/* Resync section offsets. */
390
resync_sections(ecp);
391
392
/* Store SHDR offset in EHDR. */
393
oeh.e_shoff = shtab->off;
394
395
/* Update ehdr since we modified e_shoff. */
396
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
397
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
398
elf_errmsg(-1));
399
400
/* Write out the output elf object. */
401
if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
402
errx(EXIT_FAILURE, "elf_update() failed: %s",
403
elf_errmsg(-1));
404
405
/* Release allocated resource. */
406
free_elf(ecp);
407
}
408
409
void
410
create_ihex(int ifd, int ofd)
411
{
412
Elf *e;
413
Elf_Scn *scn;
414
Elf_Data *d;
415
GElf_Ehdr eh;
416
GElf_Shdr sh;
417
int elferr;
418
uint16_t addr_hi, old_addr_hi;
419
420
if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
421
errx(EXIT_FAILURE, "elf_begin() failed: %s",
422
elf_errmsg(-1));
423
424
old_addr_hi = 0;
425
scn = NULL;
426
while ((scn = elf_nextscn(e, scn)) != NULL) {
427
if (gelf_getshdr(scn, &sh) == NULL) {
428
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
429
(void) elf_errno();
430
continue;
431
}
432
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
433
sh.sh_type == SHT_NOBITS ||
434
sh.sh_size == 0)
435
continue;
436
if (sh.sh_addr > 0xFFFFFFFF) {
437
warnx("address space too big for Intel Hex file");
438
continue;
439
}
440
(void) elf_errno();
441
if ((d = elf_getdata(scn, NULL)) == NULL) {
442
elferr = elf_errno();
443
if (elferr != 0)
444
warnx("elf_getdata failed: %s", elf_errmsg(-1));
445
continue;
446
}
447
if (d->d_buf == NULL || d->d_size == 0)
448
continue;
449
addr_hi = (sh.sh_addr >> 16) & 0xFFFF;
450
if (addr_hi > 0 && addr_hi != old_addr_hi) {
451
/* Write 04 record if addr_hi is new. */
452
old_addr_hi = addr_hi;
453
ihex_write_04(ofd, addr_hi);
454
}
455
ihex_write_00(ofd, sh.sh_addr, d->d_buf, d->d_size);
456
}
457
elferr = elf_errno();
458
if (elferr != 0)
459
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
460
461
if (gelf_getehdr(e, &eh) == NULL)
462
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
463
elf_errmsg(-1));
464
ihex_write_05(ofd, eh.e_entry);
465
ihex_write_01(ofd);
466
}
467
468
void
469
create_elf_from_ihex(struct elfcopy *ecp, int ifd)
470
{
471
char line[_LINE_BUFSZ];
472
uint8_t data[_DATA_BUFSZ];
473
GElf_Ehdr oeh;
474
struct section *s, *shtab;
475
FILE *ifp;
476
uint64_t addr, addr_base, entry, num, off, rec_addr, sec_addr;
477
size_t sz;
478
int _ifd, first, sec_index;
479
char type;
480
481
if ((_ifd = dup(ifd)) < 0)
482
err(EXIT_FAILURE, "dup failed");
483
if ((ifp = fdopen(_ifd, "r")) == NULL)
484
err(EXIT_FAILURE, "fdopen failed");
485
486
/* Create EHDR for output .o file. */
487
if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
488
errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
489
elf_errmsg(-1));
490
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
491
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
492
elf_errmsg(-1));
493
494
/* Initialise e_ident fields. */
495
oeh.e_ident[EI_CLASS] = ecp->oec;
496
oeh.e_ident[EI_DATA] = ecp->oed;
497
/*
498
* TODO: Set OSABI according to the OS platform where elfcopy(1)
499
* was build. (probably)
500
*/
501
oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
502
oeh.e_machine = ecp->oem;
503
oeh.e_type = ET_REL;
504
oeh.e_entry = 0;
505
506
ecp->flags |= RELOCATABLE;
507
508
/* Create .shstrtab section */
509
init_shstrtab(ecp);
510
ecp->shstrtab->off = 0;
511
512
/* Data sections are inserted after EHDR. */
513
off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
514
if (off == 0)
515
errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
516
517
/* Create data sections. */
518
s = NULL;
519
first = 1;
520
sec_index = 1;
521
addr_base = rec_addr = sec_addr = entry = 0;
522
while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
523
if (line[0] == '\r' || line[0] == '\n')
524
continue;
525
if (line[0] != ':') {
526
warnx("Invalid ihex record");
527
continue;
528
}
529
if (ihex_read(line, &type, &addr, &num, data, &sz) < 0) {
530
warnx("Invalid ihex record or mismatched checksum");
531
continue;
532
}
533
switch (type) {
534
case '0':
535
/* Data record. */
536
if (sz == 0)
537
break;
538
rec_addr = addr_base + addr;
539
if (first || sec_addr != rec_addr) {
540
if (s != NULL)
541
finalize_data_section(s);
542
s = new_data_section(ecp, sec_index, off,
543
rec_addr);
544
if (s == NULL) {
545
warnx("new_data_section failed");
546
break;
547
}
548
sec_index++;
549
sec_addr = rec_addr;
550
first = 0;
551
}
552
append_data(s, data, sz);
553
off += sz;
554
sec_addr += sz;
555
break;
556
case '1':
557
/* End of file record. */
558
goto done;
559
case '2':
560
/* Extended segment address record. */
561
addr_base = addr << 4;
562
break;
563
case '3':
564
/* Start segment address record (CS:IP). Ignored. */
565
break;
566
case '4':
567
/* Extended linear address record. */
568
addr_base = num << 16;
569
break;
570
case '5':
571
/* Start linear address record. */
572
entry = num;
573
break;
574
default:
575
break;
576
}
577
}
578
done:
579
if (s != NULL)
580
finalize_data_section(s);
581
if (ferror(ifp))
582
warn("fgets failed");
583
fclose(ifp);
584
585
/* Insert .shstrtab after data sections. */
586
if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
587
errx(EXIT_FAILURE, "elf_newscn failed: %s",
588
elf_errmsg(-1));
589
insert_to_sec_list(ecp, ecp->shstrtab, 1);
590
591
/* Insert section header table here. */
592
shtab = insert_shtab(ecp, 1);
593
594
/* Set entry point. */
595
oeh.e_entry = entry;
596
597
/*
598
* Write the underlying ehdr. Note that it should be called
599
* before elf_setshstrndx() since it will overwrite e->e_shstrndx.
600
*/
601
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
602
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
603
elf_errmsg(-1));
604
605
/* Update sh_name pointer for each section header entry. */
606
update_shdr(ecp, 0);
607
608
/* Renew oeh to get the updated e_shstrndx. */
609
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
610
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
611
elf_errmsg(-1));
612
613
/* Resync section offsets. */
614
resync_sections(ecp);
615
616
/* Store SHDR offset in EHDR. */
617
oeh.e_shoff = shtab->off;
618
619
/* Update ehdr since we modified e_shoff. */
620
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
621
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
622
elf_errmsg(-1));
623
624
/* Write out the output elf object. */
625
if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
626
errx(EXIT_FAILURE, "elf_update() failed: %s",
627
elf_errmsg(-1));
628
629
/* Release allocated resource. */
630
free_elf(ecp);
631
}
632
633
#define _SEC_NAMESZ 64
634
#define _SEC_INIT_CAP 1024
635
636
static struct section *
637
new_data_section(struct elfcopy *ecp, int sec_index, uint64_t off,
638
uint64_t addr)
639
{
640
char *name;
641
642
if ((name = malloc(_SEC_NAMESZ)) == NULL)
643
errx(EXIT_FAILURE, "malloc failed");
644
snprintf(name, _SEC_NAMESZ, ".sec%d", sec_index);
645
646
return (create_external_section(ecp, name, name, NULL, 0, off,
647
SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, addr, 0));
648
}
649
650
static void
651
finalize_data_section(struct section *s)
652
{
653
Elf_Data *od;
654
655
if ((od = elf_newdata(s->os)) == NULL)
656
errx(EXIT_FAILURE, "elf_newdata() failed: %s",
657
elf_errmsg(-1));
658
od->d_align = s->align;
659
od->d_off = 0;
660
od->d_buf = s->buf;
661
od->d_size = s->sz;
662
od->d_version = EV_CURRENT;
663
}
664
665
static void
666
append_data(struct section *s, const void *buf, size_t sz)
667
{
668
uint8_t *p;
669
670
if (s->buf == NULL) {
671
s->sz = 0;
672
s->cap = _SEC_INIT_CAP;
673
if ((s->buf = malloc(s->cap)) == NULL)
674
err(EXIT_FAILURE, "malloc failed");
675
}
676
677
while (sz + s->sz > s->cap) {
678
s->cap *= 2;
679
if ((s->buf = realloc(s->buf, s->cap)) == NULL)
680
err(EXIT_FAILURE, "realloc failed");
681
}
682
683
p = s->buf;
684
memcpy(&p[s->sz], buf, sz);
685
s->sz += sz;
686
}
687
688
static int
689
srec_read(const char *line, char *type, uint64_t *addr, uint8_t *data,
690
size_t *sz)
691
{
692
uint64_t count, _checksum, num;
693
size_t addr_sz;
694
int checksum, i, len;
695
696
checksum = 0;
697
len = 2;
698
if (read_num(line, &len, &count, 1, &checksum) < 0)
699
return (-1);
700
*type = line[1];
701
switch (*type) {
702
case '0':
703
case '1':
704
case '5':
705
case '9':
706
addr_sz = 2;
707
break;
708
case '2':
709
case '8':
710
addr_sz = 3;
711
break;
712
case '3':
713
case '7':
714
addr_sz = 4;
715
break;
716
default:
717
return (-1);
718
}
719
720
if (read_num(line, &len, addr, addr_sz, &checksum) < 0)
721
return (-1);
722
723
count -= addr_sz + 1;
724
if (*type >= '0' && *type <= '3') {
725
for (i = 0; (uint64_t) i < count; i++) {
726
if (read_num(line, &len, &num, 1, &checksum) < 0)
727
return -1;
728
data[i] = (uint8_t) num;
729
}
730
*sz = count;
731
} else
732
*sz = 0;
733
734
if (read_num(line, &len, &_checksum, 1, NULL) < 0)
735
return (-1);
736
737
if ((int) _checksum != (~checksum & 0xFF))
738
return (-1);
739
740
return (0);
741
}
742
743
static void
744
srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn, GElf_Shdr *sh)
745
{
746
char line[_LINE_BUFSZ];
747
GElf_Sym sym;
748
Elf_Data *d;
749
const char *name;
750
size_t sc;
751
int elferr, i;
752
753
#define _WRITE_LINE do { \
754
if (write(ofd, line, strlen(line)) != (ssize_t) strlen(line)) \
755
errx(EXIT_FAILURE, "write failed"); \
756
} while (0)
757
758
759
(void) elf_errno();
760
if ((d = elf_getdata(scn, NULL)) == NULL) {
761
elferr = elf_errno();
762
if (elferr != 0)
763
warnx("elf_getdata failed: %s",
764
elf_errmsg(-1));
765
return;
766
}
767
if (d->d_buf == NULL || d->d_size == 0)
768
return;
769
770
snprintf(line, sizeof(line), "$$ %s\r\n", ofn);
771
_WRITE_LINE;
772
sc = d->d_size / sh->sh_entsize;
773
for (i = 1; (size_t) i < sc; i++) {
774
if (gelf_getsym(d, i, &sym) != &sym) {
775
warnx("gelf_getsym failed: %s", elf_errmsg(-1));
776
continue;
777
}
778
if (GELF_ST_TYPE(sym.st_info) == STT_SECTION ||
779
GELF_ST_TYPE(sym.st_info) == STT_FILE)
780
continue;
781
if ((name = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL) {
782
warnx("elf_strptr failed: %s", elf_errmsg(-1));
783
continue;
784
}
785
snprintf(line, sizeof(line), " %s $%jx\r\n", name,
786
(uintmax_t) sym.st_value);
787
_WRITE_LINE;
788
}
789
snprintf(line, sizeof(line), "$$ \r\n");
790
_WRITE_LINE;
791
792
#undef _WRITE_LINE
793
}
794
795
static void
796
srec_write_S0(int ofd, const char *ofn)
797
{
798
799
srec_write(ofd, '0', 0, ofn, strlen(ofn));
800
}
801
802
static void
803
srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf, size_t sz,
804
size_t rlen)
805
{
806
const uint8_t *p, *pe;
807
808
p = buf;
809
pe = p + sz;
810
while (pe - p >= (int) rlen) {
811
srec_write(ofd, dr, addr, p, rlen);
812
addr += rlen;
813
p += rlen;
814
}
815
if (pe - p > 0)
816
srec_write(ofd, dr, addr, p, pe - p);
817
}
818
819
static void
820
srec_write_Se(int ofd, uint64_t e_entry, int forceS3)
821
{
822
char er;
823
824
if (e_entry > 0xFFFFFFFF) {
825
warnx("address space too big for S-Record file");
826
return;
827
}
828
829
if (forceS3)
830
er = '7';
831
else {
832
if (e_entry <= 0xFFFF)
833
er = '9';
834
else if (e_entry <= 0xFFFFFF)
835
er = '8';
836
else
837
er = '7';
838
}
839
840
srec_write(ofd, er, e_entry, NULL, 0);
841
}
842
843
static void
844
srec_write(int ofd, char type, uint64_t addr, const void *buf, size_t sz)
845
{
846
char line[_LINE_BUFSZ];
847
const uint8_t *p, *pe;
848
int len, addr_sz, checksum;
849
850
if (type == '0' || type == '1' || type == '5' || type == '9')
851
addr_sz = 2;
852
else if (type == '2' || type == '8')
853
addr_sz = 3;
854
else
855
addr_sz = 4;
856
857
checksum = 0;
858
line[0] = 'S';
859
line[1] = type;
860
len = 2;
861
write_num(line, &len, addr_sz + sz + 1, 1, &checksum);
862
write_num(line, &len, addr, addr_sz, &checksum);
863
for (p = buf, pe = p + sz; p < pe; p++)
864
write_num(line, &len, *p, 1, &checksum);
865
write_num(line, &len, ~checksum & 0xFF, 1, NULL);
866
line[len++] = '\r';
867
line[len++] = '\n';
868
if (write(ofd, line, len) != (ssize_t) len)
869
err(EXIT_FAILURE, "write failed");
870
}
871
872
static void
873
ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz)
874
{
875
uint16_t addr_hi, old_addr_hi;
876
const uint8_t *p, *pe;
877
878
old_addr_hi = (addr >> 16) & 0xFFFF;
879
p = buf;
880
pe = p + sz;
881
while (pe - p >= 16) {
882
ihex_write(ofd, 0, addr, 0, p, 16);
883
addr += 16;
884
p += 16;
885
addr_hi = (addr >> 16) & 0xFFFF;
886
if (addr_hi != old_addr_hi) {
887
old_addr_hi = addr_hi;
888
ihex_write_04(ofd, addr_hi);
889
}
890
}
891
if (pe - p > 0)
892
ihex_write(ofd, 0, addr, 0, p, pe - p);
893
}
894
895
static int
896
ihex_read(const char *line, char *type, uint64_t *addr, uint64_t *num,
897
uint8_t *data, size_t *sz)
898
{
899
uint64_t count, _checksum;
900
int checksum, i, len;
901
902
*sz = 0;
903
checksum = 0;
904
len = 1;
905
if (read_num(line, &len, &count, 1, &checksum) < 0)
906
return (-1);
907
if (read_num(line, &len, addr, 2, &checksum) < 0)
908
return (-1);
909
if (line[len++] != '0')
910
return (-1);
911
*type = line[len++];
912
checksum += *type - '0';
913
switch (*type) {
914
case '0':
915
for (i = 0; (uint64_t) i < count; i++) {
916
if (read_num(line, &len, num, 1, &checksum) < 0)
917
return (-1);
918
data[i] = (uint8_t) *num;
919
}
920
*sz = count;
921
break;
922
case '1':
923
if (count != 0)
924
return (-1);
925
break;
926
case '2':
927
case '4':
928
if (count != 2)
929
return (-1);
930
if (read_num(line, &len, num, 2, &checksum) < 0)
931
return (-1);
932
break;
933
case '3':
934
case '5':
935
if (count != 4)
936
return (-1);
937
if (read_num(line, &len, num, 4, &checksum) < 0)
938
return (-1);
939
break;
940
default:
941
return (-1);
942
}
943
944
if (read_num(line, &len, &_checksum, 1, &checksum) < 0)
945
return (-1);
946
947
if ((checksum & 0xFF) != 0) {
948
return (-1);
949
}
950
951
return (0);
952
}
953
954
static void
955
ihex_write_01(int ofd)
956
{
957
958
ihex_write(ofd, 1, 0, 0, NULL, 0);
959
}
960
961
static void
962
ihex_write_04(int ofd, uint16_t addr)
963
{
964
965
ihex_write(ofd, 4, 0, addr, NULL, 2);
966
}
967
968
static void
969
ihex_write_05(int ofd, uint64_t e_entry)
970
{
971
972
if (e_entry > 0xFFFFFFFF) {
973
warnx("address space too big for Intel Hex file");
974
return;
975
}
976
977
ihex_write(ofd, 5, 0, e_entry, NULL, 4);
978
}
979
980
static void
981
ihex_write(int ofd, int type, uint64_t addr, uint64_t num, const void *buf,
982
size_t sz)
983
{
984
char line[_LINE_BUFSZ];
985
const uint8_t *p, *pe;
986
int len, checksum;
987
988
if (sz > 16)
989
errx(EXIT_FAILURE, "Internal: ihex_write() sz too big");
990
checksum = 0;
991
line[0] = ':';
992
len = 1;
993
write_num(line, &len, sz, 1, &checksum);
994
write_num(line, &len, addr, 2, &checksum);
995
write_num(line, &len, type, 1, &checksum);
996
if (sz > 0) {
997
if (buf != NULL) {
998
for (p = buf, pe = p + sz; p < pe; p++)
999
write_num(line, &len, *p, 1, &checksum);
1000
} else
1001
write_num(line, &len, num, sz, &checksum);
1002
}
1003
write_num(line, &len, (~checksum + 1) & 0xFF, 1, NULL);
1004
line[len++] = '\r';
1005
line[len++] = '\n';
1006
if (write(ofd, line, len) != (ssize_t) len)
1007
err(EXIT_FAILURE, "write failed");
1008
}
1009
1010
static int
1011
read_num(const char *line, int *len, uint64_t *num, size_t sz, int *checksum)
1012
{
1013
uint8_t b;
1014
1015
*num = 0;
1016
for (; sz > 0; sz--) {
1017
if (!ishexdigit(line[*len]) || !ishexdigit(line[*len + 1]))
1018
return (-1);
1019
b = (hex_value(line[*len]) << 4) | hex_value(line[*len + 1]);
1020
*num = (*num << 8) | b;
1021
*len += 2;
1022
if (checksum != NULL)
1023
*checksum = (*checksum + b) & 0xFF;
1024
}
1025
1026
return (0);
1027
}
1028
1029
static void
1030
write_num(char *line, int *len, uint64_t num, size_t sz, int *checksum)
1031
{
1032
uint8_t b;
1033
1034
for (; sz > 0; sz--) {
1035
b = (num >> ((sz - 1) * 8)) & 0xFF;
1036
line[*len] = hex_digit((b >> 4) & 0xF);
1037
line[*len + 1] = hex_digit(b & 0xF);
1038
*len += 2;
1039
if (checksum != NULL)
1040
*checksum = (*checksum + b) & 0xFF;
1041
}
1042
}
1043
1044
static char
1045
hex_digit(uint8_t n)
1046
{
1047
1048
return ((n < 10) ? '0' + n : 'A' + (n - 10));
1049
}
1050
1051
static int
1052
hex_value(int x)
1053
{
1054
1055
if (isdigit(x))
1056
return (x - '0');
1057
else if (x >= 'a' && x <= 'f')
1058
return (x - 'a' + 10);
1059
else
1060
return (x - 'A' + 10);
1061
}
1062
1063
static int
1064
ishexdigit(int x)
1065
{
1066
1067
if (isdigit(x))
1068
return (1);
1069
if ((x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F'))
1070
return (1);
1071
1072
return (0);
1073
}
1074
1075