hex2pp.c (24600B)
1 /* 2 * hex2pp.c -- reference C implementation of hex2++. 3 * 4 * See docs/HEX2pp.md for the spec. Brief summary: 5 * 6 * Input is scanned once. Label definitions are recorded into a table 7 * on the fly; label references emit zero placeholders and append a 8 * fixup record. After the scan, fixups are resolved against the 9 * completed label table and patched into the output buffer. 10 * 11 * Active syntax: 12 * digits in current byte mode -> raw bytes (HEX or BINARY) 13 * :NAME -> label definition 14 * SIGIL NAME [- OTHER] -> label reference (! @ $ ~ % &) 15 * .align N [PATTERN] -> pad to N-byte boundary 16 * .fill N B -> N copies of byte B 17 * .scope / .endscope -> local-label scope (nestable) 18 * # ... / ; ... -> line comment 19 * 20 * Multi-byte reference values are emitted little-endian by default. 21 */ 22 23 #include <ctype.h> 24 #include <errno.h> 25 #include <stdarg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <sys/stat.h> 30 31 #define MAX_INPUT_BYTES (16 * 1024 * 1024) 32 #define MAX_OUTPUT_BYTES (128 * 1024 * 1024) 33 #define MAX_LABELS (1 << 20) 34 #define MAX_FIXUPS (1 << 20) 35 #define MAX_TEXT (8 * 1024 * 1024) 36 #define MAX_TOKEN 4096 37 #define MAX_SCOPE_DEPTH 32 38 #define MAX_SCOPE_HISTORY (1 << 22) 39 40 enum { HEX_MODE, BINARY_MODE }; 41 42 struct InFile { 43 const char *path; 44 char *buf; 45 int len; 46 }; 47 48 struct Label { 49 int name_off; 50 int name_len; 51 long long target_ip; 52 int scope_id; /* 0 = global */ 53 }; 54 55 struct Fixup { 56 long long out_off; /* offset in output_buf to patch */ 57 long long ip_at_ref; /* ip immediately after the reference's bytes */ 58 const char *name; /* points into input buffer */ 59 const char *other; /* NULL if no -OTHER */ 60 const char *src_path; 61 int name_len; 62 int other_len; 63 int scope_hist_off; /* index into scope_history (depth>0 only) */ 64 int scope_depth; 65 int src_line; 66 int sigil; 67 }; 68 69 static struct InFile input_file; 70 71 static char text_buf[MAX_TEXT]; 72 static int text_used; 73 74 static struct Label labels[MAX_LABELS]; 75 static int label_count; 76 77 static struct Fixup fixups[MAX_FIXUPS]; 78 static int fixup_count; 79 80 static int scope_history[MAX_SCOPE_HISTORY]; 81 static int scope_history_used; 82 83 static unsigned char output_buf[MAX_OUTPUT_BYTES]; 84 static long long output_used; 85 86 static long long ip; 87 static long long base_address; 88 static int byte_mode = HEX_MODE; 89 static int big_endian; 90 static int non_executable; 91 static const char *output_path; 92 static int ptrsize = 4; /* width of '&' and '%'; settable via .ptrsize */ 93 static int ptrsize_used; /* a '&'/'%' reference has fixed the width */ 94 95 static int scope_stack[MAX_SCOPE_DEPTH]; 96 static int scope_depth; 97 static int scope_seq; 98 99 static const char *cur_path; 100 static int cur_line; 101 102 /* --- error reporting ---------------------------------------------------- */ 103 104 static void die(const char *fmt, ...) 105 { 106 va_list ap; 107 if (cur_path != NULL) { 108 fprintf(stderr, "%s:%d: hex2pp: ", cur_path, cur_line); 109 } else { 110 fprintf(stderr, "hex2pp: "); 111 } 112 va_start(ap, fmt); 113 vfprintf(stderr, fmt, ap); 114 va_end(ap); 115 fputc('\n', stderr); 116 exit(1); 117 } 118 119 /* --- text / label table ------------------------------------------------- */ 120 121 static int intern(const char *s, int len) 122 { 123 int off; 124 if (text_used + len + 1 > MAX_TEXT) { 125 die("text pool overflow"); 126 } 127 off = text_used; 128 memcpy(text_buf + off, s, (size_t)len); 129 text_buf[off + len] = '\0'; 130 text_used += len + 1; 131 return off; 132 } 133 134 static int name_eq(const struct Label *L, const char *s, int len) 135 { 136 return L->name_len == len && memcmp(text_buf + L->name_off, s, (size_t)len) == 0; 137 } 138 139 static void define_label(const char *s, int len, int scope_id) 140 { 141 if (label_count >= MAX_LABELS) { 142 die("too many labels"); 143 } 144 labels[label_count].name_off = intern(s, len); 145 labels[label_count].name_len = len; 146 labels[label_count].target_ip = ip; 147 labels[label_count].scope_id = scope_id; 148 label_count++; 149 } 150 151 static long long lookup_label_in(const char *s, int len, const int *stack, int depth) 152 { 153 int i; 154 int d; 155 int dotted = (len > 0 && s[0] == '.' && depth > 0); 156 if (dotted) { 157 /* Inside a scope, walk the scope stack innermost-out. A dotted 158 * name resolves to the nearest enclosing definition, so an inner 159 * scope can shadow an outer one with the same local name. */ 160 for (d = depth - 1; d >= 0; d--) { 161 int sid = stack[d]; 162 for (i = 0; i < label_count; i++) { 163 if (labels[i].scope_id == sid && name_eq(&labels[i], s, len)) { 164 return labels[i].target_ip; 165 } 166 } 167 } 168 die("undefined local label '%.*s'", len, s); 169 } else { 170 for (i = 0; i < label_count; i++) { 171 if (labels[i].scope_id == 0 && name_eq(&labels[i], s, len)) { 172 return labels[i].target_ip; 173 } 174 } 175 die("undefined label '%.*s'", len, s); 176 } 177 return 0; /* unreachable */ 178 } 179 180 /* --- I/O ---------------------------------------------------------------- */ 181 182 static void emit_byte(unsigned b) 183 { 184 if (output_used >= MAX_OUTPUT_BYTES) { 185 die("output overflow"); 186 } 187 output_buf[output_used++] = (unsigned char)b; 188 ip++; 189 } 190 191 static long long emit_zeros(long long n) 192 { 193 long long off = output_used; 194 if (output_used + n > MAX_OUTPUT_BYTES) { 195 die("output overflow"); 196 } 197 memset(output_buf + output_used, 0, (size_t)n); 198 output_used += n; 199 ip += n; 200 return off; 201 } 202 203 static void emit_fill(long long n, unsigned char b) 204 { 205 if (output_used + n > MAX_OUTPUT_BYTES) { 206 die("output overflow"); 207 } 208 memset(output_buf + output_used, b, (size_t)n); 209 output_used += n; 210 ip += n; 211 } 212 213 static void write_value(long long out_off, long long v, int width, long long lo, long long hi, int range_check) 214 { 215 int i; 216 unsigned char bytes[8]; 217 218 if (range_check && (v < lo || v > hi)) { 219 die("reference out of range: value=%lld, allowed=[%lld,%lld]", v, lo, hi); 220 } 221 if (width < 1 || width > 8) { 222 die("internal: bad reference width %d", width); 223 } 224 225 for (i = 0; i < width; i++) { 226 bytes[i] = (unsigned char)((unsigned long long)v >> (8 * i)) & 0xff; 227 } 228 if (big_endian) { 229 for (i = 0; i < width; i++) { 230 output_buf[out_off + i] = bytes[width - 1 - i]; 231 } 232 } else { 233 for (i = 0; i < width; i++) { 234 output_buf[out_off + i] = bytes[i]; 235 } 236 } 237 } 238 239 /* --- per-file scanner state -------------------------------------------- */ 240 241 struct Scanner { 242 const char *buf; 243 int len; 244 int pos; 245 }; 246 247 static int eatc(struct Scanner *s) 248 { 249 int c; 250 if (s->pos >= s->len) return -1; 251 c = (unsigned char)s->buf[s->pos++]; 252 if (c == '\n') cur_line++; 253 return c; 254 } 255 256 static int is_space_any(int c) { return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'; } 257 258 static void skip_ws_and_comments(struct Scanner *s) 259 { 260 int c; 261 while (s->pos < s->len) { 262 c = (unsigned char)s->buf[s->pos]; 263 if (is_space_any(c)) { 264 eatc(s); 265 } else if (c == '#' || c == ';') { 266 while (s->pos < s->len && s->buf[s->pos] != '\n') s->pos++; 267 } else { 268 break; 269 } 270 } 271 } 272 273 /* --- byte-mode digit handling ----------------------------------------- */ 274 275 static int byte_digit_count(void) 276 { 277 if (byte_mode == HEX_MODE) return 2; 278 return 8; /* BINARY */ 279 } 280 281 static int is_byte_digit(int c) 282 { 283 if (byte_mode == HEX_MODE) return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); 284 return c == '0' || c == '1'; 285 } 286 287 static int byte_digit_value(int c) 288 { 289 if (c >= '0' && c <= '9') return c - '0'; 290 if (c >= 'a' && c <= 'f') return 10 + (c - 'a'); 291 if (c >= 'A' && c <= 'F') return 10 + (c - 'A'); 292 return -1; 293 } 294 295 static int parse_one_byte_literal(struct Scanner *s, unsigned char *out, int allow_multi, unsigned char *buf, int bufmax, int *outlen) 296 { 297 /* Parse a contiguous run of byte-mode digits (no whitespace inside, 298 * since this is for directive arguments where digit-run terminates the 299 * argument). Returns number of bytes produced. */ 300 int need = byte_digit_count(); 301 int acc = 0; 302 int have = 0; 303 int produced = 0; 304 int c; 305 306 while (s->pos < s->len) { 307 c = (unsigned char)s->buf[s->pos]; 308 if (!is_byte_digit(c)) break; 309 s->pos++; 310 if (byte_mode == HEX_MODE) acc = (acc << 4) | byte_digit_value(c); 311 else acc = (acc << 1) | (c - '0'); 312 have++; 313 if (have == need) { 314 if (allow_multi) { 315 if (produced >= bufmax) die("pattern too large"); 316 buf[produced++] = (unsigned char)(acc & 0xff); 317 } else { 318 if (produced > 0) die("byte literal: too many digits"); 319 *out = (unsigned char)(acc & 0xff); 320 produced = 1; 321 } 322 acc = 0; 323 have = 0; 324 if (!allow_multi) break; 325 } 326 } 327 if (have != 0) die("byte literal: incomplete digits (%d left over)", have); 328 if (produced == 0) die("expected byte literal"); 329 if (outlen) *outlen = produced; 330 return produced; 331 } 332 333 /* Parse a free-flowing byte stream: digits separated by arbitrary 334 * whitespace and comments. Stops at any non-digit non-whitespace 335 * non-comment character. */ 336 static void parse_byte_stream(struct Scanner *s) 337 { 338 int need = byte_digit_count(); 339 int acc = 0; 340 int have = 0; 341 int c; 342 343 for (;;) { 344 if (s->pos >= s->len) break; 345 c = (unsigned char)s->buf[s->pos]; 346 if (is_space_any(c)) { eatc(s); continue; } 347 if (c == '#' || c == ';') { 348 while (s->pos < s->len && s->buf[s->pos] != '\n') s->pos++; 349 continue; 350 } 351 if (!is_byte_digit(c)) break; 352 s->pos++; 353 if (byte_mode == HEX_MODE) acc = (acc << 4) | byte_digit_value(c); 354 else acc = (acc << 1) | (c - '0'); 355 have++; 356 if (have == need) { 357 emit_byte((unsigned)(acc & 0xff)); 358 acc = 0; 359 have = 0; 360 } 361 } 362 if (have != 0) die("byte stream: incomplete digits at end of run (%d left over)", have); 363 } 364 365 /* --- name / token reading --------------------------------------------- */ 366 367 static int is_name_terminator(int c) 368 { 369 /* Per spec: names terminated by whitespace, '-', or '>' (the two 370 * label-arithmetic separators). We also stop at end-of-line comments 371 * and EOF for safety. */ 372 if (c < 0) return 1; 373 if (is_space_any(c)) return 1; 374 if (c == '-' || c == '>') return 1; 375 if (c == '#' || c == ';') return 1; 376 return 0; 377 } 378 379 /* Scan a label name; return pointer span into the input buffer (no copy). */ 380 static int scan_name(struct Scanner *s, const char **out_start) 381 { 382 int start = s->pos; 383 while (s->pos < s->len) { 384 int c = (unsigned char)s->buf[s->pos]; 385 if (is_name_terminator(c)) break; 386 s->pos++; 387 } 388 if (s->pos == start) die("expected label name"); 389 *out_start = s->buf + start; 390 return s->pos - start; 391 } 392 393 /* Decimal integer (for directive arity arguments). */ 394 static long long read_decimal(struct Scanner *s) 395 { 396 long long v = 0; 397 int saw = 0; 398 int c; 399 while (s->pos < s->len) { 400 c = (unsigned char)s->buf[s->pos]; 401 if (c < '0' || c > '9') break; 402 v = v * 10 + (c - '0'); 403 saw = 1; 404 s->pos++; 405 } 406 if (!saw) die("expected decimal integer"); 407 return v; 408 } 409 410 /* --- references ------------------------------------------------------- */ 411 412 struct SigilInfo { 413 int width; 414 int is_rel; 415 long long lo; 416 long long hi; 417 int range_check; 418 }; 419 420 static struct SigilInfo sigil_info(int c) 421 { 422 struct SigilInfo si = {0}; 423 switch (c) { 424 case '!': si.width = 1; si.is_rel = 1; si.lo = -128; si.hi = 127; si.range_check = 1; break; 425 case '@': si.width = 2; si.is_rel = 1; si.lo = -32768; si.hi = 32767; si.range_check = 1; break; 426 case '$': si.width = 2; si.is_rel = 0; si.lo = 0; si.hi = 65535; si.range_check = 1; break; 427 case '~': si.width = 3; si.is_rel = 1; si.lo = -(1LL << 23); si.hi = (1LL << 23) - 1; si.range_check = 1; break; 428 case '%': si.width = ptrsize; si.is_rel = 1; si.lo = 0; si.hi = 0; si.range_check = 0; break; 429 case '&': si.width = ptrsize; si.is_rel = 0; si.lo = 0; si.hi = 0; si.range_check = 0; break; 430 default: die("internal: bad sigil 0x%02x", c); 431 } 432 return si; 433 } 434 435 static void record_fixup(const char *name, int name_len, 436 const char *other, int other_len, 437 int sigil, long long out_off, long long ip_after) 438 { 439 struct Fixup *f; 440 if (fixup_count >= MAX_FIXUPS) die("too many references"); 441 f = &fixups[fixup_count++]; 442 f->out_off = out_off; 443 f->ip_at_ref = ip_after; 444 f->name = name; 445 f->name_len = name_len; 446 f->other = other; 447 f->other_len = other_len; 448 f->sigil = sigil; 449 f->src_path = cur_path; 450 f->src_line = cur_line; 451 f->scope_depth = scope_depth; 452 if (scope_depth > 0) { 453 if (scope_history_used + scope_depth > MAX_SCOPE_HISTORY) { 454 die("scope history overflow"); 455 } 456 f->scope_hist_off = scope_history_used; 457 memcpy(&scope_history[scope_history_used], scope_stack, 458 (size_t)scope_depth * sizeof(int)); 459 scope_history_used += scope_depth; 460 } else { 461 f->scope_hist_off = 0; 462 } 463 } 464 465 static void process_reference(struct Scanner *s, int sigil) 466 { 467 const char *name_start; 468 const char *other_start = NULL; 469 int name_len; 470 int other_len = 0; 471 struct SigilInfo si = sigil_info(sigil); 472 long long out_off; 473 474 if (sigil == '&' || sigil == '%') ptrsize_used = 1; 475 476 /* Sigil already consumed. Read tight LABEL. */ 477 if (s->pos >= s->len || is_name_terminator((unsigned char)s->buf[s->pos])) { 478 die("sigil '%c' not followed by label name", sigil); 479 } 480 name_len = scan_name(s, &name_start); 481 482 /* Optional '-' OTHER or '>' OTHER (tight, no whitespace). 483 * '>' is a synonym for '-', accepted for hex2 compatibility. */ 484 if (s->pos < s->len && (s->buf[s->pos] == '-' || s->buf[s->pos] == '>')) { 485 s->pos++; 486 if (s->pos >= s->len || is_name_terminator((unsigned char)s->buf[s->pos])) { 487 die("'-' must be followed by label name"); 488 } 489 other_len = scan_name(s, &other_start); 490 } 491 492 out_off = emit_zeros(si.width); 493 record_fixup(name_start, name_len, other_start, other_len, 494 sigil, out_off, ip); 495 } 496 497 /* --- directives ------------------------------------------------------- */ 498 499 static int read_directive_name(struct Scanner *s, char *out, int max) 500 { 501 /* '.' already consumed. Read alpha chars. */ 502 int n = 0; 503 while (s->pos < s->len) { 504 int c = (unsigned char)s->buf[s->pos]; 505 if (!isalpha(c)) break; 506 if (n >= max) die("directive name too long"); 507 out[n++] = (char)c; 508 s->pos++; 509 } 510 if (n == 0) die("expected directive name after '.'"); 511 return n; 512 } 513 514 static void skip_inline_ws(struct Scanner *s) 515 { 516 /* Directive arguments do NOT cross newlines: `.align N PATTERN` ends 517 * at end-of-line, otherwise `.align 8\n cc` would slurp `cc` as 518 * pattern. Skip space/tab and inline comments only. */ 519 int c; 520 while (s->pos < s->len) { 521 c = (unsigned char)s->buf[s->pos]; 522 if (c == ' ' || c == '\t' || c == '\r' || c == '\f' || c == '\v') { 523 s->pos++; 524 } else if (c == '#' || c == ';') { 525 while (s->pos < s->len && s->buf[s->pos] != '\n') s->pos++; 526 } else { 527 break; 528 } 529 } 530 } 531 532 static void do_align(struct Scanner *s) 533 { 534 long long N; 535 long long pad; 536 long long target; 537 long long i; 538 unsigned char patbuf[MAX_TOKEN]; 539 int patlen = 0; 540 int has_pattern = 0; 541 int c; 542 543 skip_inline_ws(s); 544 N = read_decimal(s); 545 if (N <= 0 || (N & (N - 1)) != 0) { 546 die(".align: N must be a positive power of two (got %lld)", N); 547 } 548 549 /* Optional pattern: peek -- if next non-ws is a byte digit, parse it. */ 550 skip_inline_ws(s); 551 if (s->pos < s->len) { 552 c = (unsigned char)s->buf[s->pos]; 553 if (is_byte_digit(c)) { 554 parse_one_byte_literal(s, NULL, 1, patbuf, (int)sizeof(patbuf), &patlen); 555 has_pattern = 1; 556 } 557 } 558 559 target = (ip + N - 1) & ~(N - 1); 560 pad = target - ip; 561 if (pad <= 0) return; 562 if (output_used + pad > MAX_OUTPUT_BYTES) die("output overflow"); 563 if (!has_pattern) { 564 memset(output_buf + output_used, 0, (size_t)pad); 565 } else { 566 for (i = 0; i < pad; i++) { 567 output_buf[output_used + i] = patbuf[i % patlen]; 568 } 569 } 570 output_used += pad; 571 ip += pad; 572 } 573 574 static void do_fill(struct Scanner *s) 575 { 576 long long N; 577 unsigned char b; 578 579 skip_inline_ws(s); 580 N = read_decimal(s); 581 if (N < 0) die(".fill: N must be non-negative (got %lld)", N); 582 skip_inline_ws(s); 583 parse_one_byte_literal(s, &b, 0, NULL, 0, NULL); 584 if (N > 0) emit_fill(N, b); 585 } 586 587 static void do_ptrsize(struct Scanner *s) 588 { 589 long long N; 590 skip_inline_ws(s); 591 N = read_decimal(s); 592 if (N != 4 && N != 8) { 593 die(".ptrsize: N must be 4 or 8 (got %lld)", N); 594 } 595 if (ptrsize_used && (int)N != ptrsize) { 596 die(".ptrsize %lld conflicts with already-used width %d", N, ptrsize); 597 } 598 ptrsize = (int)N; 599 } 600 601 static void do_scope_open(void) 602 { 603 if (scope_depth >= MAX_SCOPE_DEPTH) die(".scope: depth overflow"); 604 scope_seq++; 605 scope_stack[scope_depth++] = scope_seq; 606 } 607 608 static void do_scope_close(void) 609 { 610 if (scope_depth <= 0) die(".endscope: not in a scope"); 611 scope_depth--; 612 } 613 614 /* --- main scanner loop ------------------------------------------------ */ 615 616 static void process_file(struct InFile *f) 617 { 618 struct Scanner s = { f->buf, f->len, 0 }; 619 cur_path = f->path; 620 cur_line = 1; 621 622 for (;;) { 623 int c; 624 skip_ws_and_comments(&s); 625 if (s.pos >= s.len) break; 626 c = (unsigned char)s.buf[s.pos]; 627 628 if (c == ':') { 629 const char *name; 630 int n; 631 int dotted; 632 int scope; 633 s.pos++; 634 n = scan_name(&s, &name); 635 /* A dot-prefixed name is scope-local only inside a .scope; 636 * outside, it is an ordinary global name. */ 637 dotted = (n > 0 && name[0] == '.' && scope_depth > 0); 638 scope = dotted ? scope_stack[scope_depth - 1] : 0; 639 define_label(name, n, scope); 640 continue; 641 } 642 643 if (c == '.') { 644 char dn[MAX_TOKEN]; 645 int n; 646 s.pos++; 647 n = read_directive_name(&s, dn, sizeof(dn)); 648 if (n == 5 && memcmp(dn, "align", 5) == 0) do_align(&s); 649 else if (n == 4 && memcmp(dn, "fill", 4) == 0) do_fill(&s); 650 else if (n == 5 && memcmp(dn, "scope", 5) == 0) do_scope_open(); 651 else if (n == 8 && memcmp(dn, "endscope", 8) == 0) do_scope_close(); 652 else if (n == 7 && memcmp(dn, "ptrsize", 7) == 0) do_ptrsize(&s); 653 else die("unknown directive '.%.*s'", n, dn); 654 continue; 655 } 656 657 if (c == '!' || c == '@' || c == '$' || c == '~' || c == '%' || c == '&') { 658 s.pos++; 659 process_reference(&s, c); 660 continue; 661 } 662 663 if (is_byte_digit(c)) { 664 parse_byte_stream(&s); 665 continue; 666 } 667 668 die("unexpected character 0x%02x ('%c')", c, isprint(c) ? c : '?'); 669 } 670 } 671 672 /* --- fixup resolution ------------------------------------------------- */ 673 674 static void patch_fixups(void) 675 { 676 int i; 677 for (i = 0; i < fixup_count; i++) { 678 struct Fixup *f = &fixups[i]; 679 struct SigilInfo si = sigil_info(f->sigil); 680 const int *stack = (f->scope_depth > 0) 681 ? &scope_history[f->scope_hist_off] 682 : NULL; 683 long long t_label; 684 long long value; 685 686 cur_path = f->src_path; 687 cur_line = f->src_line; 688 689 t_label = lookup_label_in(f->name, f->name_len, stack, f->scope_depth); 690 if (f->other != NULL) { 691 long long t_other = lookup_label_in(f->other, f->other_len, 692 stack, f->scope_depth); 693 value = t_label - t_other; 694 } else if (si.is_rel) { 695 value = t_label - f->ip_at_ref; 696 } else { 697 value = t_label + base_address; 698 } 699 write_value(f->out_off, value, si.width, si.lo, si.hi, si.range_check); 700 } 701 } 702 703 /* --- argument parsing & top-level ------------------------------------- */ 704 705 static long long parse_long(const char *s, const char *what) 706 { 707 char *end; 708 long long v; 709 int base = 10; 710 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) base = 16; 711 errno = 0; 712 v = strtoll(s, &end, base); 713 if (errno != 0 || *end != '\0') { 714 fprintf(stderr, "hex2pp: invalid %s: %s\n", what, s); 715 exit(1); 716 } 717 return v; 718 } 719 720 static void load_input(const char *path) 721 { 722 FILE *fp; 723 long sz; 724 char *buf; 725 726 fp = fopen(path, "rb"); 727 if (fp == NULL) { perror(path); exit(1); } 728 if (fseek(fp, 0, SEEK_END) != 0) { perror(path); exit(1); } 729 sz = ftell(fp); 730 if (sz < 0) { perror(path); exit(1); } 731 if (sz > MAX_INPUT_BYTES) { fprintf(stderr, "%s: input too large\n", path); exit(1); } 732 rewind(fp); 733 buf = (char *)malloc((size_t)sz + 1); 734 if (buf == NULL) { fprintf(stderr, "out of memory\n"); exit(1); } 735 if (sz > 0 && fread(buf, 1, (size_t)sz, fp) != (size_t)sz) { 736 perror(path); 737 exit(1); 738 } 739 buf[sz] = '\0'; 740 fclose(fp); 741 742 input_file.path = path; 743 input_file.buf = buf; 744 input_file.len = (int)sz; 745 } 746 747 static void usage(const char *prog) 748 { 749 fprintf(stderr, 750 "usage: %s [-B ADDR] [-E|-e] [-b] [-N] IN OUT\n", 751 prog); 752 } 753 754 int main(int argc, char **argv) 755 { 756 int i; 757 const char *in_path = NULL; 758 759 for (i = 1; i < argc; i++) { 760 const char *a = argv[i]; 761 if (strcmp(a, "-B") == 0) { 762 if (++i >= argc) { usage(argv[0]); return 1; } 763 base_address = parse_long(argv[i], "base address"); 764 } else if (strcmp(a, "-E") == 0) { 765 big_endian = 1; 766 } else if (strcmp(a, "-e") == 0) { 767 big_endian = 0; 768 } else if (strcmp(a, "-b") == 0) { 769 byte_mode = BINARY_MODE; 770 } else if (strcmp(a, "-N") == 0) { 771 non_executable = 1; 772 } else if (a[0] == '-' && a[1] != '\0') { 773 fprintf(stderr, "hex2pp: unknown argument: %s\n", a); 774 usage(argv[0]); 775 return 1; 776 } else if (in_path == NULL) { 777 in_path = a; 778 } else if (output_path == NULL) { 779 output_path = a; 780 } else { 781 fprintf(stderr, "hex2pp: extra positional argument: %s\n", a); 782 usage(argv[0]); 783 return 1; 784 } 785 } 786 787 if (in_path == NULL || output_path == NULL) { 788 usage(argv[0]); 789 return 1; 790 } 791 load_input(in_path); 792 793 ip = 0; 794 output_used = 0; 795 scope_depth = 0; 796 scope_seq = 0; 797 ptrsize = 4; 798 ptrsize_used = 0; 799 process_file(&input_file); 800 if (scope_depth != 0) die(".scope not closed at end of input"); 801 patch_fixups(); 802 803 /* Write output. */ 804 { 805 FILE *fp = fopen(output_path, "wb"); 806 if (fp == NULL) { perror(output_path); return 1; } 807 if (output_used > 0 && 808 fwrite(output_buf, 1, (size_t)output_used, fp) != (size_t)output_used) { 809 perror(output_path); 810 fclose(fp); 811 return 1; 812 } 813 fclose(fp); 814 } 815 816 if (!non_executable) { 817 struct stat st; 818 if (stat(output_path, &st) == 0 && S_ISREG(st.st_mode)) { 819 (void)chmod(output_path, 0750); 820 } 821 } 822 823 return 0; 824 }