1 /* 2 * Program entry point, command line parsing 3 * 4 * Copyright (C) 2001-2008 Peter Johnson 5 * Copyright (C) 2007-2008 Samuel Thibault 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 #include <util.h> 29 30 #include <ctype.h> 31 #include <libyasm/compat-queue.h> 32 #include <libyasm/bitvect.h> 33 #include <libyasm.h> 34 35 #ifdef HAVE_LIBGEN_H 36 #include <libgen.h> 37 #endif 38 39 #include "tasm-options.h" 40 41 #ifdef CMAKE_BUILD 42 #include "yasm-plugin.h" 43 #endif 44 45 #include "license.c" 46 47 #define DEFAULT_OBJFMT_MODULE "bin" 48 49 /*@null@*/ /*@only@*/ static char *obj_filename = NULL, *in_filename = NULL; 50 /*@null@*/ /*@only@*/ static char *list_filename = NULL, *xref_filename = NULL; 51 /*@null@*/ /*@only@*/ static char *machine_name = NULL; 52 static int special_options = 0; 53 static int segment_ordering = 0; 54 static int cross_reference = 0; 55 static int floating_point = 0; 56 static int listing = 0; 57 static int expanded_listing = 0; 58 static int case_sensitivity = 0; 59 static int valid_length = -1; 60 /*@null@*/ /*@dependent@*/ static yasm_arch *cur_arch = NULL; 61 /*@null@*/ /*@dependent@*/ static const yasm_arch_module * 62 cur_arch_module = NULL; 63 /*@null@*/ /*@dependent@*/ static const yasm_parser_module * 64 cur_parser_module = NULL; 65 /*@null@*/ /*@dependent@*/ static yasm_preproc *cur_preproc = NULL; 66 /*@null@*/ /*@dependent@*/ static const yasm_preproc_module * 67 cur_preproc_module = NULL; 68 /*@null@*/ static char *objfmt_keyword = NULL; 69 /*@null@*/ /*@dependent@*/ static const yasm_objfmt_module * 70 cur_objfmt_module = NULL; 71 /*@null@*/ /*@dependent@*/ static const yasm_dbgfmt_module * 72 cur_dbgfmt_module = NULL; 73 /*@null@*/ /*@dependent@*/ static yasm_listfmt *cur_listfmt = NULL; 74 /*@null@*/ /*@dependent@*/ static const yasm_listfmt_module * 75 cur_listfmt_module = NULL; 76 static int warning_error = 0; /* warnings being treated as errors */ 77 static FILE *errfile; 78 /*@null@*/ /*@only@*/ static char *error_filename = NULL; 79 80 /*@null@*/ /*@dependent@*/ static FILE *open_file(const char *filename, 81 const char *mode); 82 static void check_errors(/*@only@*/ yasm_errwarns *errwarns, 83 /*@only@*/ yasm_object *object, 84 /*@only@*/ yasm_linemap *linemap); 85 static void cleanup(/*@null@*/ /*@only@*/ yasm_object *object); 86 87 /* Forward declarations: cmd line parser handlers */ 88 static int opt_special_handler(char *cmd, /*@null@*/ char *param, int extra); 89 static int opt_segment_ordering_handler(char *cmd, /*@null@*/ char *param, int extra); 90 static int opt_cross_reference_handler(char *cmd, /*@null@*/ char *param, int extra); 91 static int opt_floating_point_handler(char *cmd, /*@null@*/ char *param, int extra); 92 static int opt_ignore(char *cmd, /*@null@*/ char *param, int extra); 93 static int opt_listing_handler(char *cmd, /*@null@*/ char *param, int extra); 94 static int opt_case_handler(char *cmd, /*@null@*/ char *param, int extra); 95 static int opt_valid_length_handler(char *cmd, /*@null@*/ char *param, int extra); 96 97 static int opt_warning_handler(char *cmd, /*@null@*/ char *param, int extra); 98 static int opt_preproc_option(char *cmd, /*@null@*/ char *param, int extra); 99 static int opt_exe_handler(char *cmd, /*@null@*/ char *param, int extra); 100 101 static /*@only@*/ char *replace_extension(const char *orig, /*@null@*/ 102 const char *ext, const char *def); 103 static void print_error(const char *fmt, ...); 104 105 static /*@exits@*/ void handle_yasm_int_error(const char *file, 106 unsigned int line, 107 const char *message); 108 static /*@exits@*/ void handle_yasm_fatal(const char *message, va_list va); 109 static const char *handle_yasm_gettext(const char *msgid); 110 static void print_yasm_error(const char *filename, unsigned long line, 111 const char *msg, /*@null@*/ const char *xref_fn, 112 unsigned long xref_line, 113 /*@null@*/ const char *xref_msg); 114 static void print_yasm_warning(const char *filename, unsigned long line, 115 const char *msg); 116 117 static void apply_preproc_builtins(void); 118 static void apply_preproc_standard_macros(const yasm_stdmac *stdmacs); 119 static void apply_preproc_saved_options(void); 120 static void print_list_keyword_desc(const char *name, const char *keyword); 121 122 /* values for special_options */ 123 #define SPECIAL_SHOW_HELP 0x01 124 #define SPECIAL_SHOW_VERSION 0x02 125 #define SPECIAL_SHOW_LICENSE 0x04 126 127 #define SEGMENT_ORDERING_ALPHABETIC 0x01 128 #define SEGMENT_ORDERING_SOURCE 0x02 129 130 #define FP_EMULATED 0x01 131 #define FP_REAL 0x02 132 133 #define CASE_ALL 0x01 134 #define CASE_GLOBALS 0x02 135 #define CASE_NONE 0x04 136 137 #define DEBUG_FULL 0x01 138 #define DEBUG_LINES 0x02 139 #define DEBUG_NONE 0x04 140 141 /* command line options */ 142 static opt_option options[] = 143 { 144 { "version", 0, opt_special_handler, SPECIAL_SHOW_VERSION, 145 N_("show version text"), NULL }, 146 { "license", 0, opt_special_handler, SPECIAL_SHOW_LICENSE, 147 N_("show license text"), NULL }, 148 { "a", 0, opt_segment_ordering_handler, SEGMENT_ORDERING_ALPHABETIC, 149 N_("Alphabetic segment ordering"), NULL }, 150 { "s", 0, opt_segment_ordering_handler, SEGMENT_ORDERING_SOURCE, 151 N_("Source segment ordering"), NULL }, 152 153 { "c", 0, opt_cross_reference_handler, 0, 154 N_("Generate cross-reference in listing"), NULL }, 155 156 { "d", 1, opt_preproc_option, 2, 157 N_("pre-define a macro, optionally to value"), N_("macro[=value]") }, 158 159 { "e", 0, opt_floating_point_handler, FP_EMULATED, 160 N_("Emulated floating-point instructions (not supported)"), NULL }, 161 { "r", 0, opt_floating_point_handler, FP_REAL, 162 N_("Real floating-point instructions"), NULL }, 163 164 { "h", 0, opt_special_handler, SPECIAL_SHOW_HELP, 165 N_("show help text"), NULL }, 166 { "?", 0, opt_special_handler, SPECIAL_SHOW_HELP, 167 N_("show help text"), NULL }, 168 169 { "i", 1, opt_preproc_option, 0, 170 N_("add include path"), N_("path") }, 171 172 { "j", 1, opt_ignore, 0, 173 N_("Jam in an assemble directive CMD (eg. /jIDEAL) (not supported)"), NULL }, 174 175 { "k", 1, opt_ignore, 0, 176 N_("Hash table capacity (ignored)"), N_("# symbols") }, 177 178 { "l", 0, opt_listing_handler, 0, 179 N_("Generate listing"), N_("l=normal listing, la=expanded listing") }, 180 181 { "ml", 0, opt_case_handler, CASE_ALL, 182 N_("Case sensitivity on all symbols"), NULL }, 183 { "mx", 0, opt_case_handler, CASE_GLOBALS, 184 N_("Case sensitivity on global symbols"), NULL }, 185 { "mu", 0, opt_case_handler, CASE_NONE, 186 N_("No case sensitivity on symbols"), NULL }, 187 { "mv", 0, opt_valid_length_handler, 0, 188 N_("Set maximum valid length for symbols"), N_("length") }, 189 190 { "m", 1, opt_ignore, 0, 191 N_("Allow multiple passes to resolve forward reference (ignored)"), N_("number of passes") }, 192 193 { "n", 0, opt_ignore, 0, 194 N_("Suppress symbol tables in listing"), NULL }, 195 196 { "o", 0, opt_ignore, 0, 197 N_("Object code"), N_("os: standard, o: standard w/overlays, op: Phar Lap, oi: IBM") }, 198 199 { "p", 0, opt_ignore, 0, 200 N_("Check for code segment overrides in protected mode"), NULL }, 201 { "q", 0, opt_ignore, 0, 202 N_("Suppress OBJ records not needed for linking (ignored)"), NULL }, 203 { "t", 0, opt_ignore, 0, 204 N_("Suppress messages if successful assembly"), NULL }, 205 { "u", 0, opt_ignore, 0, 206 N_("Set version emulation"), N_("Version") }, 207 { "w", 1, opt_warning_handler, 0, 208 N_("Set warning level"), N_("w0=none, w1=w2=warnings on, w-xxx/w+xxx=disable/enable warning xxx") }, 209 { "x", 0, opt_ignore, 0, 210 N_("Include false conditionals in listing"), NULL }, 211 { "zi", 0, opt_ignore, DEBUG_FULL, 212 N_("Full debug info"), NULL }, 213 { "zd", 0, opt_ignore, DEBUG_LINES, 214 N_("Line numbers debug info"), NULL }, 215 { "zn", 0, opt_ignore, DEBUG_NONE, 216 N_("No debug info"), NULL }, 217 { "z", 0, opt_ignore, 0, 218 N_("Display source line with error message (ignored)"), NULL }, 219 220 { "b", 0, opt_exe_handler, 0, 221 N_("Build a (very) basic .exe file"), NULL }, 222 }; 223 224 /* version message */ 225 /*@observer@*/ static const char *version_msg[] = { 226 PACKAGE_STRING, 227 "Compiled on " __DATE__ ".", 228 "Copyright (c) 2001-2010 Peter Johnson and other Yasm developers.", 229 "Run yasm --license for licensing overview and summary." 230 }; 231 232 /* help messages */ 233 /*@observer@*/ static const char *help_head = N_( 234 "usage: tasm [option]* source [,object] [,listing] [,xref] \n" 235 "Options:\n"); 236 /*@observer@*/ static const char *help_tail = N_( 237 "\n" 238 "source is asm source to be assembled.\n" 239 "\n" 240 "Sample invocation:\n" 241 " tasm /zi source.asm\n" 242 "\n" 243 "Report bugs to bug-yasm (at) tortall.net\n"); 244 245 /* parsed command line storage until appropriate modules have been loaded */ 246 typedef STAILQ_HEAD(constcharparam_head, constcharparam) constcharparam_head; 247 248 typedef struct constcharparam { 249 STAILQ_ENTRY(constcharparam) link; 250 const char *param; 251 int id; 252 } constcharparam; 253 254 static constcharparam_head preproc_options; 255 256 static int 257 do_assemble(void) 258 { 259 yasm_object *object; 260 const char *base_filename; 261 /*@null@*/ FILE *obj = NULL; 262 yasm_arch_create_error arch_error; 263 yasm_linemap *linemap; 264 yasm_errwarns *errwarns = yasm_errwarns_create(); 265 int i, matched; 266 267 /* Initialize line map */ 268 linemap = yasm_linemap_create(); 269 yasm_linemap_set(linemap, in_filename, 0, 1, 1); 270 271 /* determine the object filename if not specified */ 272 if (!obj_filename) { 273 if (in_filename == NULL) 274 /* Default to yasm.out if no obj filename specified */ 275 obj_filename = yasm__xstrdup("yasm.out"); 276 else { 277 /* replace (or add) extension to base filename */ 278 yasm__splitpath(in_filename, &base_filename); 279 if (base_filename[0] == '\0') 280 obj_filename = yasm__xstrdup("yasm.out"); 281 else 282 obj_filename = replace_extension(base_filename, 283 "obj", 284 "yasm.out"); 285 } 286 } 287 288 cur_arch = yasm_arch_create(cur_arch_module, machine_name, 289 cur_parser_module->keyword, &arch_error); 290 if (!cur_arch) { 291 switch (arch_error) { 292 case YASM_ARCH_CREATE_BAD_MACHINE: 293 print_error(_("%s: `%s' is not a valid %s for %s `%s'"), 294 _("FATAL"), machine_name, _("machine"), 295 _("architecture"), cur_arch_module->keyword); 296 break; 297 case YASM_ARCH_CREATE_BAD_PARSER: 298 print_error(_("%s: `%s' is not a valid %s for %s `%s'"), 299 _("FATAL"), cur_parser_module->keyword, 300 _("parser"), _("architecture"), 301 cur_arch_module->keyword); 302 break; 303 default: 304 print_error(_("%s: unknown architecture error"), _("FATAL")); 305 } 306 307 return EXIT_FAILURE; 308 } 309 310 /* Create object */ 311 object = yasm_object_create(in_filename, obj_filename, cur_arch, 312 cur_objfmt_module, cur_dbgfmt_module); 313 if (!object) { 314 yasm_error_class eclass; 315 unsigned long xrefline; 316 /*@only@*/ /*@null@*/ char *estr, *xrefstr; 317 318 yasm_error_fetch(&eclass, &estr, &xrefline, &xrefstr); 319 print_error("%s: %s", _("FATAL"), estr); 320 yasm_xfree(estr); 321 yasm_xfree(xrefstr); 322 323 cleanup(object); 324 return EXIT_FAILURE; 325 } 326 327 /* Get a fresh copy of objfmt_module as it may have changed. */ 328 cur_objfmt_module = ((yasm_objfmt_base *)object->objfmt)->module; 329 330 /* Check to see if the requested preprocessor is in the allowed list 331 * for the active parser. 332 */ 333 matched = 0; 334 for (i=0; cur_parser_module->preproc_keywords[i]; i++) 335 if (yasm__strcasecmp(cur_parser_module->preproc_keywords[i], 336 cur_preproc_module->keyword) == 0) 337 matched = 1; 338 if (!matched) { 339 print_error(_("%s: `%s' is not a valid %s for %s `%s'"), _("FATAL"), 340 cur_preproc_module->keyword, _("preprocessor"), 341 _("parser"), cur_parser_module->keyword); 342 cleanup(object); 343 return EXIT_FAILURE; 344 } 345 346 cur_preproc = yasm_preproc_create(cur_preproc_module, in_filename, 347 object->symtab, linemap, errwarns); 348 349 apply_preproc_builtins(); 350 apply_preproc_standard_macros(cur_parser_module->stdmacs); 351 apply_preproc_standard_macros(cur_objfmt_module->stdmacs); 352 apply_preproc_saved_options(); 353 354 /* Get initial x86 BITS setting from object format */ 355 if (strcmp(cur_arch_module->keyword, "x86") == 0) { 356 yasm_arch_set_var(cur_arch, "mode_bits", 357 cur_objfmt_module->default_x86_mode_bits); 358 } 359 360 /* Parse! */ 361 cur_parser_module->do_parse(object, cur_preproc, list_filename != NULL, 362 linemap, errwarns); 363 364 check_errors(errwarns, object, linemap); 365 366 /* Finalize parse */ 367 yasm_object_finalize(object, errwarns); 368 check_errors(errwarns, object, linemap); 369 370 /* Optimize */ 371 yasm_object_optimize(object, errwarns); 372 check_errors(errwarns, object, linemap); 373 374 /* generate any debugging information */ 375 yasm_dbgfmt_generate(object, linemap, errwarns); 376 check_errors(errwarns, object, linemap); 377 378 /* open the object file for output (if not already opened by dbg objfmt) */ 379 if (!obj && strcmp(cur_objfmt_module->keyword, "dbg") != 0) { 380 obj = open_file(obj_filename, "wb"); 381 if (!obj) { 382 cleanup(object); 383 return EXIT_FAILURE; 384 } 385 } 386 387 /* Write the object file */ 388 yasm_objfmt_output(object, obj?obj:stderr, 389 strcmp(cur_dbgfmt_module->keyword, "null"), errwarns); 390 391 /* Close object file */ 392 if (obj) 393 fclose(obj); 394 395 /* If we had an error at this point, we also need to delete the output 396 * object file (to make sure it's not left newer than the source). 397 */ 398 if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) 399 remove(obj_filename); 400 check_errors(errwarns, object, linemap); 401 402 /* Open and write the list file */ 403 if (list_filename) { 404 FILE *list = open_file(list_filename, "wt"); 405 if (!list) { 406 cleanup(object); 407 return EXIT_FAILURE; 408 } 409 /* Initialize the list format */ 410 cur_listfmt = yasm_listfmt_create(cur_listfmt_module, in_filename, 411 obj_filename); 412 yasm_listfmt_output(cur_listfmt, list, linemap, cur_arch); 413 fclose(list); 414 } 415 416 yasm_errwarns_output_all(errwarns, linemap, warning_error, 417 print_yasm_error, print_yasm_warning); 418 419 yasm_linemap_destroy(linemap); 420 yasm_errwarns_destroy(errwarns); 421 cleanup(object); 422 return EXIT_SUCCESS; 423 } 424 425 /* main function */ 426 /*@-globstate -unrecog@*/ 427 int 428 main(int argc, char *argv[]) 429 { 430 size_t i; 431 432 errfile = stderr; 433 434 #if defined(HAVE_SETLOCALE) && defined(HAVE_LC_MESSAGES) 435 setlocale(LC_MESSAGES, ""); 436 #endif 437 #if defined(LOCALEDIR) 438 bindtextdomain(PACKAGE, LOCALEDIR); 439 #endif 440 textdomain(PACKAGE); 441 442 /* Initialize errwarn handling */ 443 yasm_internal_error_ = handle_yasm_int_error; 444 yasm_fatal = handle_yasm_fatal; 445 yasm_gettext_hook = handle_yasm_gettext; 446 yasm_errwarn_initialize(); 447 448 /* Initialize BitVector (needed for intnum/floatnum). */ 449 if (BitVector_Boot() != ErrCode_Ok) { 450 print_error(_("%s: could not initialize BitVector"), _("FATAL")); 451 return EXIT_FAILURE; 452 } 453 454 /* Initialize intnum and floatnum */ 455 yasm_intnum_initialize(); 456 yasm_floatnum_initialize(); 457 458 #ifdef CMAKE_BUILD 459 /* Load standard modules */ 460 if (!load_plugin("yasmstd")) { 461 print_error(_("%s: could not load standard modules"), _("FATAL")); 462 return EXIT_FAILURE; 463 } 464 #endif 465 466 /* Initialize parameter storage */ 467 STAILQ_INIT(&preproc_options); 468 469 if (parse_cmdline(argc, argv, options, NELEMS(options), print_error)) 470 return EXIT_FAILURE; 471 472 switch (special_options) { 473 case SPECIAL_SHOW_HELP: 474 /* Does gettext calls internally */ 475 help_msg(help_head, help_tail, options, NELEMS(options)); 476 return EXIT_SUCCESS; 477 case SPECIAL_SHOW_VERSION: 478 for (i=0; i<NELEMS(version_msg); i++) 479 printf("%s\n", version_msg[i]); 480 return EXIT_SUCCESS; 481 case SPECIAL_SHOW_LICENSE: 482 for (i=0; i<NELEMS(license_msg); i++) 483 printf("%s\n", license_msg[i]); 484 return EXIT_SUCCESS; 485 } 486 487 /* Open error file if specified. */ 488 if (error_filename) { 489 errfile = open_file(error_filename, "wt"); 490 if (!errfile) 491 return EXIT_FAILURE; 492 } 493 494 /* If not already specified, default to bin as the object format. */ 495 if (!cur_objfmt_module) { 496 if (!objfmt_keyword) 497 objfmt_keyword = yasm__xstrdup(DEFAULT_OBJFMT_MODULE); 498 cur_objfmt_module = yasm_load_objfmt(objfmt_keyword); 499 if (!cur_objfmt_module) { 500 print_error(_("%s: could not load default %s"), _("FATAL"), 501 _("object format")); 502 return EXIT_FAILURE; 503 } 504 } 505 506 /* TASM's architecture is x86 */ 507 cur_arch_module = yasm_load_arch("x86"); 508 if (!cur_arch_module) { 509 print_error(_("%s: could not load %s"), _("FATAL"), 510 _("architecture")); 511 return EXIT_FAILURE; 512 } 513 machine_name = 514 yasm__xstrdup(cur_arch_module->default_machine_keyword); 515 516 /* Check for arch help */ 517 if (machine_name && strcmp(machine_name, "help") == 0) { 518 const yasm_arch_machine *m = cur_arch_module->machines; 519 printf(_("Available %s for %s `%s':\n"), _("machines"), 520 _("architecture"), cur_arch_module->keyword); 521 while (m->keyword && m->name) { 522 print_list_keyword_desc(m->name, m->keyword); 523 m++; 524 } 525 return EXIT_SUCCESS; 526 } 527 528 cur_parser_module = yasm_load_parser("tasm"); 529 if (!cur_parser_module) { 530 print_error(_("%s: could not load %s"), _("FATAL"), 531 _("parser")); 532 cleanup(NULL); 533 return EXIT_FAILURE; 534 } 535 536 /* If not already specified, default to the parser's default preproc. */ 537 if (!cur_preproc_module) { 538 cur_preproc_module = 539 yasm_load_preproc(cur_parser_module->default_preproc_keyword); 540 if (!cur_preproc_module) { 541 print_error(_("%s: could not load default %s"), _("FATAL"), 542 _("preprocessor")); 543 cleanup(NULL); 544 return EXIT_FAILURE; 545 } 546 } 547 548 /* Determine input filename and open input file. */ 549 if (!in_filename) { 550 print_error(_("No input files specified")); 551 return EXIT_FAILURE; 552 } 553 554 /* If list file enabled, make sure we have a list format loaded. */ 555 if (list_filename) { 556 /* use nasm as the list format. */ 557 cur_listfmt_module = yasm_load_listfmt("nasm"); 558 } 559 560 /* If not already specified, default to null as the debug format. */ 561 if (!cur_dbgfmt_module) { 562 cur_dbgfmt_module = yasm_load_dbgfmt("null"); 563 if (!cur_dbgfmt_module) { 564 print_error(_("%s: could not load default %s"), _("FATAL"), 565 _("debug format")); 566 return EXIT_FAILURE; 567 } 568 } 569 570 return do_assemble(); 571 } 572 /*@=globstate =unrecog@*/ 573 574 /* Open the object file. Returns 0 on failure. */ 575 static FILE * 576 open_file(const char *filename, const char *mode) 577 { 578 FILE *f; 579 580 f = fopen(filename, mode); 581 if (!f) 582 print_error(_("could not open file `%s'"), filename); 583 return f; 584 } 585 586 static void 587 check_errors(yasm_errwarns *errwarns, yasm_object *object, 588 yasm_linemap *linemap) 589 { 590 if (yasm_errwarns_num_errors(errwarns, warning_error) > 0) { 591 yasm_errwarns_output_all(errwarns, linemap, warning_error, 592 print_yasm_error, print_yasm_warning); 593 yasm_linemap_destroy(linemap); 594 yasm_errwarns_destroy(errwarns); 595 cleanup(object); 596 exit(EXIT_FAILURE); 597 } 598 } 599 600 /* Define DO_FREE to 1 to enable deallocation of all data structures. 601 * Useful for detecting memory leaks, but slows down execution unnecessarily 602 * (as the OS will free everything we miss here). 603 */ 604 #define DO_FREE 1 605 606 /* Cleans up all allocated structures. */ 607 static void 608 cleanup(yasm_object *object) 609 { 610 if (DO_FREE) { 611 if (cur_listfmt) 612 yasm_listfmt_destroy(cur_listfmt); 613 if (cur_preproc) 614 yasm_preproc_destroy(cur_preproc); 615 if (object) 616 yasm_object_destroy(object); 617 618 yasm_floatnum_cleanup(); 619 yasm_intnum_cleanup(); 620 621 yasm_errwarn_cleanup(); 622 623 BitVector_Shutdown(); 624 } 625 626 if (DO_FREE) { 627 if (in_filename) 628 yasm_xfree(in_filename); 629 if (obj_filename) 630 yasm_xfree(obj_filename); 631 if (list_filename) 632 yasm_xfree(list_filename); 633 if (xref_filename) 634 yasm_xfree(xref_filename); 635 if (machine_name) 636 yasm_xfree(machine_name); 637 if (objfmt_keyword) 638 yasm_xfree(objfmt_keyword); 639 } 640 641 if (errfile != stderr && errfile != stdout) 642 fclose(errfile); 643 #ifdef CMAKE_BUILD 644 unload_plugins(); 645 #endif 646 } 647 648 /* 649 * Command line options handlers 650 */ 651 static char ** const filenames[] = { 652 &in_filename, &obj_filename, &list_filename, &xref_filename, NULL 653 }, ** const * cur_filename = &filenames[0]; 654 655 static int filename_handler(char *param) { 656 if (!*cur_filename) { 657 print_error(_("error: too many files on command line.")); 658 return 1; 659 } 660 661 if (*param) 662 **cur_filename = yasm__xstrdup(param); 663 664 return 0; 665 } 666 int 667 not_an_option_handler(char *param) { 668 char *c, *d = param; 669 670 while ((c = strchr(d, ','))) { 671 *c = '\0'; 672 if (filename_handler(d)) 673 return 1; 674 d = c + 1; 675 cur_filename++; 676 } 677 filename_handler(d); 678 return 0; 679 } 680 681 static int 682 opt_special_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 683 { 684 if (special_options == 0) 685 special_options = extra; 686 return 0; 687 } 688 689 static int 690 opt_segment_ordering_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 691 { 692 segment_ordering = extra; 693 return 0; 694 } 695 696 static int 697 opt_cross_reference_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 698 { 699 cross_reference = 1; 700 return 0; 701 } 702 703 static int 704 opt_floating_point_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 705 { 706 floating_point = extra; 707 return 0; 708 } 709 710 static int 711 opt_ignore(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 712 { 713 return 0; 714 } 715 716 static int 717 opt_listing_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 718 { 719 if (param && param[0]) { 720 if (param[0] != 'a') 721 return 1; 722 expanded_listing = 1; 723 } 724 listing = 1; 725 return 0; 726 } 727 728 static int 729 opt_case_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 730 { 731 case_sensitivity = extra; 732 return 0; 733 } 734 735 static int 736 opt_valid_length_handler(/*@unused@*/ char *cmd, /*@unused@*/ char *param, int extra) 737 { 738 valid_length = atoi(param); 739 return 0; 740 } 741 742 static int 743 opt_warning_handler(char *cmd, /*@unused@*/ char *param, int extra) 744 { 745 /* is it disabling the warning instead of enabling? */ 746 void (*action)(yasm_warn_class wclass) = NULL; 747 748 if (cmd[0] == '0') { 749 /* /w0, disable warnings */ 750 yasm_warn_disable_all(); 751 return 0; 752 } 753 754 if (cmd[0] == '1' || cmd[0] == '2') { 755 /* /w[12], enable warnings */ 756 yasm_warn_enable(YASM_WARN_UNREC_CHAR); 757 yasm_warn_enable(YASM_WARN_ORPHAN_LABEL); 758 yasm_warn_enable(YASM_WARN_UNINIT_CONTENTS); 759 return 0; 760 } 761 762 /* detect no- prefix to disable the warning */ 763 if (cmd[0] == '-') { 764 action = yasm_warn_disable; 765 } else if (cmd[0] == '+') { 766 action = yasm_warn_enable; 767 } else return 1; 768 769 /* skip past '+/-' */ 770 cmd++; 771 772 if (cmd[0] == '\0') 773 /* just /w- or /w+, so definitely not valid */ 774 return 1; 775 else if (strcmp(cmd, "error") == 0) 776 warning_error = (action == yasm_warn_enable); 777 else if (strcmp(cmd, "unrecognized-char") == 0) 778 action(YASM_WARN_UNREC_CHAR); 779 else if (strcmp(cmd, "orphan-labels") == 0) 780 action(YASM_WARN_ORPHAN_LABEL); 781 else if (strcmp(cmd, "uninit-contents") == 0) 782 action(YASM_WARN_UNINIT_CONTENTS); 783 else if (strcmp(cmd, "size-override") == 0) 784 action(YASM_WARN_SIZE_OVERRIDE); 785 else 786 return 1; 787 788 return 0; 789 } 790 791 static int 792 opt_preproc_option(/*@unused@*/ char *cmd, char *param, int extra) 793 { 794 constcharparam *cp; 795 cp = yasm_xmalloc(sizeof(constcharparam)); 796 cp->param = param; 797 cp->id = extra; 798 STAILQ_INSERT_TAIL(&preproc_options, cp, link); 799 return 0; 800 } 801 802 static int 803 opt_exe_handler(char *cmd, /*@unused@*/ char *param, int extra) 804 { 805 objfmt_keyword = yasm__xstrdup("dosexe"); 806 return 0; 807 } 808 809 static void 810 apply_preproc_builtins() 811 { 812 char *predef; 813 814 if (!objfmt_keyword) 815 objfmt_keyword = yasm__xstrdup(DEFAULT_OBJFMT_MODULE); 816 817 /* Define standard YASM assembly-time macro constants */ 818 predef = yasm_xmalloc(strlen("__YASM_OBJFMT__=") 819 + strlen(objfmt_keyword) + 1); 820 strcpy(predef, "__YASM_OBJFMT__="); 821 strcat(predef, objfmt_keyword); 822 yasm_preproc_define_builtin(cur_preproc, predef); 823 yasm_xfree(predef); 824 } 825 826 static void 827 apply_preproc_standard_macros(const yasm_stdmac *stdmacs) 828 { 829 int i, matched; 830 831 if (!stdmacs) 832 return; 833 834 matched = -1; 835 for (i=0; stdmacs[i].parser; i++) 836 if (yasm__strcasecmp(stdmacs[i].parser, 837 cur_parser_module->keyword) == 0 && 838 yasm__strcasecmp(stdmacs[i].preproc, 839 cur_preproc_module->keyword) == 0) 840 matched = i; 841 if (matched >= 0 && stdmacs[matched].macros) 842 yasm_preproc_add_standard(cur_preproc, stdmacs[matched].macros); 843 } 844 845 static void 846 apply_preproc_saved_options() 847 { 848 constcharparam *cp, *cpnext; 849 850 void (*funcs[3])(yasm_preproc *, const char *); 851 funcs[0] = cur_preproc_module->add_include_file; 852 funcs[1] = cur_preproc_module->predefine_macro; 853 funcs[2] = cur_preproc_module->undefine_macro; 854 855 STAILQ_FOREACH(cp, &preproc_options, link) { 856 if (0 <= cp->id && cp->id < 3 && funcs[cp->id]) 857 funcs[cp->id](cur_preproc, cp->param); 858 } 859 860 cp = STAILQ_FIRST(&preproc_options); 861 while (cp != NULL) { 862 cpnext = STAILQ_NEXT(cp, link); 863 yasm_xfree(cp); 864 cp = cpnext; 865 } 866 STAILQ_INIT(&preproc_options); 867 } 868 869 /* Replace extension on a filename (or append one if none is present). 870 * If output filename would be identical to input (same extension out as in), 871 * returns (copy of) def. 872 * A NULL ext means the trailing '.' should NOT be included, whereas a "" ext 873 * means the trailing '.' should be included. 874 */ 875 static char * 876 replace_extension(const char *orig, /*@null@*/ const char *ext, 877 const char *def) 878 { 879 char *out, *outext; 880 size_t deflen, outlen; 881 882 /* allocate enough space for full existing name + extension */ 883 outlen = strlen(orig) + 2; 884 if (ext) 885 outlen += strlen(ext) + 1; 886 deflen = strlen(def) + 1; 887 if (outlen < deflen) 888 outlen = deflen; 889 out = yasm_xmalloc(outlen); 890 891 strcpy(out, orig); 892 outext = strrchr(out, '.'); 893 if (outext) { 894 /* Existing extension: make sure it's not the same as the replacement 895 * (as we don't want to overwrite the source file). 896 */ 897 outext++; /* advance past '.' */ 898 if (ext && strcmp(outext, ext) == 0) { 899 outext = NULL; /* indicate default should be used */ 900 print_error( 901 _("file name already ends in `.%s': output will be in `%s'"), 902 ext, def); 903 } 904 } else { 905 /* No extension: make sure the output extension is not empty 906 * (again, we don't want to overwrite the source file). 907 */ 908 if (!ext) 909 print_error( 910 _("file name already has no extension: output will be in `%s'"), 911 def); 912 else { 913 outext = strrchr(out, '\0'); /* point to end of the string */ 914 *outext++ = '.'; /* append '.' */ 915 } 916 } 917 918 /* replace extension or use default name */ 919 if (outext) { 920 if (!ext) { 921 /* Back up and replace '.' with string terminator */ 922 outext--; 923 *outext = '\0'; 924 } else 925 strcpy(outext, ext); 926 } else 927 strcpy(out, def); 928 929 return out; 930 } 931 932 void 933 print_list_keyword_desc(const char *name, const char *keyword) 934 { 935 printf("%4s%-12s%s\n", "", keyword, name); 936 } 937 938 static void 939 print_error(const char *fmt, ...) 940 { 941 va_list va; 942 fprintf(errfile, "tasm: "); 943 va_start(va, fmt); 944 vfprintf(errfile, fmt, va); 945 va_end(va); 946 fputc('\n', errfile); 947 } 948 949 static /*@exits@*/ void 950 handle_yasm_int_error(const char *file, unsigned int line, const char *message) 951 { 952 fprintf(stderr, _("INTERNAL ERROR at %s, line %u: %s\n"), file, line, 953 gettext(message)); 954 #ifdef HAVE_ABORT 955 abort(); 956 #else 957 exit(EXIT_FAILURE); 958 #endif 959 } 960 961 static /*@exits@*/ void 962 handle_yasm_fatal(const char *fmt, va_list va) 963 { 964 fprintf(errfile, "**%s**: ", _("Fatal")); 965 vfprintf(errfile, gettext(fmt), va); 966 fputc('\n', errfile); 967 exit(EXIT_FAILURE); 968 } 969 970 static const char * 971 handle_yasm_gettext(const char *msgid) 972 { 973 return gettext(msgid); 974 } 975 976 static void 977 print_yasm_error(const char *filename, unsigned long line, const char *msg, 978 const char *xref_fn, unsigned long xref_line, 979 const char *xref_msg) 980 { 981 if (line) 982 fprintf(errfile, "**%s** %s(%lu) %s\n", _("Error"), filename, line, msg); 983 else 984 fprintf(errfile, "**%s** %s %s\n", _("Error"), filename, msg); 985 986 if (/* xref_fn && */ xref_msg) { 987 if (xref_line) 988 fprintf(errfile, "**%s** %s(%lu) %s\n", _("Error"), filename, xref_line, xref_msg); 989 else 990 fprintf(errfile, "**%s** %s %s\n", _("Error"), filename, xref_msg); 991 } 992 } 993 994 static void 995 print_yasm_warning(const char *filename, unsigned long line, const char *msg) 996 { 997 if (line) 998 fprintf(errfile, "*%s* %s(%lu) %s\n", _("Warning"), filename, line, msg); 999 else 1000 fprintf(errfile, "*%s* %s %s\n", _("Warning"), filename, msg); 1001 } 1002