acc.cpp revision 7810bc9abd7c2c415d87b62dea1ff75d5fdc7397
1/* 2 Obfuscated Tiny C Compiler 3 4 Copyright (C) 2001-2003 Fabrice Bellard 5 6 This software is provided 'as-is', without any express or implied 7 warranty. In no event will the authors be held liable for any damages 8 arising from the use of this software. 9 10 Permission is granted to anyone to use this software for any purpose, 11 including commercial applications, and to alter it and redistribute it 12 freely, subject to the following restrictions: 13 14 1. The origin of this software must not be misrepresented; you must not 15 claim that you wrote the original software. If you use this software 16 in a product, an acknowledgment in the product and its documentation 17 *is* required. 18 2. Altered source versions must be plainly marked as such, and must not be 19 misrepresented as being the original software. 20 3. This notice may not be removed or altered from any source distribution. 21 */ 22 23#include <ctype.h> 24#include <dlfcn.h> 25#include <stdarg.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29 30#if defined(__arm__) 31#include <unistd.h> 32#endif 33 34#include "disassem.h" 35 36namespace acc { 37 38class compiler { 39 class CodeBuf { 40 char* ind; 41 char* pProgramBase; 42 43 void release() { 44 if (pProgramBase != 0) { 45 free(pProgramBase); 46 pProgramBase = 0; 47 } 48 } 49 50 public: 51 CodeBuf() { 52 pProgramBase = 0; 53 ind = 0; 54 } 55 56 ~CodeBuf() { 57 release(); 58 } 59 60 void init(int size) { 61 release(); 62 pProgramBase = (char*) calloc(1, size); 63 ind = pProgramBase; 64 } 65 66 void o(int n) { 67 /* cannot use unsigned, so we must do a hack */ 68 while (n && n != -1) { 69 *ind++ = n; 70 n = n >> 8; 71 } 72 } 73 74 int o4(int n) { 75 int result = (int) ind; 76 * (int*) ind = n; 77 ind += 4; 78 return result; 79 } 80 81 /* 82 * Output a byte. Handles all values, 0..ff. 83 */ 84 void ob(int n) { 85 *ind++ = n; 86 } 87 88 /* output a symbol and patch all calls to it */ 89 void gsym(int t) { 90 int n; 91 while (t) { 92 n = *(int *) t; /* next value */ 93 *(int *) t = ((int) ind) - t - 4; 94 t = n; 95 } 96 } 97 98 /* psym is used to put an instruction with a data field which is a 99 reference to a symbol. It is in fact the same as oad ! */ 100 int psym(int n, int t) { 101 return oad(n, t); 102 } 103 104 /* instruction + address */ 105 int oad(int n, int t) { 106 o(n); 107 *(int *) ind = t; 108 t = (int) ind; 109 ind = ind + 4; 110 return t; 111 } 112 113 inline void* getBase() { 114 return (void*) pProgramBase; 115 } 116 117 int getSize() { 118 return ind - pProgramBase; 119 } 120 121 int getPC() { 122 return (int) ind; 123 } 124 }; 125 126 class CodeGenerator { 127 public: 128 CodeGenerator() {} 129 virtual ~CodeGenerator() {} 130 131 virtual void init(CodeBuf* pCodeBuf) { 132 this->pCodeBuf = pCodeBuf; 133 } 134 135 /* returns address to patch with local variable size 136 */ 137 virtual int functionEntry(int argCount) = 0; 138 139 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) = 0; 140 141 /* load immediate value */ 142 virtual void li(int t) = 0; 143 144 virtual int gjmp(int t) = 0; 145 146 /* l = 0: je, l == 1: jne */ 147 virtual int gtst(bool l, int t) = 0; 148 149 virtual void gcmp(int op) = 0; 150 151 virtual void genOp(int op) = 0; 152 153 virtual void clearECX() = 0; 154 155 virtual void pushEAX() = 0; 156 157 virtual void popECX() = 0; 158 159 virtual void storeEAXToAddressECX(bool isInt) = 0; 160 161 virtual void loadEAXIndirect(bool isInt) = 0; 162 163 virtual void leaEAX(int ea) = 0; 164 165 virtual void storeEAX(int ea) = 0; 166 167 virtual void loadEAX(int ea, bool isIncDec, int op) = 0; 168 169 virtual int beginFunctionCallArguments() = 0; 170 171 virtual void storeEAToArg(int l) = 0; 172 173 virtual void endFunctionCallArguments(int a, int l) = 0; 174 175 176 virtual int callForward(int symbol) = 0; 177 178 virtual void callRelative(int t) = 0; 179 180 virtual void callIndirect(int l) = 0; 181 182 virtual void adjustStackAfterCall(int l, bool isIndirect) = 0; 183 184 virtual int disassemble(FILE* out) = 0; 185 186 /* output a symbol and patch all calls to it */ 187 virtual void gsym(int t) { 188 pCodeBuf->gsym(t); 189 } 190 191 virtual int finishCompile() { 192#if defined(__arm__) 193 const long base = long(pCodeBuf->getBase()); 194 const long curr = base + long(pCodeBuf->getSize()); 195 int err = cacheflush(base, curr, 0); 196 return err; 197#else 198 return 0; 199#endif 200 } 201 202 /** 203 * Adjust relative branches by this amount. 204 */ 205 virtual int jumpOffset() = 0; 206 207 protected: 208 void o(int n) { 209 pCodeBuf->o(n); 210 } 211 212 /* 213 * Output a byte. Handles all values, 0..ff. 214 */ 215 void ob(int n) { 216 pCodeBuf->ob(n); 217 } 218 219 /* psym is used to put an instruction with a data field which is a 220 reference to a symbol. It is in fact the same as oad ! */ 221 int psym(int n, int t) { 222 return oad(n, t); 223 } 224 225 /* instruction + address */ 226 int oad(int n, int t) { 227 return pCodeBuf->oad(n,t); 228 } 229 230 int getBase() { 231 return (int) pCodeBuf->getBase(); 232 } 233 234 int getPC() { 235 return pCodeBuf->getPC(); 236 } 237 238 int o4(int data) { 239 return pCodeBuf->o4(data); 240 } 241 private: 242 CodeBuf* pCodeBuf; 243 }; 244 245 class ARMCodeGenerator : public CodeGenerator { 246 public: 247 ARMCodeGenerator() {} 248 virtual ~ARMCodeGenerator() {} 249 250 /* returns address to patch with local variable size 251 */ 252 virtual int functionEntry(int argCount) { 253 fprintf(stderr, "functionEntry(%d);\n", argCount); 254 // sp -> arg4 arg5 ... 255 // Push our register-based arguments back on the stack 256 if (argCount > 0) { 257 int regArgCount = argCount <= 4 ? argCount : 4; 258 o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {} 259 } 260 // sp -> arg0 arg1 ... 261 o4(0xE92D4800); // stmfd sp!, {fp, lr} 262 // sp, fp -> oldfp, retadr, arg0 arg1 .... 263 o4(0xE1A0B00D); // mov fp, sp 264 return o4(0xE24DD000); // sub sp, sp, # <local variables> 265 } 266 267 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { 268 fprintf(stderr, "functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize); 269 // Patch local variable allocation code: 270 if (localVariableSize < 0 || localVariableSize > 255) { 271 error("localVariables out of range: %d", localVariableSize); 272 } 273 *(char*) (localVariableAddress) = localVariableSize; 274 275 // sp -> locals .... fp -> oldfp, retadr, arg0, arg1, ... 276 o4(0xE1A0E00B); // mov lr, fp 277 o4(0xE59BB000); // ldr fp, [fp] 278 o4(0xE28ED004); // add sp, lr, #4 279 // sp -> retadr, arg0, ... 280 o4(0xE8BD4000); // ldmfd sp!, {lr} 281 // sp -> arg0 .... 282 if (argCount > 0) { 283 // We store the PC into the lr so we can adjust the sp before 284 // returning. We need to pull off the registers we pushed 285 // earlier. We don't need to actually store them anywhere, 286 // just adjust the stack. 287 int regArgCount = argCount <= 4 ? argCount : 4; 288 o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2 289 } 290 o4(0xE12FFF1E); // bx lr 291 } 292 293 /* load immediate value */ 294 virtual void li(int t) { 295 fprintf(stderr, "li(%d);\n", t); 296 if (t >= 0 && t < 255) { 297 o4(0xE3A00000 + t); // mov r0, #0 298 } else if (t >= -256 && t < 0) { 299 // mvn means move constant ^ ~0 300 o4(0xE3E00001 - t); // mvn r0, #0 301 } else { 302 o4(0xE51F0000); // ldr r0, .L3 303 o4(0xEA000000); // b .L99 304 o4(t); // .L3: .word 0 305 // .L99: 306 } 307 } 308 309 virtual int gjmp(int t) { 310 fprintf(stderr, "gjmp(%d);\n", t); 311 return o4(0xEA000000 | encodeAddress(t)); // b .L33 312 } 313 314 /* l = 0: je, l == 1: jne */ 315 virtual int gtst(bool l, int t) { 316 fprintf(stderr, "gtst(%d, %d);\n", l, t); 317 o4(0xE3500000); // cmp r0,#0 318 int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq 319 return o4(branch | encodeAddress(t)); 320 } 321 322 virtual void gcmp(int op) { 323 fprintf(stderr, "gcmp(%d);\n", op); 324 o4(0xE1510000); // cmp r1, r1 325 switch(op) { 326 case OP_EQUALS: 327 o4(0x03A00001); // moveq r0,#1 328 o4(0x13A00000); // movne r0,#0 329 break; 330 case OP_NOT_EQUALS: 331 o4(0x03A00000); // moveq r0,#0 332 o4(0x13A00001); // movne r0,#1 333 break; 334 case OP_LESS_EQUAL: 335 o4(0xD3A00001); // movle r0,#1 336 o4(0xC3A00000); // movgt r0,#0 337 break; 338 case OP_GREATER: 339 o4(0xD3A00000); // movle r0,#0 340 o4(0xC3A00001); // movgt r0,#1 341 break; 342 case OP_GREATER_EQUAL: 343 o4(0xA3A00001); // movge r0,#1 344 o4(0xB3A00000); // movlt r0,#0 345 break; 346 case OP_LESS: 347 o4(0xA3A00000); // movge r0,#0 348 o4(0xB3A00001); // movlt r0,#1 349 break; 350 default: 351 error("Unknown comparison op %d", op); 352 break; 353 } 354 } 355 356 virtual void genOp(int op) { 357 fprintf(stderr, "genOp(%d);\n", op); 358 switch(op) { 359 case OP_MUL: 360 o4(0x0E0000091); // mul r0,r1,r0 361 break; 362 case OP_PLUS: 363 o4(0xE0810000); // add r0,r1,r0 364 break; 365 case OP_MINUS: 366 o4(0xE0410000); // sub r0,r1,r0 367 break; 368 case OP_SHIFT_LEFT: 369 o4(0xE1A00011); // lsl r0,r1,r0 370 break; 371 case OP_SHIFT_RIGHT: 372 o4(0xE1A00051); // asr r0,r1,r0 373 break; 374 case OP_BIT_AND: 375 o4(0xE0010000); // and r0,r1,r0 376 break; 377 case OP_BIT_XOR: 378 o4(0xE0210000); // eor r0,r1,r0 379 break; 380 case OP_BIT_OR: 381 o4(0xE1810000); // orr r0,r1,r0 382 break; 383 case OP_BIT_NOT: 384 o4(0xE1E00000); // mvn r0, r0 385 break; 386 default: 387 error("Unimplemented op %d\n", op); 388 break; 389 } 390#if 0 391 o(decodeOp(op)); 392 if (op == OP_MOD) 393 o(0x92); /* xchg %edx, %eax */ 394#endif 395 } 396 397 virtual void clearECX() { 398 fprintf(stderr, "clearECX();\n"); 399 o4(0xE3A01000); // mov r1, #0 400 } 401 402 virtual void pushEAX() { 403 fprintf(stderr, "pushEAX();\n"); 404 o4(0xE92D0001); // stmfd sp!,{r0} 405 } 406 407 virtual void popECX() { 408 fprintf(stderr, "popECX();\n"); 409 o4(0xE8BD0002); // ldmfd sp!,{r1} 410 } 411 412 virtual void storeEAXToAddressECX(bool isInt) { 413 fprintf(stderr, "storeEAXToAddressECX(%d);\n", isInt); 414 if (isInt) { 415 o4(0xE5810000); // str r0, [r1] 416 } else { 417 o4(0xE5C10000); // strb r0, [r1] 418 } 419 } 420 421 virtual void loadEAXIndirect(bool isInt) { 422 fprintf(stderr, "loadEAXIndirect(%d);\n", isInt); 423 if (isInt) 424 o4(0xE5900000); // ldr r0, [r0] 425 else 426 o4(0xE5D00000); // ldrb r0, [r0] 427 } 428 429 virtual void leaEAX(int ea) { 430 fprintf(stderr, "leaEAX(%d);\n", ea); 431 if (ea < LOCAL) { 432 // Local, fp relative 433 if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { 434 error("Offset out of range: %08x", ea); 435 } 436 if (ea < 0) { 437 o4(0xE24B0F00 | (0xff & ((-ea) >> 2))); // sub r0, fp, #ea 438 } else { 439 o4(0xE28B0F00 | (0xff & (ea >> 2))); // add r0, fp, #ea 440 } 441 } else { 442 // Global, absolute. 443 o4(0xE59F0000); // ldr r0, .L1 444 o4(0xEA000000); // b .L99 445 o4(ea); // .L1: .word 0 446 // .L99: 447 } 448 } 449 450 virtual void storeEAX(int ea) { 451 fprintf(stderr, "storeEAX(%d);\n", ea); 452 if (ea < LOCAL) { 453 // Local, fp relative 454 if (ea < -4095 || ea > 4095) { 455 error("Offset out of range: %08x", ea); 456 } 457 if (ea < 0) { 458 o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] 459 } else { 460 o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] 461 } 462 } else{ 463 // Global, absolute 464 o4(0xE59F1000); // ldr r1, .L1 465 o4(0xEA000000); // b .L99 466 o4(ea); // .L1: .word 0 467 o4(0xE5810000); // .L99: str r0, [r1] 468 } 469 } 470 471 virtual void loadEAX(int ea, bool isIncDec, int op) { 472 fprintf(stderr, "loadEAX(%d, %d, %d);\n", ea, isIncDec, op); 473 if (ea < LOCAL) { 474 // Local, fp relative 475 if (ea < -4095 || ea > 4095) { 476 error("Offset out of range: %08x", ea); 477 } 478 if (ea < 0) { 479 o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] 480 } else { 481 o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] 482 } 483 } else { 484 // Global, absolute 485 o4(0xE59F2000); // ldr r2, .L1 486 o4(0xEA000000); // b .L99 487 o4(ea); // .L1: .word ea 488 o4(0xE5920000); // .L99: ldr r0, [r2] 489 } 490 491 if (isIncDec) { 492 switch (op) { 493 case OP_INCREMENT: 494 o4(0xE2801001); // add r1, r0, #1 495 break; 496 case OP_DECREMENT: 497 o4(0xE2401001); // sub r1, r0, #1 498 break; 499 default: 500 error("unknown opcode: %d", op); 501 } 502 if (ea < LOCAL) { 503 // Local, fp relative 504 // Don't need range check, was already checked above 505 if (ea < 0) { 506 o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea] 507 } else { 508 o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea] 509 } 510 } else{ 511 // Global, absolute 512 // r2 is already set up from before. 513 o4(0xE5821000); // str r1, [r2] 514 } 515 } 516 } 517 518 virtual int beginFunctionCallArguments() { 519 fprintf(stderr, "beginFunctionCallArguments();\n"); 520 return o4(0xE24DDF00); // Placeholder 521 } 522 523 virtual void storeEAToArg(int l) { 524 fprintf(stderr, "storeEAToArg(%d);\n", l); 525 if (l < 0 || l > 4096-4) { 526 error("l out of range for stack offset: 0x%08x", l); 527 } 528 o4(0xE58D0000 + l); // str r0, [sp, #4] 529 } 530 531 virtual void endFunctionCallArguments(int a, int l) { 532 fprintf(stderr, "endFunctionCallArguments(0x%08x, %d);\n", a, l); 533 if (l < 0 || l > 0x3FC) { 534 error("L out of range for stack adjustment: 0x%08x", l); 535 } 536 * (int*) a = 0xE24DDF00 | (l >> 2); // sub sp, sp, #0 << 2 537 int argCount = l >> 2; 538 if (argCount > 0) { 539 int regArgCount = argCount > 4 ? 4 : argCount; 540 o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{} 541 } 542 } 543 544 virtual int callForward(int symbol) { 545 fprintf(stderr, "callForward(%d);\n", symbol); 546 // Forward calls are always short (local) 547 return o4(0xEB000000 | encodeAddress(symbol)); 548 } 549 550 virtual void callRelative(int t) { 551 fprintf(stderr, "callRelative(%d);\n", t); 552 int abs = t + getPC() + jumpOffset(); 553 fprintf(stderr, "abs=%d (0x%08x)\n", abs, abs); 554 if (t >= - (1 << 25) && t < (1 << 25)) { 555 o4(0xEB000000 | encodeAddress(t)); 556 } else { 557 // Long call. 558 o4(0xE59FC000); // ldr r12, .L1 559 o4(0xEA000000); // b .L99 560 o4(t - 12); // .L1: .word 0 561 o4(0xE08CC00F); // .L99: add r12,pc 562 o4(0xE12FFF3C); // blx r12 563 } 564 } 565 566 virtual void callIndirect(int l) { 567 fprintf(stderr, "callIndirect(%d);\n", l); 568 int argCount = l >> 2; 569 int poppedArgs = argCount > 4 ? 4 : argCount; 570 int adjustedL = l - (poppedArgs << 2); 571 if (adjustedL < 0 || adjustedL > 4096-4) { 572 error("l out of range for stack offset: 0x%08x", l); 573 } 574 o4(0xE59DC000 | (0xfff & adjustedL)); // ldr r12, [sp,#adjustedL] 575 o4(0xE12FFF3C); // blx r12 576 } 577 578 virtual void adjustStackAfterCall(int l, bool isIndirect) { 579 fprintf(stderr, "adjustStackAfterCall(%d, %d);\n", l, isIndirect); 580 int argCount = l >> 2; 581 int stackArgs = argCount > 4 ? argCount - 4 : 0; 582 int stackUse = stackArgs + (isIndirect ? 1 : 0); 583 if (stackUse) { 584 if (stackUse < 0 || stackUse > 255) { 585 error("L out of range for stack adjustment: 0x%08x", l); 586 } 587 o4(0xE28DDF00 | stackUse); // add sp, sp, #stackUse << 2 588 } 589 } 590 591 virtual int jumpOffset() { 592 return 8; 593 } 594 595 /* output a symbol and patch all calls to it */ 596 virtual void gsym(int t) { 597 fprintf(stderr, "gsym(0x%x)\n", t); 598 int n; 599 int base = getBase(); 600 int pc = getPC(); 601 fprintf(stderr, "pc = 0x%x\n", pc); 602 while (t) { 603 int data = * (int*) t; 604 int decodedOffset = ((BRANCH_REL_ADDRESS_MASK & data) << 2); 605 if (decodedOffset == 0) { 606 n = 0; 607 } else { 608 n = base + decodedOffset; /* next value */ 609 } 610 *(int *) t = (data & ~BRANCH_REL_ADDRESS_MASK) 611 | encodeRelAddress(pc - t - 8); 612 t = n; 613 } 614 } 615 616 virtual int disassemble(FILE* out) { 617 disasmOut = out; 618 disasm_interface_t di; 619 di.di_readword = disassemble_readword; 620 di.di_printaddr = disassemble_printaddr; 621 di.di_printf = disassemble_printf; 622 623 int base = getBase(); 624 int pc = getPC(); 625 for(int i = base; i < pc; i += 4) { 626 fprintf(out, "%08x: %08x ", i, *(int*) i); 627 ::disasm(&di, i, 0); 628 } 629 return 0; 630 } 631 632 private: 633 static FILE* disasmOut; 634 635 static u_int 636 disassemble_readword(u_int address) 637 { 638 return(*((u_int *)address)); 639 } 640 641 static void 642 disassemble_printaddr(u_int address) 643 { 644 fprintf(disasmOut, "0x%08x", address); 645 } 646 647 static void 648 disassemble_printf(const char *fmt, ...) { 649 va_list ap; 650 va_start(ap, fmt); 651 vfprintf(disasmOut, fmt, ap); 652 va_end(ap); 653 } 654 655 static const int BRANCH_REL_ADDRESS_MASK = 0x00ffffff; 656 657 /** Encode a relative address that might also be 658 * a label. 659 */ 660 int encodeAddress(int value) { 661 int base = getBase(); 662 if (value >= base && value <= getPC() ) { 663 // This is a label, encode it relative to the base. 664 value = value - base; 665 } 666 return encodeRelAddress(value); 667 } 668 669 int encodeRelAddress(int value) { 670 return BRANCH_REL_ADDRESS_MASK & (value >> 2); 671 } 672 673 void error(const char* fmt,...) { 674 va_list ap; 675 va_start(ap, fmt); 676 vfprintf(stderr, fmt, ap); 677 va_end(ap); 678 exit(12); 679 } 680 }; 681 682 class X86CodeGenerator : public CodeGenerator { 683 public: 684 X86CodeGenerator() {} 685 virtual ~X86CodeGenerator() {} 686 687 /* returns address to patch with local variable size 688 */ 689 virtual int functionEntry(int argCount) { 690 o(0xe58955); /* push %ebp, mov %esp, %ebp */ 691 return oad(0xec81, 0); /* sub $xxx, %esp */ 692 } 693 694 virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { 695 o(0xc3c9); /* leave, ret */ 696 *(int *) localVariableAddress = localVariableSize; /* save local variables */ 697 } 698 699 /* load immediate value */ 700 virtual void li(int t) { 701 oad(0xb8, t); /* mov $xx, %eax */ 702 } 703 704 virtual int gjmp(int t) { 705 return psym(0xe9, t); 706 } 707 708 /* l = 0: je, l == 1: jne */ 709 virtual int gtst(bool l, int t) { 710 o(0x0fc085); /* test %eax, %eax, je/jne xxx */ 711 return psym(0x84 + l, t); 712 } 713 714 virtual void gcmp(int op) { 715 int t = decodeOp(op); 716 o(0xc139); /* cmp %eax,%ecx */ 717 li(0); 718 o(0x0f); /* setxx %al */ 719 o(t + 0x90); 720 o(0xc0); 721 } 722 723 virtual void genOp(int op) { 724 o(decodeOp(op)); 725 if (op == OP_MOD) 726 o(0x92); /* xchg %edx, %eax */ 727 } 728 729 virtual void clearECX() { 730 oad(0xb9, 0); /* movl $0, %ecx */ 731 } 732 733 virtual void pushEAX() { 734 o(0x50); /* push %eax */ 735 } 736 737 virtual void popECX() { 738 o(0x59); /* pop %ecx */ 739 } 740 741 virtual void storeEAXToAddressECX(bool isInt) { 742 o(0x0188 + isInt); /* movl %eax/%al, (%ecx) */ 743 } 744 745 virtual void loadEAXIndirect(bool isInt) { 746 if (isInt) 747 o(0x8b); /* mov (%eax), %eax */ 748 else 749 o(0xbe0f); /* movsbl (%eax), %eax */ 750 ob(0); /* add zero in code */ 751 } 752 753 virtual void leaEAX(int ea) { 754 gmov(10, ea); /* leal EA, %eax */ 755 } 756 757 virtual void storeEAX(int ea) { 758 gmov(6, ea); /* mov %eax, EA */ 759 } 760 761 virtual void loadEAX(int ea, bool isIncDec, int op) { 762 gmov(8, ea); /* mov EA, %eax */ 763 if (isIncDec) { 764 /* Implement post-increment or post decrement. 765 */ 766 gmov(0, ea); /* 83 ADD */ 767 o(decodeOp(op)); 768 } 769 } 770 771 virtual int beginFunctionCallArguments() { 772 return oad(0xec81, 0); /* sub $xxx, %esp */ 773 } 774 775 virtual void storeEAToArg(int l) { 776 oad(0x248489, l); /* movl %eax, xxx(%esp) */ 777 } 778 779 virtual void endFunctionCallArguments(int a, int l) { 780 * (int*) a = l; 781 } 782 783 virtual int callForward(int symbol) { 784 return psym(0xe8, symbol); /* call xxx */ 785 } 786 787 virtual void callRelative(int t) { 788 psym(0xe8, t); /* call xxx */ 789 } 790 791 virtual void callIndirect(int l) { 792 oad(0x2494ff, l); /* call *xxx(%esp) */ 793 } 794 795 virtual void adjustStackAfterCall(int l, bool isIndirect) { 796 if (isIndirect) { 797 l += 4; 798 } 799 oad(0xc481, l); /* add $xxx, %esp */ 800 } 801 802 virtual int jumpOffset() { 803 return 5; 804 } 805 806 virtual int disassemble(FILE* out) { 807 return 1; 808 } 809 810 private: 811 static const int operatorHelper[]; 812 813 int decodeOp(int op) { 814 if (op < 0 || op > OP_COUNT) { 815 fprintf(stderr, "Out-of-range operator: %d\n", op); 816 exit(1); 817 } 818 return operatorHelper[op]; 819 } 820 821 void gmov(int l, int t) { 822 o(l + 0x83); 823 oad((t < LOCAL) << 7 | 5, t); 824 } 825 }; 826 827 /* vars: value of variables 828 loc : local variable index 829 glo : global variable index 830 ind : output code ptr 831 rsym: return symbol 832 prog: output code 833 dstk: define stack 834 dptr, dch: macro state 835 */ 836 int tok, tokc, tokl, ch, vars, rsym, loc, glo, sym_stk, dstk, 837 dptr, dch, last_id; 838 void* pSymbolBase; 839 void* pGlobalBase; 840 void* pVarsBase; 841 FILE* file; 842 843 CodeBuf codeBuf; 844 CodeGenerator* pGen; 845 846 static const int ALLOC_SIZE = 99999; 847 848 /* depends on the init string */ 849 static const int TOK_STR_SIZE = 48; 850 static const int TOK_IDENT = 0x100; 851 static const int TOK_INT = 0x100; 852 static const int TOK_IF = 0x120; 853 static const int TOK_ELSE = 0x138; 854 static const int TOK_WHILE = 0x160; 855 static const int TOK_BREAK = 0x190; 856 static const int TOK_RETURN = 0x1c0; 857 static const int TOK_FOR = 0x1f8; 858 static const int TOK_DEFINE = 0x218; 859 static const int TOK_MAIN = 0x250; 860 861 static const int TOK_DUMMY = 1; 862 static const int TOK_NUM = 2; 863 864 static const int LOCAL = 0x200; 865 866 static const int SYM_FORWARD = 0; 867 static const int SYM_DEFINE = 1; 868 869 /* tokens in string heap */ 870 static const int TAG_TOK = ' '; 871 static const int TAG_MACRO = 2; 872 873 static const int OP_INCREMENT = 0; 874 static const int OP_DECREMENT = 1; 875 static const int OP_MUL = 2; 876 static const int OP_DIV = 3; 877 static const int OP_MOD = 4; 878 static const int OP_PLUS = 5; 879 static const int OP_MINUS = 6; 880 static const int OP_SHIFT_LEFT = 7; 881 static const int OP_SHIFT_RIGHT = 8; 882 static const int OP_LESS_EQUAL = 9; 883 static const int OP_GREATER_EQUAL = 10; 884 static const int OP_LESS = 11; 885 static const int OP_GREATER = 12; 886 static const int OP_EQUALS = 13; 887 static const int OP_NOT_EQUALS = 14; 888 static const int OP_LOGICAL_AND = 15; 889 static const int OP_LOGICAL_OR = 16; 890 static const int OP_BIT_AND = 17; 891 static const int OP_BIT_XOR = 18; 892 static const int OP_BIT_OR = 19; 893 static const int OP_BIT_NOT = 20; 894 static const int OP_LOGICAL_NOT = 21; 895 static const int OP_COUNT = 22; 896 897 /* Operators are searched from front, the two-character operators appear 898 * before the single-character operators with the same first character. 899 * @ is used to pad out single-character operators. 900 */ 901 static const char* operatorChars; 902 static const char operatorLevel[]; 903 904 void pdef(int t) { 905 *(char *) dstk++ = t; 906 } 907 908 void inp() { 909 if (dptr) { 910 ch = *(char *) dptr++; 911 if (ch == TAG_MACRO) { 912 dptr = 0; 913 ch = dch; 914 } 915 } else 916 ch = fgetc(file); 917 /* printf("ch=%c 0x%x\n", ch, ch); */ 918 } 919 920 int isid() { 921 return isalnum(ch) | (ch == '_'); 922 } 923 924 /* read a character constant */ 925 void getq() { 926 if (ch == '\\') { 927 inp(); 928 if (ch == 'n') 929 ch = '\n'; 930 } 931 } 932 933 void next() { 934 int l, a; 935 936 while (isspace(ch) | (ch == '#')) { 937 if (ch == '#') { 938 inp(); 939 next(); 940 if (tok == TOK_DEFINE) { 941 next(); 942 pdef(TAG_TOK); /* fill last ident tag */ 943 *(int *) tok = SYM_DEFINE; 944 *(int *) (tok + 4) = dstk; /* define stack */ 945 } 946 /* well we always save the values ! */ 947 while (ch != '\n') { 948 pdef(ch); 949 inp(); 950 } 951 pdef(ch); 952 pdef(TAG_MACRO); 953 } 954 inp(); 955 } 956 tokl = 0; 957 tok = ch; 958 /* encode identifiers & numbers */ 959 if (isid()) { 960 pdef(TAG_TOK); 961 last_id = dstk; 962 while (isid()) { 963 pdef(ch); 964 inp(); 965 } 966 if (isdigit(tok)) { 967 tokc = strtol((char*) last_id, 0, 0); 968 tok = TOK_NUM; 969 } else { 970 *(char *) dstk = TAG_TOK; /* no need to mark end of string (we 971 suppose data is initialized to zero by calloc) */ 972 tok = (int) (strstr((char*) sym_stk, (char*) (last_id - 1)) 973 - sym_stk); 974 *(char *) dstk = 0; /* mark real end of ident for dlsym() */ 975 tok = tok * 8 + TOK_IDENT; 976 if (tok > TOK_DEFINE) { 977 tok = vars + tok; 978 /* printf("tok=%s %x\n", last_id, tok); */ 979 /* define handling */ 980 if (*(int *) tok == SYM_DEFINE) { 981 dptr = *(int *) (tok + 4); 982 dch = ch; 983 inp(); 984 next(); 985 } 986 } 987 } 988 } else { 989 inp(); 990 if (tok == '\'') { 991 tok = TOK_NUM; 992 getq(); 993 tokc = ch; 994 inp(); 995 inp(); 996 } else if ((tok == '/') & (ch == '*')) { 997 inp(); 998 while (ch) { 999 while (ch != '*') 1000 inp(); 1001 inp(); 1002 if (ch == '/') 1003 ch = 0; 1004 } 1005 inp(); 1006 next(); 1007 } else if ((tok == '/') & (ch == '/')) { 1008 inp(); 1009 while (ch && (ch != '\n')) { 1010 inp(); 1011 } 1012 inp(); 1013 next(); 1014 } else { 1015 const char* t = operatorChars; 1016 int opIndex = 0; 1017 while ((l = *t++) != 0) { 1018 a = *t++; 1019 tokl = operatorLevel[opIndex]; 1020 tokc = opIndex; 1021 if ((l == tok) & ((a == ch) | (a == '@'))) { 1022#if 0 1023 printf("%c%c -> tokl=%d tokc=0x%x\n", 1024 l, a, tokl, tokc); 1025#endif 1026 if (a == ch) { 1027 inp(); 1028 tok = TOK_DUMMY; /* dummy token for double tokens */ 1029 } 1030 break; 1031 } 1032 opIndex++; 1033 } 1034 if (l == 0) { 1035 tokl = 0; 1036 tokc = 0; 1037 } 1038 } 1039 } 1040#if 0 1041 { 1042 int p; 1043 1044 printf("tok=0x%x ", tok); 1045 if (tok >= TOK_IDENT) { 1046 printf("'"); 1047 if (tok> TOK_DEFINE) 1048 p = sym_stk + 1 + (tok - vars - TOK_IDENT) / 8; 1049 else 1050 p = sym_stk + 1 + (tok - TOK_IDENT) / 8; 1051 while (*(char *)p != TAG_TOK && *(char *)p) 1052 printf("%c", *(char *)p++); 1053 printf("'\n"); 1054 } else if (tok == TOK_NUM) { 1055 printf("%d\n", tokc); 1056 } else { 1057 printf("'%c'\n", tok); 1058 } 1059 } 1060#endif 1061 } 1062 1063 void error(const char *fmt, ...) { 1064 va_list ap; 1065 1066 va_start(ap, fmt); 1067 fprintf(stderr, "%ld: ", ftell((FILE *) file)); 1068 vfprintf(stderr, fmt, ap); 1069 fprintf(stderr, "\n"); 1070 va_end(ap); 1071 exit(1); 1072 } 1073 1074 void skip(int c) { 1075 if (tok != c) { 1076 error("'%c' expected", c); 1077 } 1078 next(); 1079 } 1080 1081 /* l is one if '=' parsing wanted (quick hack) */ 1082 void unary(int l) { 1083 int n, t, a, c; 1084 t = 0; 1085 n = 1; /* type of expression 0 = forward, 1 = value, other = 1086 lvalue */ 1087 if (tok == '\"') { 1088 pGen->li(glo); 1089 while (ch != '\"') { 1090 getq(); 1091 *(char *) glo++ = ch; 1092 inp(); 1093 } 1094 *(char *) glo = 0; 1095 glo = (glo + 4) & -4; /* align heap */ 1096 inp(); 1097 next(); 1098 } else { 1099 c = tokl; 1100 a = tokc; 1101 t = tok; 1102 next(); 1103 if (t == TOK_NUM) { 1104 pGen->li(a); 1105 } else if (c == 2) { 1106 /* -, +, !, ~ */ 1107 unary(0); 1108 pGen->clearECX(); 1109 if (t == '!') 1110 pGen->gcmp(a); 1111 else 1112 pGen->genOp(a); 1113 } else if (t == '(') { 1114 expr(); 1115 skip(')'); 1116 } else if (t == '*') { 1117 /* parse cast */ 1118 skip('('); 1119 t = tok; /* get type */ 1120 next(); /* skip int/char/void */ 1121 next(); /* skip '*' or '(' */ 1122 if (tok == '*') { 1123 /* function type */ 1124 skip('*'); 1125 skip(')'); 1126 skip('('); 1127 skip(')'); 1128 t = 0; 1129 } 1130 skip(')'); 1131 unary(0); 1132 if (tok == '=') { 1133 next(); 1134 pGen->pushEAX(); 1135 expr(); 1136 pGen->popECX(); 1137 pGen->storeEAXToAddressECX(t == TOK_INT); 1138 } else if (t) { 1139 pGen->loadEAXIndirect(t == TOK_INT); 1140 } 1141 } else if (t == '&') { 1142 pGen->leaEAX(*(int *) tok); 1143 next(); 1144 } else { 1145 n = *(int *) t; 1146 /* forward reference: try dlsym */ 1147 if (!n) { 1148 n = (int) dlsym(RTLD_DEFAULT, (char*) last_id); 1149 } 1150 if ((tok == '=') & l) { 1151 /* assignment */ 1152 next(); 1153 expr(); 1154 pGen->storeEAX(n); 1155 } else if (tok != '(') { 1156 /* variable */ 1157 pGen->loadEAX(n, tokl == 11, tokc); 1158 if (tokl == 11) { 1159 next(); 1160 } 1161 } 1162 } 1163 } 1164 1165 /* function call */ 1166 if (tok == '(') { 1167 if (n == 1) 1168 pGen->pushEAX(); 1169 1170 /* push args and invert order */ 1171 a = pGen->beginFunctionCallArguments(); 1172 next(); 1173 l = 0; 1174 while (tok != ')') { 1175 expr(); 1176 pGen->storeEAToArg(l); 1177 if (tok == ',') 1178 next(); 1179 l = l + 4; 1180 } 1181 pGen->endFunctionCallArguments(a, l); 1182 next(); 1183 if (!n) { 1184 /* forward reference */ 1185 t = t + 4; 1186 *(int *) t = pGen->callForward(*(int *) t); 1187 } else if (n == 1) { 1188 pGen->callIndirect(l); 1189 } else { 1190 pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset()); 1191 } 1192 if (l || n == 1) 1193 pGen->adjustStackAfterCall(l, n == 1); 1194 } 1195 } 1196 1197 void sum(int l) { 1198 int t, n, a; 1199 t = 0; 1200 if (l-- == 1) 1201 unary(1); 1202 else { 1203 sum(l); 1204 a = 0; 1205 while (l == tokl) { 1206 n = tok; 1207 t = tokc; 1208 next(); 1209 1210 if (l > 8) { 1211 a = pGen->gtst(t == OP_LOGICAL_OR, a); /* && and || output code generation */ 1212 sum(l); 1213 } else { 1214 pGen->pushEAX(); 1215 sum(l); 1216 pGen->popECX(); 1217 1218 if ((l == 4) | (l == 5)) { 1219 pGen->gcmp(t); 1220 } else { 1221 pGen->genOp(t); 1222 } 1223 } 1224 } 1225 /* && and || output code generation */ 1226 if (a && l > 8) { 1227 a = pGen->gtst(t == OP_LOGICAL_OR, a); 1228 pGen->li(t != OP_LOGICAL_OR); 1229 pGen->gjmp(5); /* jmp $ + 5 (sizeof li, FIXME for ARM) */ 1230 pGen->gsym(a); 1231 pGen->li(t == OP_LOGICAL_OR); 1232 } 1233 } 1234 } 1235 1236 void expr() { 1237 sum(11); 1238 } 1239 1240 int test_expr() { 1241 expr(); 1242 return pGen->gtst(0, 0); 1243 } 1244 1245 void block(int l) { 1246 int a, n, t; 1247 1248 if (tok == TOK_IF) { 1249 next(); 1250 skip('('); 1251 a = test_expr(); 1252 skip(')'); 1253 block(l); 1254 if (tok == TOK_ELSE) { 1255 next(); 1256 n = pGen->gjmp(0); /* jmp */ 1257 pGen->gsym(a); 1258 block(l); 1259 pGen->gsym(n); /* patch else jmp */ 1260 } else { 1261 pGen->gsym(a); /* patch if test */ 1262 } 1263 } else if ((tok == TOK_WHILE) | (tok == TOK_FOR)) { 1264 t = tok; 1265 next(); 1266 skip('('); 1267 if (t == TOK_WHILE) { 1268 n = codeBuf.getPC(); // top of loop, target of "next" iteration 1269 a = test_expr(); 1270 } else { 1271 if (tok != ';') 1272 expr(); 1273 skip(';'); 1274 n = codeBuf.getPC(); 1275 a = 0; 1276 if (tok != ';') 1277 a = test_expr(); 1278 skip(';'); 1279 if (tok != ')') { 1280 t = pGen->gjmp(0); 1281 expr(); 1282 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); 1283 pGen->gsym(t); 1284 n = t + 4; 1285 } 1286 } 1287 skip(')'); 1288 block((int) &a); 1289 pGen->gjmp(n - codeBuf.getPC() - pGen->jumpOffset()); /* jmp */ 1290 pGen->gsym(a); 1291 } else if (tok == '{') { 1292 next(); 1293 /* declarations */ 1294 decl(1); 1295 while (tok != '}') 1296 block(l); 1297 next(); 1298 } else { 1299 if (tok == TOK_RETURN) { 1300 next(); 1301 if (tok != ';') 1302 expr(); 1303 rsym = pGen->gjmp(rsym); /* jmp */ 1304 } else if (tok == TOK_BREAK) { 1305 next(); 1306 *(int *) l = pGen->gjmp(*(int *) l); 1307 } else if (tok != ';') 1308 expr(); 1309 skip(';'); 1310 } 1311 } 1312 1313 /* 'l' is true if local declarations */ 1314 void decl(int l) { 1315 int a; 1316 1317 while ((tok == TOK_INT) | ((tok != -1) & (!l))) { 1318 if (tok == TOK_INT) { 1319 next(); 1320 while (tok != ';') { 1321 if (l) { 1322 loc = loc + 4; 1323 *(int *) tok = -loc; 1324 } else { 1325 *(int *) tok = glo; 1326 glo = glo + 4; 1327 } 1328 next(); 1329 if (tok == ',') 1330 next(); 1331 } 1332 skip(';'); 1333 } else { 1334 /* patch forward references (XXX: do not work for function 1335 pointers) */ 1336 pGen->gsym(*(int *) (tok + 4)); 1337 /* put function address */ 1338 *(int *) tok = codeBuf.getPC(); 1339 next(); 1340 skip('('); 1341 a = 8; 1342 int argCount = 0; 1343 while (tok != ')') { 1344 /* read param name and compute offset */ 1345 *(int *) tok = a; 1346 a = a + 4; 1347 next(); 1348 if (tok == ',') 1349 next(); 1350 argCount++; 1351 } 1352 next(); /* skip ')' */ 1353 rsym = loc = 0; 1354 a = pGen->functionEntry(argCount); 1355 block(0); 1356 pGen->gsym(rsym); 1357 pGen->functionExit(argCount, a, loc); 1358 } 1359 } 1360 } 1361 1362 void cleanup() { 1363 if (sym_stk != 0) { 1364 free((void*) sym_stk); 1365 sym_stk = 0; 1366 } 1367 if (pGlobalBase != 0) { 1368 free((void*) pGlobalBase); 1369 pGlobalBase = 0; 1370 } 1371 if (pVarsBase != 0) { 1372 free(pVarsBase); 1373 pVarsBase = 0; 1374 } 1375 if (pGen) { 1376 delete pGen; 1377 pGen = 0; 1378 } 1379 } 1380 1381 void clear() { 1382 tok = 0; 1383 tokc = 0; 1384 tokl = 0; 1385 ch = 0; 1386 vars = 0; 1387 rsym = 0; 1388 loc = 0; 1389 glo = 0; 1390 sym_stk = 0; 1391 dstk = 0; 1392 dptr = 0; 1393 dch = 0; 1394 last_id = 0; 1395 file = 0; 1396 pGlobalBase = 0; 1397 pVarsBase = 0; 1398 pGen = 0; 1399 } 1400 1401 void setArchitecture(const char* architecture) { 1402 delete pGen; 1403 pGen = 0; 1404 1405 if (architecture != NULL) { 1406 if (strcmp(architecture, "arm") == 0) { 1407 pGen = new ARMCodeGenerator(); 1408 } else if (strcmp(architecture, "x86") == 0) { 1409 pGen = new X86CodeGenerator(); 1410 } else { 1411 fprintf(stderr, "Unknown architecture %s", architecture); 1412 } 1413 } 1414 1415 if (pGen == NULL) { 1416 pGen = new ARMCodeGenerator(); 1417 } 1418 } 1419 1420public: 1421 struct args { 1422 args() { 1423 architecture = 0; 1424 } 1425 const char* architecture; 1426 }; 1427 1428 compiler() { 1429 clear(); 1430 } 1431 1432 ~compiler() { 1433 cleanup(); 1434 } 1435 1436 int compile(FILE* in, args& args) { 1437 cleanup(); 1438 clear(); 1439 codeBuf.init(ALLOC_SIZE); 1440 setArchitecture(args.architecture); 1441 pGen->init(&codeBuf); 1442 file = in; 1443 sym_stk = (int) calloc(1, ALLOC_SIZE); 1444 dstk = (int) strcpy((char*) sym_stk, 1445 " int if else while break return for define main ") 1446 + TOK_STR_SIZE; 1447 pGlobalBase = calloc(1, ALLOC_SIZE); 1448 glo = (int) pGlobalBase; 1449 pVarsBase = calloc(1, ALLOC_SIZE); 1450 vars = (int) pVarsBase; 1451 inp(); 1452 next(); 1453 decl(0); 1454 pGen->finishCompile(); 1455 return 0; 1456 } 1457 1458 int run(int argc, char** argv) { 1459 typedef int (*mainPtr)(int argc, char** argv); 1460 mainPtr aMain = (mainPtr) *(int*) (vars + TOK_MAIN); 1461 if (!aMain) { 1462 fprintf(stderr, "Could not find function \"main\".\n"); 1463 return -1; 1464 } 1465 return aMain(argc, argv); 1466 } 1467 1468 int dump(FILE* out) { 1469 fwrite(codeBuf.getBase(), 1, codeBuf.getSize(), out); 1470 return 0; 1471 } 1472 1473 int disassemble(FILE* out) { 1474 return pGen->disassemble(out); 1475 } 1476 1477}; 1478 1479const char* compiler::operatorChars = 1480 "++--*@/@%@+@-@<<>><=>=<@>@==!=&&||&@^@|@~@!@"; 1481 1482const char compiler::operatorLevel[] = 1483 {11, 11, 1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 1484 5, 5, /* ==, != */ 1485 9, 10, /* &&, || */ 1486 6, 7, 8, /* & ^ | */ 1487 2, 2 /* ~ ! */ 1488 }; 1489 1490FILE* compiler::ARMCodeGenerator::disasmOut; 1491 1492const int compiler::X86CodeGenerator::operatorHelper[] = { 1493 0x1, // ++ 1494 0xff, // -- 1495 0xc1af0f, // * 1496 0xf9f79991, // / 1497 0xf9f79991, // % (With manual assist to swap results) 1498 0xc801, // + 1499 0xd8f7c829, // - 1500 0xe0d391, // << 1501 0xf8d391, // >> 1502 0xe, // <= 1503 0xd, // >= 1504 0xc, // < 1505 0xf, // > 1506 0x4, // == 1507 0x5, // != 1508 0x0, // && 1509 0x1, // || 1510 0xc821, // & 1511 0xc831, // ^ 1512 0xc809, // | 1513 0xd0f7, // ~ 1514 0x4 // ! 1515}; 1516 1517} // namespace acc 1518 1519// This is a separate function so it can easily be set by breakpoint in gdb. 1520int run(acc::compiler& c, int argc, char** argv) { 1521 return c.run(argc, argv); 1522} 1523 1524int main(int argc, char** argv) { 1525 bool doDump = false; 1526 bool doDisassemble = false; 1527 const char* inFile = NULL; 1528 const char* outFile = NULL; 1529 const char* architecture = "arm"; 1530 int i; 1531 for (i = 1; i < argc; i++) { 1532 char* arg = argv[i]; 1533 if (arg[0] == '-') { 1534 switch (arg[1]) { 1535 case 'a': 1536 if (i + 1 >= argc) { 1537 fprintf(stderr, "Expected architecture after -a\n"); 1538 return 2; 1539 } 1540 architecture = argv[i+1]; 1541 i += 1; 1542 break; 1543 case 'd': 1544 if (i + 1 >= argc) { 1545 fprintf(stderr, "Expected filename after -d\n"); 1546 return 2; 1547 } 1548 doDump = true; 1549 outFile = argv[i + 1]; 1550 i += 1; 1551 break; 1552 case 'S': 1553 doDisassemble = true; 1554 break; 1555 default: 1556 fprintf(stderr, "Unrecognized flag %s\n", arg); 1557 return 3; 1558 } 1559 } else if (inFile == NULL) { 1560 inFile = arg; 1561 } else { 1562 break; 1563 } 1564 } 1565 1566 FILE* in = stdin; 1567 if (inFile) { 1568 in = fopen(inFile, "r"); 1569 if (!in) { 1570 fprintf(stderr, "Could not open input file %s\n", inFile); 1571 return 1; 1572 } 1573 } 1574 acc::compiler compiler; 1575 acc::compiler::args args; 1576 args.architecture = architecture; 1577 int compileResult = compiler.compile(in, args); 1578 if (in != stdin) { 1579 fclose(in); 1580 } 1581 if (compileResult) { 1582 fprintf(stderr, "Compile failed: %d\n", compileResult); 1583 return 6; 1584 } 1585 if (doDisassemble) { 1586 compiler.disassemble(stderr); 1587 } 1588 if (doDump) { 1589 FILE* save = fopen(outFile, "w"); 1590 if (!save) { 1591 fprintf(stderr, "Could not open output file %s\n", outFile); 1592 return 5; 1593 } 1594 compiler.dump(save); 1595 fclose(save); 1596 } else { 1597 fprintf(stderr, "Executing compiled code:\n"); 1598 int codeArgc = argc - i + 1; 1599 char** codeArgv = argv + i - 1; 1600 codeArgv[0] = (char*) (inFile ? inFile : "stdin"); 1601 int result = run(compiler, codeArgc, codeArgv); 1602 fprintf(stderr, "result: %d\n", result); 1603 return result; 1604 } 1605 1606 return 0; 1607} 1608