2 * Copyright (c) 2010,2011 Kai Wang
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/param.h>
39 ELFTC_VCSID("$Id: ascii.c 3487 2016-08-24 18:12:08Z emaste $");
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,
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,
62 static void srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn,
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,
71 #define _LINE_BUFSZ 1024
72 #define _DATA_BUFSZ 256
75 * Convert ELF object to S-Record.
78 create_srec(struct elfcopy *ecp, int ifd, int ofd, const char *ofn)
90 if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
91 errx(EXIT_FAILURE, "elf_begin() failed: %s",
94 /* Output a symbol table for `symbolsrec' target. */
95 if (!strncmp(ecp->otgt, "symbolsrec", strlen("symbolsrec"))) {
97 while ((scn = elf_nextscn(e, scn)) != NULL) {
98 if (gelf_getshdr(scn, &sh) == NULL) {
99 warnx("gelf_getshdr failed: %s",
104 if (sh.sh_type != SHT_SYMTAB)
106 srec_write_symtab(ofd, ofn, e, scn, &sh);
111 if (ecp->flags & SREC_FORCE_S3)
115 * Find maximum address size in the first iteration.
119 while ((scn = elf_nextscn(e, scn)) != NULL) {
120 if (gelf_getshdr(scn, &sh) == NULL) {
121 warnx("gelf_getshdr failed: %s",
126 if ((sh.sh_flags & SHF_ALLOC) == 0 ||
127 sh.sh_type == SHT_NOBITS ||
130 if ((uint64_t) sh.sh_addr > max_addr)
131 max_addr = sh.sh_addr;
133 elferr = elf_errno();
135 warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
137 if (max_addr <= 0xFFFF)
139 else if (max_addr <= 0xFFFFFF)
145 if (ecp->flags & SREC_FORCE_LEN) {
146 addr_sz = dr - '0' + 1;
147 if (ecp->srec_len < 1)
149 else if (ecp->srec_len + addr_sz + 1 > 255)
150 rlen = 255 - (addr_sz + 1);
152 rlen = ecp->srec_len;
156 /* Generate S0 record which contains the output filename. */
157 srec_write_S0(ofd, ofn);
159 /* Generate S{1,2,3} data records for section data. */
161 while ((scn = elf_nextscn(e, scn)) != NULL) {
162 if (gelf_getshdr(scn, &sh) == NULL) {
163 warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
167 if ((sh.sh_flags & SHF_ALLOC) == 0 ||
168 sh.sh_type == SHT_NOBITS ||
171 if (sh.sh_addr > 0xFFFFFFFF) {
172 warnx("address space too big for S-Record file");
176 if ((d = elf_getdata(scn, NULL)) == NULL) {
177 elferr = elf_errno();
179 warnx("elf_getdata failed: %s", elf_errmsg(-1));
182 if (d->d_buf == NULL || d->d_size == 0)
184 srec_write_Sd(ofd, dr, sh.sh_addr, d->d_buf, d->d_size, rlen);
186 elferr = elf_errno();
188 warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
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",
194 srec_write_Se(ofd, eh.e_entry, ecp->flags & SREC_FORCE_S3);
198 create_elf_from_srec(struct elfcopy *ecp, int ifd)
200 char line[_LINE_BUFSZ], name[_LINE_BUFSZ];
201 uint8_t data[_DATA_BUFSZ];
203 struct section *s, *shtab;
205 uint64_t addr, entry, off, sec_addr;
208 int _ifd, first, sec_index, in_symtab, symtab_created;
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");
217 /* Create EHDR for output .o file. */
218 if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
219 errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
221 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
222 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
225 /* Initialise e_ident fields. */
226 oeh.e_ident[EI_CLASS] = ecp->oec;
227 oeh.e_ident[EI_DATA] = ecp->oed;
229 * TODO: Set OSABI according to the OS platform where elfcopy(1)
230 * was build. (probably)
232 oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
233 oeh.e_machine = ecp->oem;
237 ecp->flags |= RELOCATABLE;
239 /* Create .shstrtab section */
241 ecp->shstrtab->off = 0;
243 /* Data sections are inserted after EHDR. */
244 off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
246 errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
248 /* Create data sections. */
252 sec_addr = entry = 0;
253 while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
255 if (line[0] == '\r' || line[0] == '\n')
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] == '$')
267 if (line[0] != 'S' || line[1] < '0' || line[1] > '9') {
268 warnx("Invalid srec record");
271 if (srec_read(line, &type, &addr, data, &sz) < 0) {
272 warnx("Invalid srec record or mismatched checksum");
281 if (first || sec_addr != addr) {
283 finalize_data_section(s);
284 s = new_data_section(ecp, sec_index, off,
287 warnx("new_data_section failed");
294 append_data(s, data, sz);
308 finalize_data_section(s);
310 warn("fgets failed");
312 /* Insert .shstrtab after data sections. */
313 if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
314 errx(EXIT_FAILURE, "elf_newscn failed: %s",
316 insert_to_sec_list(ecp, ecp->shstrtab, 1);
318 /* Insert section header table here. */
319 shtab = insert_shtab(ecp, 1);
322 * Rescan and create symbol table if we found '$$' section in
327 if (ecp->flags & SYMTAB_EXIST) {
328 if (fseek(ifp, 0, SEEK_SET) < 0) {
329 warn("fseek failed");
330 ecp->flags &= ~SYMTAB_EXIST;
333 while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
335 if (line[0] == '$' && line[1] == '$') {
339 if (sscanf(line, "%s $%jx", name,
341 warnx("Invalid symbolsrec record");
344 if (!symtab_created) {
345 create_external_symtab(ecp);
348 add_to_symtab(ecp, name, st_value, 0, SHN_ABS,
349 ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
351 if (line[0] == '$' && line[1] == '$') {
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);
365 ecp->flags &= ~SYMTAB_EXIST;
370 /* Set entry point. */
374 * Write the underlying ehdr. Note that it should be called
375 * before elf_setshstrndx() since it will overwrite e->e_shstrndx.
377 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
378 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
381 /* Generate section name string table (.shstrtab). */
384 /* Update sh_name pointer for each section header entry. */
387 /* Renew oeh to get the updated e_shstrndx. */
388 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
389 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
392 /* Resync section offsets. */
393 resync_sections(ecp);
395 /* Store SHDR offset in EHDR. */
396 oeh.e_shoff = shtab->off;
398 /* Update ehdr since we modified e_shoff. */
399 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
400 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
403 /* Write out the output elf object. */
404 if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
405 errx(EXIT_FAILURE, "elf_update() failed: %s",
408 /* Release allocated resource. */
413 create_ihex(int ifd, int ofd)
421 uint16_t addr_hi, old_addr_hi;
423 if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
424 errx(EXIT_FAILURE, "elf_begin() failed: %s",
429 while ((scn = elf_nextscn(e, scn)) != NULL) {
430 if (gelf_getshdr(scn, &sh) == NULL) {
431 warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
435 if ((sh.sh_flags & SHF_ALLOC) == 0 ||
436 sh.sh_type == SHT_NOBITS ||
439 if (sh.sh_addr > 0xFFFFFFFF) {
440 warnx("address space too big for Intel Hex file");
444 if ((d = elf_getdata(scn, NULL)) == NULL) {
445 elferr = elf_errno();
447 warnx("elf_getdata failed: %s", elf_errmsg(-1));
450 if (d->d_buf == NULL || d->d_size == 0)
452 addr_hi = (sh.sh_addr >> 16) & 0xFFFF;
453 if (addr_hi > 0 && addr_hi != old_addr_hi) {
454 /* Write 04 record if addr_hi is new. */
455 old_addr_hi = addr_hi;
456 ihex_write_04(ofd, addr_hi);
458 ihex_write_00(ofd, sh.sh_addr, d->d_buf, d->d_size);
460 elferr = elf_errno();
462 warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
464 if (gelf_getehdr(e, &eh) == NULL)
465 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
467 ihex_write_05(ofd, eh.e_entry);
472 create_elf_from_ihex(struct elfcopy *ecp, int ifd)
474 char line[_LINE_BUFSZ];
475 uint8_t data[_DATA_BUFSZ];
477 struct section *s, *shtab;
479 uint64_t addr, addr_base, entry, num, off, rec_addr, sec_addr;
481 int _ifd, first, sec_index;
484 if ((_ifd = dup(ifd)) < 0)
485 err(EXIT_FAILURE, "dup failed");
486 if ((ifp = fdopen(_ifd, "r")) == NULL)
487 err(EXIT_FAILURE, "fdopen failed");
489 /* Create EHDR for output .o file. */
490 if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
491 errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
493 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
494 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
497 /* Initialise e_ident fields. */
498 oeh.e_ident[EI_CLASS] = ecp->oec;
499 oeh.e_ident[EI_DATA] = ecp->oed;
501 * TODO: Set OSABI according to the OS platform where elfcopy(1)
502 * was build. (probably)
504 oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
505 oeh.e_machine = ecp->oem;
509 ecp->flags |= RELOCATABLE;
511 /* Create .shstrtab section */
513 ecp->shstrtab->off = 0;
515 /* Data sections are inserted after EHDR. */
516 off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
518 errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
520 /* Create data sections. */
524 addr_base = rec_addr = sec_addr = entry = 0;
525 while (fgets(line, _LINE_BUFSZ, ifp) != NULL) {
526 if (line[0] == '\r' || line[0] == '\n')
528 if (line[0] != ':') {
529 warnx("Invalid ihex record");
532 if (ihex_read(line, &type, &addr, &num, data, &sz) < 0) {
533 warnx("Invalid ihex record or mismatched checksum");
541 rec_addr = addr_base + addr;
542 if (first || sec_addr != rec_addr) {
544 finalize_data_section(s);
545 s = new_data_section(ecp, sec_index, off,
548 warnx("new_data_section failed");
555 append_data(s, data, sz);
560 /* End of file record. */
563 /* Extended segment address record. */
564 addr_base = addr << 4;
567 /* Start segment address record (CS:IP). Ignored. */
570 /* Extended linear address record. */
571 addr_base = num << 16;
574 /* Start linear address record. */
583 finalize_data_section(s);
585 warn("fgets failed");
588 /* Insert .shstrtab after data sections. */
589 if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
590 errx(EXIT_FAILURE, "elf_newscn failed: %s",
592 insert_to_sec_list(ecp, ecp->shstrtab, 1);
594 /* Insert section header table here. */
595 shtab = insert_shtab(ecp, 1);
597 /* Set entry point. */
601 * Write the underlying ehdr. Note that it should be called
602 * before elf_setshstrndx() since it will overwrite e->e_shstrndx.
604 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
605 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
608 /* Generate section name string table (.shstrtab). */
611 /* Update sh_name pointer for each section header entry. */
614 /* Renew oeh to get the updated e_shstrndx. */
615 if (gelf_getehdr(ecp->eout, &oeh) == NULL)
616 errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
619 /* Resync section offsets. */
620 resync_sections(ecp);
622 /* Store SHDR offset in EHDR. */
623 oeh.e_shoff = shtab->off;
625 /* Update ehdr since we modified e_shoff. */
626 if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
627 errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
630 /* Write out the output elf object. */
631 if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
632 errx(EXIT_FAILURE, "elf_update() failed: %s",
635 /* Release allocated resource. */
639 #define _SEC_NAMESZ 64
640 #define _SEC_INIT_CAP 1024
642 static struct section *
643 new_data_section(struct elfcopy *ecp, int sec_index, uint64_t off,
648 if ((name = malloc(_SEC_NAMESZ)) == NULL)
649 errx(EXIT_FAILURE, "malloc failed");
650 snprintf(name, _SEC_NAMESZ, ".sec%d", sec_index);
652 return (create_external_section(ecp, name, name, NULL, 0, off,
653 SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, addr, 0));
657 finalize_data_section(struct section *s)
661 if ((od = elf_newdata(s->os)) == NULL)
662 errx(EXIT_FAILURE, "elf_newdata() failed: %s",
664 od->d_align = s->align;
668 od->d_version = EV_CURRENT;
672 append_data(struct section *s, const void *buf, size_t sz)
676 if (s->buf == NULL) {
678 s->cap = _SEC_INIT_CAP;
679 if ((s->buf = malloc(s->cap)) == NULL)
680 err(EXIT_FAILURE, "malloc failed");
683 while (sz + s->sz > s->cap) {
685 if ((s->buf = realloc(s->buf, s->cap)) == NULL)
686 err(EXIT_FAILURE, "realloc failed");
690 memcpy(&p[s->sz], buf, sz);
695 srec_read(const char *line, char *type, uint64_t *addr, uint8_t *data,
698 uint64_t count, _checksum, num;
700 int checksum, i, len;
704 if (read_num(line, &len, &count, 1, &checksum) < 0)
726 if (read_num(line, &len, addr, addr_sz, &checksum) < 0)
729 count -= addr_sz + 1;
730 if (*type >= '0' && *type <= '3') {
731 for (i = 0; (uint64_t) i < count; i++) {
732 if (read_num(line, &len, &num, 1, &checksum) < 0)
734 data[i] = (uint8_t) num;
740 if (read_num(line, &len, &_checksum, 1, NULL) < 0)
743 if ((int) _checksum != (~checksum & 0xFF))
750 srec_write_symtab(int ofd, const char *ofn, Elf *e, Elf_Scn *scn, GElf_Shdr *sh)
752 char line[_LINE_BUFSZ];
759 #define _WRITE_LINE do { \
760 if (write(ofd, line, strlen(line)) != (ssize_t) strlen(line)) \
761 errx(EXIT_FAILURE, "write failed"); \
766 if ((d = elf_getdata(scn, NULL)) == NULL) {
767 elferr = elf_errno();
769 warnx("elf_getdata failed: %s",
773 if (d->d_buf == NULL || d->d_size == 0)
776 snprintf(line, sizeof(line), "$$ %s\r\n", ofn);
778 sc = d->d_size / sh->sh_entsize;
779 for (i = 1; (size_t) i < sc; i++) {
780 if (gelf_getsym(d, i, &sym) != &sym) {
781 warnx("gelf_getsym failed: %s", elf_errmsg(-1));
784 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION ||
785 GELF_ST_TYPE(sym.st_info) == STT_FILE)
787 if ((name = elf_strptr(e, sh->sh_link, sym.st_name)) == NULL) {
788 warnx("elf_strptr failed: %s", elf_errmsg(-1));
791 snprintf(line, sizeof(line), " %s $%jx\r\n", name,
792 (uintmax_t) sym.st_value);
795 snprintf(line, sizeof(line), "$$ \r\n");
802 srec_write_S0(int ofd, const char *ofn)
805 srec_write(ofd, '0', 0, ofn, strlen(ofn));
809 srec_write_Sd(int ofd, char dr, uint64_t addr, const void *buf, size_t sz,
812 const uint8_t *p, *pe;
816 while (pe - p >= (int) rlen) {
817 srec_write(ofd, dr, addr, p, rlen);
822 srec_write(ofd, dr, addr, p, pe - p);
826 srec_write_Se(int ofd, uint64_t e_entry, int forceS3)
830 if (e_entry > 0xFFFFFFFF) {
831 warnx("address space too big for S-Record file");
838 if (e_entry <= 0xFFFF)
840 else if (e_entry <= 0xFFFFFF)
846 srec_write(ofd, er, e_entry, NULL, 0);
850 srec_write(int ofd, char type, uint64_t addr, const void *buf, size_t sz)
852 char line[_LINE_BUFSZ];
853 const uint8_t *p, *pe;
854 int len, addr_sz, checksum;
856 if (type == '0' || type == '1' || type == '5' || type == '9')
858 else if (type == '2' || type == '8')
867 write_num(line, &len, addr_sz + sz + 1, 1, &checksum);
868 write_num(line, &len, addr, addr_sz, &checksum);
869 for (p = buf, pe = p + sz; p < pe; p++)
870 write_num(line, &len, *p, 1, &checksum);
871 write_num(line, &len, ~checksum & 0xFF, 1, NULL);
874 if (write(ofd, line, len) != (ssize_t) len)
875 err(EXIT_FAILURE, "write failed");
879 ihex_write_00(int ofd, uint64_t addr, const void *buf, size_t sz)
881 uint16_t addr_hi, old_addr_hi;
882 const uint8_t *p, *pe;
884 old_addr_hi = (addr >> 16) & 0xFFFF;
887 while (pe - p >= 16) {
888 ihex_write(ofd, 0, addr, 0, p, 16);
891 addr_hi = (addr >> 16) & 0xFFFF;
892 if (addr_hi != old_addr_hi) {
893 old_addr_hi = addr_hi;
894 ihex_write_04(ofd, addr_hi);
898 ihex_write(ofd, 0, addr, 0, p, pe - p);
902 ihex_read(const char *line, char *type, uint64_t *addr, uint64_t *num,
903 uint8_t *data, size_t *sz)
905 uint64_t count, _checksum;
906 int checksum, i, len;
911 if (read_num(line, &len, &count, 1, &checksum) < 0)
913 if (read_num(line, &len, addr, 2, &checksum) < 0)
915 if (line[len++] != '0')
918 checksum += *type - '0';
921 for (i = 0; (uint64_t) i < count; i++) {
922 if (read_num(line, &len, num, 1, &checksum) < 0)
924 data[i] = (uint8_t) *num;
936 if (read_num(line, &len, num, 2, &checksum) < 0)
943 if (read_num(line, &len, num, 4, &checksum) < 0)
950 if (read_num(line, &len, &_checksum, 1, &checksum) < 0)
953 if ((checksum & 0xFF) != 0) {
961 ihex_write_01(int ofd)
964 ihex_write(ofd, 1, 0, 0, NULL, 0);
968 ihex_write_04(int ofd, uint16_t addr)
971 ihex_write(ofd, 4, 0, addr, NULL, 2);
975 ihex_write_05(int ofd, uint64_t e_entry)
978 if (e_entry > 0xFFFFFFFF) {
979 warnx("address space too big for Intel Hex file");
983 ihex_write(ofd, 5, 0, e_entry, NULL, 4);
987 ihex_write(int ofd, int type, uint64_t addr, uint64_t num, const void *buf,
990 char line[_LINE_BUFSZ];
991 const uint8_t *p, *pe;
995 errx(EXIT_FAILURE, "Internal: ihex_write() sz too big");
999 write_num(line, &len, sz, 1, &checksum);
1000 write_num(line, &len, addr, 2, &checksum);
1001 write_num(line, &len, type, 1, &checksum);
1004 for (p = buf, pe = p + sz; p < pe; p++)
1005 write_num(line, &len, *p, 1, &checksum);
1007 write_num(line, &len, num, sz, &checksum);
1009 write_num(line, &len, (~checksum + 1) & 0xFF, 1, NULL);
1012 if (write(ofd, line, len) != (ssize_t) len)
1013 err(EXIT_FAILURE, "write failed");
1017 read_num(const char *line, int *len, uint64_t *num, size_t sz, int *checksum)
1022 for (; sz > 0; sz--) {
1023 if (!ishexdigit(line[*len]) || !ishexdigit(line[*len + 1]))
1025 b = (hex_value(line[*len]) << 4) | hex_value(line[*len + 1]);
1026 *num = (*num << 8) | b;
1028 if (checksum != NULL)
1029 *checksum = (*checksum + b) & 0xFF;
1036 write_num(char *line, int *len, uint64_t num, size_t sz, int *checksum)
1040 for (; sz > 0; sz--) {
1041 b = (num >> ((sz - 1) * 8)) & 0xFF;
1042 line[*len] = hex_digit((b >> 4) & 0xF);
1043 line[*len + 1] = hex_digit(b & 0xF);
1045 if (checksum != NULL)
1046 *checksum = (*checksum + b) & 0xFF;
1051 hex_digit(uint8_t n)
1054 return ((n < 10) ? '0' + n : 'A' + (n - 10));
1063 else if (x >= 'a' && x <= 'f')
1064 return (x - 'a' + 10);
1066 return (x - 'A' + 10);
1075 if ((x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F'))