ldrdf.c 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393
  1. /* ----------------------------------------------------------------------- *
  2. *
  3. * Copyright 1996-2014 The NASM Authors - All Rights Reserved
  4. * See the file AUTHORS included with the NASM distribution for
  5. * the specific copyright holders.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following
  9. * conditions are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * * Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following
  15. * disclaimer in the documentation and/or other materials provided
  16. * with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  19. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  20. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  22. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  25. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  27. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  29. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  30. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. * ----------------------------------------------------------------------- */
  33. /*
  34. * ldrdf.c - RDOFF Object File linker/loader main program.
  35. */
  36. /*
  37. * TODO:
  38. * - enhance search of required export symbols in libraries (now depends
  39. * on modules order in library)
  40. * - keep a cache of symbol names in each library module so
  41. * we don't have to constantly recheck the file
  42. * - general performance improvements
  43. *
  44. * BUGS & LIMITATIONS: this program doesn't support multiple code, data
  45. * or bss segments, therefore for 16 bit programs whose code, data or BSS
  46. * segment exceeds 64K in size, it will not work. This program probably
  47. * won't work if compiled by a 16 bit compiler. Try DJGPP if you're running
  48. * under DOS. '#define STINGY_MEMORY' may help a little.
  49. */
  50. #include "compiler.h"
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include "rdfutils.h"
  55. #include "symtab.h"
  56. #include "collectn.h"
  57. #include "rdlib.h"
  58. #include "segtab.h"
  59. #include "nasmlib.h"
  60. #define LDRDF_VERSION "1.08"
  61. /* #define STINGY_MEMORY */
  62. /* =======================================================================
  63. * Types & macros that are private to this program
  64. */
  65. struct segment_infonode {
  66. int dest_seg; /* output segment to be placed into, -1 to
  67. skip linking this segment */
  68. int32_t reloc; /* segment's relocation factor */
  69. };
  70. struct modulenode {
  71. rdffile f; /* the RDOFF file structure */
  72. struct segment_infonode seginfo[RDF_MAXSEGS]; /* what are we doing
  73. with each segment? */
  74. void *header;
  75. char *name;
  76. struct modulenode *next;
  77. int32_t bss_reloc;
  78. };
  79. #include "ldsegs.h"
  80. /* ==========================================================================
  81. * Function prototypes of private utility functions
  82. */
  83. void processmodule(const char *filename, struct modulenode *mod);
  84. int allocnewseg(uint16_t type, uint16_t reserved);
  85. int findsegment(uint16_t type, uint16_t reserved);
  86. void symtab_add(const char *symbol, int segment, int32_t offset);
  87. int symtab_get(const char *symbol, int *segment, int32_t *offset);
  88. /* =========================================================================
  89. * Global data structures.
  90. */
  91. /* a linked list of modules that will be included in the output */
  92. struct modulenode *modules = NULL;
  93. struct modulenode *lastmodule = NULL;
  94. /* a linked list of libraries to be searched for unresolved imported symbols */
  95. struct librarynode *libraries = NULL;
  96. struct librarynode *lastlib = NULL;
  97. /* the symbol table */
  98. void *symtab = NULL;
  99. /* objects search path */
  100. char *objpath = NULL;
  101. /* libraries search path */
  102. char *libpath = NULL;
  103. /* file to embed as a generic record */
  104. char *generic_rec_file = NULL;
  105. /* module name to be added at the beginning of output file */
  106. char *modname_specified = NULL;
  107. /* the header of the output file, built up stage by stage */
  108. rdf_headerbuf *newheader = NULL;
  109. /* The current state of segment allocation, including information about
  110. * which output segment numbers have been allocated, and their types and
  111. * amount of data which has already been allocated inside them.
  112. */
  113. struct SegmentHeaderRec outputseg[RDF_MAXSEGS];
  114. int nsegs = 0;
  115. int32_t bss_length;
  116. /* global options which affect how the program behaves */
  117. struct ldrdfoptions {
  118. int verbose;
  119. int align;
  120. int dynalink;
  121. int strip;
  122. int respfile;
  123. int stderr_redir;
  124. int objpath;
  125. int libpath;
  126. } options;
  127. int errorcount = 0; /* determines main program exit status */
  128. /* =========================================================================
  129. * Utility functions
  130. */
  131. /*
  132. * initsegments()
  133. *
  134. * sets up segments 0, 1, and 2, the initial code data and bss segments
  135. */
  136. static void initsegments(void)
  137. {
  138. nsegs = 3;
  139. outputseg[0].type = 1;
  140. outputseg[0].number = 0;
  141. outputseg[0].reserved = 0;
  142. outputseg[0].length = 0;
  143. outputseg[1].type = 2;
  144. outputseg[1].number = 1;
  145. outputseg[1].reserved = 0;
  146. outputseg[1].length = 0;
  147. outputseg[2].type = 0xFFFF; /* reserved segment type */
  148. outputseg[2].number = 2;
  149. outputseg[2].reserved = 0;
  150. outputseg[2].length = 0;
  151. bss_length = 0;
  152. }
  153. /*
  154. * loadmodule()
  155. *
  156. * Determine the characteristics of a module, and decide what to do with
  157. * each segment it contains (including determining destination segments and
  158. * relocation factors for segments that are kept).
  159. */
  160. static void loadmodule(const char *filename)
  161. {
  162. if (options.verbose)
  163. printf("loading `%s'\n", filename);
  164. /* allocate a new module entry on the end of the modules list */
  165. if (!modules) {
  166. modules = nasm_malloc(sizeof(*modules));
  167. lastmodule = modules;
  168. } else {
  169. lastmodule->next = nasm_malloc(sizeof(*modules));
  170. lastmodule = lastmodule->next;
  171. }
  172. if (!lastmodule) {
  173. fprintf(stderr, "ldrdf: out of memory\n");
  174. exit(1);
  175. }
  176. /* open the file using 'rdfopen', which returns nonzero on error */
  177. if (rdfopen(&lastmodule->f, filename) != 0) {
  178. rdfperror("ldrdf", filename);
  179. exit(1);
  180. }
  181. /*
  182. * store information about the module, and determine what segments
  183. * it contains, and what we should do with them (determine relocation
  184. * factor if we decide to keep them)
  185. */
  186. lastmodule->header = NULL;
  187. lastmodule->name = nasm_strdup(filename);
  188. lastmodule->next = NULL;
  189. processmodule(filename, lastmodule);
  190. }
  191. /*
  192. * processmodule()
  193. *
  194. * step through each segment, determine what exactly we're doing with
  195. * it, and if we intend to keep it, determine (a) which segment to
  196. * put it in and (b) whereabouts in that segment it will end up.
  197. * (b) is fairly easy, because we're now keeping track of how big each
  198. * segment in our output file is...
  199. */
  200. void processmodule(const char *filename, struct modulenode *mod)
  201. {
  202. struct segconfig sconf;
  203. int seg, outseg;
  204. void *header;
  205. rdfheaderrec *hr;
  206. int32_t bssamount = 0;
  207. int bss_was_referenced = 0;
  208. memset(&sconf, 0, sizeof sconf);
  209. for (seg = 0; seg < mod->f.nsegs; seg++) {
  210. /*
  211. * get the segment configuration for this type from the segment
  212. * table. getsegconfig() is a macro, defined in ldsegs.h.
  213. */
  214. getsegconfig(sconf, mod->f.seg[seg].type);
  215. if (options.verbose > 1) {
  216. printf("%s %04x [%04x:%10s] ", filename,
  217. mod->f.seg[seg].number, mod->f.seg[seg].type,
  218. sconf.typedesc);
  219. }
  220. /*
  221. * sconf->dowhat tells us what to do with a segment of this type.
  222. */
  223. switch (sconf.dowhat) {
  224. case SEG_IGNORE:
  225. /*
  226. * Set destination segment to -1, to indicate that this segment
  227. * should be ignored for the purpose of output, ie it is left
  228. * out of the linked executable.
  229. */
  230. mod->seginfo[seg].dest_seg = -1;
  231. if (options.verbose > 1)
  232. printf("IGNORED\n");
  233. break;
  234. case SEG_NEWSEG:
  235. /*
  236. * The configuration tells us to create a new segment for
  237. * each occurrence of this segment type.
  238. */
  239. outseg = allocnewseg(sconf.mergetype,
  240. mod->f.seg[seg].reserved);
  241. mod->seginfo[seg].dest_seg = outseg;
  242. mod->seginfo[seg].reloc = 0;
  243. outputseg[outseg].length = mod->f.seg[seg].length;
  244. if (options.verbose > 1)
  245. printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
  246. mod->seginfo[seg].reloc, mod->f.seg[seg].length);
  247. break;
  248. case SEG_MERGE:
  249. /*
  250. * The configuration tells us to merge the segment with
  251. * a previously existing segment of type 'sconf.mergetype',
  252. * if one exists. Otherwise a new segment is created.
  253. * This is handled transparently by 'findsegment()'.
  254. */
  255. outseg = findsegment(sconf.mergetype,
  256. mod->f.seg[seg].reserved);
  257. mod->seginfo[seg].dest_seg = outseg;
  258. /*
  259. * We need to add alignment to these segments.
  260. */
  261. if (outputseg[outseg].length % options.align != 0)
  262. outputseg[outseg].length +=
  263. options.align -
  264. (outputseg[outseg].length % options.align);
  265. mod->seginfo[seg].reloc = outputseg[outseg].length;
  266. outputseg[outseg].length += mod->f.seg[seg].length;
  267. if (options.verbose > 1)
  268. printf("=> %04x:%08"PRIx32" (+%04"PRIx32")\n", outseg,
  269. mod->seginfo[seg].reloc, mod->f.seg[seg].length);
  270. }
  271. }
  272. /*
  273. * extract symbols from the header, and dump them into the
  274. * symbol table
  275. */
  276. header = nasm_malloc(mod->f.header_len);
  277. if (!header) {
  278. fprintf(stderr, "ldrdf: not enough memory\n");
  279. exit(1);
  280. }
  281. if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
  282. rdfperror("ldrdf", filename);
  283. exit(1);
  284. }
  285. while ((hr = rdfgetheaderrec(&mod->f))) {
  286. switch (hr->type) {
  287. case RDFREC_IMPORT: /* imported symbol */
  288. case RDFREC_FARIMPORT:
  289. /* Define with seg = -1 */
  290. symtab_add(hr->i.label, -1, 0);
  291. break;
  292. case RDFREC_GLOBAL:{ /* exported symbol */
  293. int destseg;
  294. int32_t destreloc;
  295. if (hr->e.segment == 2) {
  296. bss_was_referenced = 1;
  297. destreloc = bss_length;
  298. if (destreloc % options.align != 0)
  299. destreloc +=
  300. options.align - (destreloc % options.align);
  301. destseg = 2;
  302. } else {
  303. if ((destseg =
  304. mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
  305. continue;
  306. destreloc = mod->seginfo[(int)hr->e.segment].reloc;
  307. }
  308. symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
  309. break;
  310. }
  311. case RDFREC_BSS: /* BSS reservation */
  312. /*
  313. * first, amalgamate all BSS reservations in this module
  314. * into one, because we allow this in the output format.
  315. */
  316. bssamount += hr->b.amount;
  317. break;
  318. case RDFREC_COMMON:{ /* Common variable */
  319. symtabEnt *ste = symtabFind(symtab, hr->c.label);
  320. /* Is the symbol already in the table? */
  321. if (ste)
  322. break;
  323. /* Align the variable */
  324. if (bss_length % hr->c.align != 0)
  325. bss_length += hr->c.align - (bss_length % hr->c.align);
  326. if (options.verbose > 1) {
  327. printf("%s %04x common '%s' => 0002:%08"PRIx32" (+%04"PRIx32")\n",
  328. filename, hr->c.segment, hr->c.label,
  329. bss_length, hr->c.size);
  330. }
  331. symtab_add(hr->c.label, 2, bss_length);
  332. mod->bss_reloc = bss_length;
  333. bss_length += hr->c.size;
  334. break;
  335. }
  336. }
  337. }
  338. if (bssamount != 0 || bss_was_referenced) {
  339. /*
  340. * handle the BSS segment - first pad the existing bss length
  341. * to the correct alignment, then store the length in bss_reloc
  342. * for this module. Then add this module's BSS length onto
  343. * bss_length.
  344. */
  345. if (bss_length % options.align != 0)
  346. bss_length += options.align - (bss_length % options.align);
  347. mod->bss_reloc = bss_length;
  348. if (options.verbose > 1) {
  349. printf("%s 0002 [ BSS] => 0002:%08"PRIx32" (+%04"PRIx32")\n",
  350. filename, bss_length, bssamount);
  351. }
  352. bss_length += bssamount;
  353. }
  354. #ifdef STINGY_MEMORY
  355. /*
  356. * we free the header buffer here, to save memory later.
  357. * this isn't efficient, but probably halves the memory usage
  358. * of this program...
  359. */
  360. mod->f.header_loc = NULL;
  361. nasm_free(header);
  362. #endif
  363. }
  364. /*
  365. * Return 1 if a given module is in the list, 0 otherwise.
  366. */
  367. static int lookformodule(const char *name)
  368. {
  369. struct modulenode *curr = modules;
  370. while (curr) {
  371. if (!strcmp(name, curr->name))
  372. return 1;
  373. curr = curr->next;
  374. }
  375. return 0;
  376. }
  377. /*
  378. * allocnewseg()
  379. * findsegment()
  380. *
  381. * These functions manipulate the array of output segments, and are used
  382. * by processmodule(). allocnewseg() allocates a segment in the array,
  383. * initialising it to be empty. findsegment() first scans the array for
  384. * a segment of the type requested, and if one isn't found allocates a
  385. * new one.
  386. */
  387. int allocnewseg(uint16_t type, uint16_t reserved)
  388. {
  389. outputseg[nsegs].type = type;
  390. outputseg[nsegs].number = nsegs;
  391. outputseg[nsegs].reserved = reserved;
  392. outputseg[nsegs].length = 0;
  393. outputseg[nsegs].offset = 0;
  394. outputseg[nsegs].data = NULL;
  395. return nsegs++;
  396. }
  397. int findsegment(uint16_t type, uint16_t reserved)
  398. {
  399. int i;
  400. for (i = 0; i < nsegs; i++)
  401. if (outputseg[i].type == type)
  402. return i;
  403. return allocnewseg(type, reserved);
  404. }
  405. /*
  406. * symtab_add()
  407. *
  408. * inserts a symbol into the global symbol table, which associates symbol
  409. * names either with addresses, or a marker that the symbol hasn't been
  410. * resolved yet, or possibly that the symbol has been defined as
  411. * contained in a dynamic [load time/run time] linked library.
  412. *
  413. * segment = -1 => not yet defined
  414. * segment = -2 => defined as dll symbol
  415. *
  416. * If the symbol is already defined, and the new segment >= 0, then
  417. * if the original segment was < 0 the symbol is redefined, otherwise
  418. * a duplicate symbol warning is issued. If new segment == -1, this
  419. * routine won't change a previously existing symbol. It will change
  420. * to segment = -2 only if the segment was previously < 0.
  421. */
  422. void symtab_add(const char *symbol, int segment, int32_t offset)
  423. {
  424. symtabEnt *ste;
  425. ste = symtabFind(symtab, symbol);
  426. if (ste) {
  427. if (ste->segment >= 0) {
  428. /*
  429. * symbol previously defined
  430. */
  431. if (segment < 0)
  432. return;
  433. fprintf(error_file, "warning: `%s' redefined\n", symbol);
  434. return;
  435. }
  436. /*
  437. * somebody wanted the symbol, and put an undefined symbol
  438. * marker into the table
  439. */
  440. if (segment == -1)
  441. return;
  442. /*
  443. * we have more information now - update the symbol's entry
  444. */
  445. ste->segment = segment;
  446. ste->offset = offset;
  447. ste->flags = 0;
  448. return;
  449. }
  450. /*
  451. * this is the first declaration of this symbol
  452. */
  453. ste = nasm_malloc(sizeof(symtabEnt));
  454. if (!ste) {
  455. fprintf(stderr, "ldrdf: out of memory\n");
  456. exit(1);
  457. }
  458. ste->name = nasm_strdup(symbol);
  459. ste->segment = segment;
  460. ste->offset = offset;
  461. ste->flags = 0;
  462. symtabInsert(symtab, ste);
  463. }
  464. /*
  465. * symtab_get()
  466. *
  467. * Retrieves the values associated with a symbol. Undefined symbols
  468. * are assumed to have -1:0 associated. Returns 1 if the symbol was
  469. * successfully located.
  470. */
  471. int symtab_get(const char *symbol, int *segment, int32_t *offset)
  472. {
  473. symtabEnt *ste = symtabFind(symtab, symbol);
  474. if (!ste) {
  475. *segment = -1;
  476. *offset = 0;
  477. return 0;
  478. } else {
  479. *segment = ste->segment;
  480. *offset = ste->offset;
  481. return 1;
  482. }
  483. }
  484. /*
  485. * add_library()
  486. *
  487. * checks that a library can be opened and is in the correct format,
  488. * then adds it to the linked list of libraries.
  489. */
  490. static void add_library(const char *name)
  491. {
  492. if (rdl_verify(name)) {
  493. rdl_perror("ldrdf", name);
  494. errorcount++;
  495. return;
  496. }
  497. if (!libraries) {
  498. lastlib = libraries = nasm_malloc(sizeof(*libraries));
  499. if (!libraries) {
  500. fprintf(stderr, "ldrdf: out of memory\n");
  501. exit(1);
  502. }
  503. } else {
  504. lastlib->next = nasm_malloc(sizeof(*libraries));
  505. if (!lastlib->next) {
  506. fprintf(stderr, "ldrdf: out of memory\n");
  507. exit(1);
  508. }
  509. lastlib = lastlib->next;
  510. }
  511. lastlib->next = NULL;
  512. if (rdl_open(lastlib, name)) {
  513. rdl_perror("ldrdf", name);
  514. errorcount++;
  515. return;
  516. }
  517. }
  518. /*
  519. * search_libraries()
  520. *
  521. * scans through the list of libraries, attempting to match symbols
  522. * defined in library modules against symbols that are referenced but
  523. * not defined (segment = -1 in the symbol table)
  524. *
  525. * returns 1 if any extra library modules are included, indicating that
  526. * another pass through the library list should be made (possibly).
  527. */
  528. static int search_libraries(void)
  529. {
  530. struct librarynode *cur;
  531. rdffile f;
  532. int i;
  533. void *header;
  534. int segment;
  535. int32_t offset;
  536. int doneanything = 0, pass = 1, keepfile;
  537. rdfheaderrec *hr;
  538. cur = libraries;
  539. while (cur) {
  540. if (options.verbose > 2)
  541. printf("scanning library `%s', pass %d...\n", cur->name, pass);
  542. for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
  543. if (pass == 2 && lookformodule(f.name))
  544. continue;
  545. if (options.verbose > 3)
  546. printf(" looking in module `%s'\n", f.name);
  547. header = nasm_malloc(f.header_len);
  548. if (!header) {
  549. fprintf(stderr, "ldrdf: not enough memory\n");
  550. exit(1);
  551. }
  552. if (rdfloadseg(&f, RDOFF_HEADER, header)) {
  553. rdfperror("ldrdf", f.name);
  554. errorcount++;
  555. return 0;
  556. }
  557. keepfile = 0;
  558. while ((hr = rdfgetheaderrec(&f))) {
  559. /* We're only interested in exports, so skip others */
  560. if (hr->type != RDFREC_GLOBAL)
  561. continue;
  562. /*
  563. * If the symbol is marked as SYM_GLOBAL, somebody will be
  564. * definitely interested in it..
  565. */
  566. if ((hr->e.flags & SYM_GLOBAL) == 0) {
  567. /*
  568. * otherwise the symbol is just public. Find it in
  569. * the symbol table. If the symbol isn't defined, we
  570. * aren't interested, so go on to the next.
  571. * If it is defined as anything but -1, we're also not
  572. * interested. But if it is defined as -1, insert this
  573. * module into the list of modules to use, and go
  574. * immediately on to the next module...
  575. */
  576. if (!symtab_get(hr->e.label, &segment, &offset)
  577. || segment != -1)
  578. continue;
  579. }
  580. doneanything = 1;
  581. keepfile = 1;
  582. /*
  583. * as there are undefined symbols, we can assume that
  584. * there are modules on the module list by the time
  585. * we get here.
  586. */
  587. lastmodule->next = nasm_malloc(sizeof(*lastmodule->next));
  588. if (!lastmodule->next) {
  589. fprintf(stderr, "ldrdf: not enough memory\n");
  590. exit(1);
  591. }
  592. lastmodule = lastmodule->next;
  593. memcpy(&lastmodule->f, &f, sizeof(f));
  594. lastmodule->name = nasm_strdup(f.name);
  595. lastmodule->next = NULL;
  596. processmodule(f.name, lastmodule);
  597. break;
  598. }
  599. if (!keepfile) {
  600. nasm_free(f.name);
  601. f.name = NULL;
  602. f.fp = NULL;
  603. }
  604. }
  605. if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
  606. rdl_perror("ldrdf", cur->name);
  607. cur = cur->next;
  608. if (cur == NULL && pass == 1) {
  609. cur = libraries;
  610. pass++;
  611. }
  612. }
  613. return doneanything;
  614. }
  615. /*
  616. * write_output()
  617. *
  618. * this takes the linked list of modules, and walks through it, merging
  619. * all the modules into a single output module, and then writes this to a
  620. * file.
  621. */
  622. static void write_output(const char *filename)
  623. {
  624. FILE *f;
  625. rdf_headerbuf *rdfheader;
  626. struct modulenode *cur;
  627. int i, n, availableseg, seg, localseg, isrelative;
  628. void *header;
  629. rdfheaderrec *hr, newrec;
  630. symtabEnt *se;
  631. segtab segs;
  632. int32_t offset;
  633. uint8_t *data;
  634. if ((f = fopen(filename, "wb")) == NULL) {
  635. fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
  636. exit(1);
  637. }
  638. if ((rdfheader = rdfnewheader()) == NULL) {
  639. fprintf(stderr, "ldrdf: out of memory\n");
  640. exit(1);
  641. }
  642. /*
  643. * If '-g' option was given, first record in output file will be a
  644. * `generic' record, filled with a given file content.
  645. * This can be useful, for example, when constructing multiboot
  646. * compliant kernels.
  647. */
  648. if (generic_rec_file) {
  649. FILE *ff;
  650. if (options.verbose)
  651. printf("\nadding generic record from binary file %s\n",
  652. generic_rec_file);
  653. hr = (rdfheaderrec *) nasm_malloc(sizeof(struct GenericRec));
  654. if ((ff = fopen(generic_rec_file, "r")) == NULL) {
  655. fprintf(stderr, "ldrdf: couldn't open %s for input\n",
  656. generic_rec_file);
  657. exit(1);
  658. }
  659. n = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
  660. fseek(ff, 0, SEEK_END);
  661. if (ftell(ff) > (long)sizeof(hr->g.data)) {
  662. fprintf(error_file,
  663. "warning: maximum generic record size is %u, "
  664. "rest of file ignored\n",
  665. (unsigned int)sizeof(hr->g.data));
  666. }
  667. fclose(ff);
  668. hr->g.type = RDFREC_GENERIC;
  669. hr->g.reclen = n;
  670. rdfaddheader(rdfheader, hr);
  671. nasm_free(hr);
  672. }
  673. /*
  674. * Add module name record if `-mn' option was given
  675. */
  676. if (modname_specified) {
  677. n = strlen(modname_specified);
  678. if ((n < 1) || (n >= MODLIB_NAME_MAX)) {
  679. fprintf(stderr, "ldrdf: invalid length of module name `%s'\n",
  680. modname_specified);
  681. exit(1);
  682. }
  683. if (options.verbose)
  684. printf("\nadding module name record %s\n", modname_specified);
  685. hr = (rdfheaderrec *) nasm_malloc(sizeof(struct ModRec));
  686. hr->m.type = RDFREC_MODNAME;
  687. hr->m.reclen = n + 1;
  688. strcpy(hr->m.modname, modname_specified);
  689. rdfaddheader(rdfheader, hr);
  690. nasm_free(hr);
  691. }
  692. if (options.verbose)
  693. printf("\nbuilding output module (%d segments)\n", nsegs);
  694. /*
  695. * Allocate the memory for the segments. We may be better off
  696. * building the output module one segment at a time when running
  697. * under 16 bit DOS, but that would be a slower way of doing this.
  698. * And you could always use DJGPP...
  699. */
  700. for (i = 0; i < nsegs; i++) {
  701. outputseg[i].data = NULL;
  702. if (!outputseg[i].length)
  703. continue;
  704. outputseg[i].data = nasm_malloc(outputseg[i].length);
  705. if (!outputseg[i].data) {
  706. fprintf(stderr, "ldrdf: out of memory\n");
  707. exit(1);
  708. }
  709. }
  710. /*
  711. * initialise availableseg, used to allocate segment numbers for
  712. * imported and exported labels...
  713. */
  714. availableseg = nsegs;
  715. /*
  716. * Step through the modules, performing required actions on each one
  717. */
  718. for (cur = modules; cur; cur = cur->next) {
  719. /*
  720. * Read the actual segment contents into the correct places in
  721. * the newly allocated segments
  722. */
  723. for (i = 0; i < cur->f.nsegs; i++) {
  724. int dest = cur->seginfo[i].dest_seg;
  725. if (dest == -1)
  726. continue;
  727. if (rdfloadseg(&cur->f, i,
  728. outputseg[dest].data + cur->seginfo[i].reloc)) {
  729. rdfperror("ldrdf", cur->name);
  730. exit(1);
  731. }
  732. }
  733. /*
  734. * Perform fixups, and add new header records where required
  735. */
  736. header = nasm_malloc(cur->f.header_len);
  737. if (!header) {
  738. fprintf(stderr, "ldrdf: out of memory\n");
  739. exit(1);
  740. }
  741. if (cur->f.header_loc)
  742. rdfheaderrewind(&cur->f);
  743. else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
  744. rdfperror("ldrdf", cur->name);
  745. exit(1);
  746. }
  747. /*
  748. * we need to create a local segment number -> location
  749. * table for the segments in this module.
  750. */
  751. init_seglocations(&segs);
  752. for (i = 0; i < cur->f.nsegs; i++) {
  753. add_seglocation(&segs, cur->f.seg[i].number,
  754. cur->seginfo[i].dest_seg,
  755. cur->seginfo[i].reloc);
  756. }
  757. /*
  758. * and the BSS segment (doh!)
  759. */
  760. add_seglocation(&segs, 2, 2, cur->bss_reloc);
  761. while ((hr = rdfgetheaderrec(&cur->f))) {
  762. switch (hr->type) {
  763. case RDFREC_RELOC: /* relocation record - need to do a fixup */
  764. /*
  765. * First correct the offset stored in the segment from
  766. * the start of the segment (which may well have changed).
  767. *
  768. * To do this we add to the number stored the relocation
  769. * factor associated with the segment that contains the
  770. * target segment.
  771. *
  772. * The relocation could be a relative relocation, in which
  773. * case we have to first subtract the amount we've relocated
  774. * the containing segment by.
  775. */
  776. if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
  777. fprintf(stderr,
  778. "%s: reloc to undefined segment %04x\n",
  779. cur->name, (int)hr->r.refseg);
  780. errorcount++;
  781. break;
  782. }
  783. isrelative =
  784. (hr->r.segment & RDOFF_RELATIVEMASK) ==
  785. RDOFF_RELATIVEMASK;
  786. hr->r.segment &= (RDOFF_RELATIVEMASK - 1);
  787. if (hr->r.segment == 2 ||
  788. (localseg =
  789. rdffindsegment(&cur->f, hr->r.segment)) == -1) {
  790. fprintf(stderr, "%s: reloc from %s segment (%d)\n",
  791. cur->name,
  792. hr->r.segment == 2 ? "BSS" : "unknown",
  793. hr->r.segment);
  794. errorcount++;
  795. break;
  796. }
  797. if (hr->r.length != 1 && hr->r.length != 2 &&
  798. hr->r.length != 4) {
  799. fprintf(stderr, "%s: nonstandard length reloc "
  800. "(%d bytes)\n", cur->name, hr->r.length);
  801. errorcount++;
  802. break;
  803. }
  804. /*
  805. * okay, now the relocation is in the segment pointed to by
  806. * cur->seginfo[localseg], and we know everything else is
  807. * okay to go ahead and do the relocation
  808. */
  809. data = outputseg[cur->seginfo[localseg].dest_seg].data;
  810. data += cur->seginfo[localseg].reloc + hr->r.offset;
  811. /*
  812. * data now points to the reference that needs
  813. * relocation. Calculate the relocation factor.
  814. * Factor is:
  815. * offset of referred object in segment [in offset]
  816. * (- relocation of localseg, if ref is relative)
  817. * For simplicity, the result is stored in 'offset'.
  818. * Then add 'offset' onto the value at data.
  819. */
  820. if (isrelative)
  821. offset -= cur->seginfo[localseg].reloc;
  822. switch (hr->r.length) {
  823. case 1:
  824. offset += *data;
  825. if (offset < -127 || offset > 128)
  826. fprintf(error_file,
  827. "warning: relocation out of range "
  828. "at %s(%02x:%08"PRIx32")\n", cur->name,
  829. (int)hr->r.segment, hr->r.offset);
  830. *data = (char)offset;
  831. break;
  832. case 2:
  833. offset += *(int16_t *)data;
  834. if (offset < -32767 || offset > 32768)
  835. fprintf(error_file,
  836. "warning: relocation out of range "
  837. "at %s(%02x:%08"PRIx32")\n", cur->name,
  838. (int)hr->r.segment, hr->r.offset);
  839. *(int16_t *)data = (int16_t)offset;
  840. break;
  841. case 4:
  842. *(int32_t *)data += offset;
  843. /* we can't easily detect overflow on this one */
  844. break;
  845. }
  846. /*
  847. * If the relocation was relative between two symbols in
  848. * the same segment, then we're done.
  849. *
  850. * Otherwise, we need to output a new relocation record
  851. * with the references updated segment and offset...
  852. */
  853. if (!isrelative || cur->seginfo[localseg].dest_seg != seg) {
  854. hr->r.segment = cur->seginfo[localseg].dest_seg;
  855. hr->r.offset += cur->seginfo[localseg].reloc;
  856. hr->r.refseg = seg;
  857. if (isrelative)
  858. hr->r.segment += RDOFF_RELATIVEMASK;
  859. rdfaddheader(rdfheader, hr);
  860. }
  861. break;
  862. case RDFREC_IMPORT: /* import symbol */
  863. case RDFREC_FARIMPORT:
  864. /*
  865. * scan the global symbol table for the symbol
  866. * and associate its location with the segment number
  867. * for this module
  868. */
  869. se = symtabFind(symtab, hr->i.label);
  870. if (!se || se->segment == -1) {
  871. if (!options.dynalink && !(hr->i.flags & SYM_IMPORT)) {
  872. fprintf(error_file,
  873. "error: unresolved reference to `%s'"
  874. " in module `%s'\n", hr->i.label,
  875. cur->name);
  876. errorcount++;
  877. }
  878. /*
  879. * we need to allocate a segment number for this
  880. * symbol, and store it in the symbol table for
  881. * future reference
  882. */
  883. if (!se) {
  884. se = nasm_malloc(sizeof(*se));
  885. if (!se) {
  886. fprintf(stderr, "ldrdf: out of memory\n");
  887. exit(1);
  888. }
  889. se->name = nasm_strdup(hr->i.label);
  890. se->flags = 0;
  891. se->segment = availableseg++;
  892. se->offset = 0;
  893. symtabInsert(symtab, se);
  894. } else {
  895. se->segment = availableseg++;
  896. se->offset = 0;
  897. }
  898. /*
  899. * output a header record that imports it to the
  900. * recently allocated segment number...
  901. */
  902. newrec = *hr;
  903. newrec.i.segment = se->segment;
  904. rdfaddheader(rdfheader, &newrec);
  905. }
  906. add_seglocation(&segs, hr->i.segment, se->segment,
  907. se->offset);
  908. break;
  909. case RDFREC_GLOBAL: /* export symbol */
  910. /*
  911. * need to insert an export for this symbol into the new
  912. * header, unless we're stripping symbols. Even if we're
  913. * stripping, put the symbol if it's marked as SYM_GLOBAL.
  914. */
  915. if (options.strip && !(hr->e.flags & SYM_GLOBAL))
  916. break;
  917. if (hr->e.segment == 2) {
  918. seg = 2;
  919. offset = cur->bss_reloc;
  920. } else {
  921. localseg = rdffindsegment(&cur->f, hr->e.segment);
  922. if (localseg == -1) {
  923. fprintf(stderr, "%s: exported symbol `%s' from "
  924. "unrecognised segment\n", cur->name,
  925. hr->e.label);
  926. errorcount++;
  927. break;
  928. }
  929. offset = cur->seginfo[localseg].reloc;
  930. seg = cur->seginfo[localseg].dest_seg;
  931. }
  932. hr->e.segment = seg;
  933. hr->e.offset += offset;
  934. rdfaddheader(rdfheader, hr);
  935. break;
  936. case RDFREC_MODNAME: /* module name */
  937. /*
  938. * Insert module name record if export symbols
  939. * are not stripped.
  940. * If module name begins with '$' - insert it anyway.
  941. */
  942. if (options.strip && hr->m.modname[0] != '$')
  943. break;
  944. rdfaddheader(rdfheader, hr);
  945. break;
  946. case RDFREC_DLL: /* DLL name */
  947. /*
  948. * Insert DLL name if it begins with '$'
  949. */
  950. if (hr->d.libname[0] != '$')
  951. break;
  952. rdfaddheader(rdfheader, hr);
  953. break;
  954. case RDFREC_SEGRELOC: /* segment fixup */
  955. /*
  956. * modify the segment numbers if necessary, and
  957. * pass straight through to the output module header
  958. *
  959. * *** FIXME ***
  960. */
  961. if (hr->r.segment == 2) {
  962. fprintf(stderr, "%s: segment fixup in BSS section\n",
  963. cur->name);
  964. errorcount++;
  965. break;
  966. }
  967. localseg = rdffindsegment(&cur->f, hr->r.segment);
  968. if (localseg == -1) {
  969. fprintf(stderr, "%s: segment fixup in unrecognised"
  970. " segment (%d)\n", cur->name, hr->r.segment);
  971. errorcount++;
  972. break;
  973. }
  974. hr->r.segment = cur->seginfo[localseg].dest_seg;
  975. hr->r.offset += cur->seginfo[localseg].reloc;
  976. if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
  977. fprintf(stderr, "%s: segment fixup to undefined "
  978. "segment %04x\n", cur->name,
  979. (int)hr->r.refseg);
  980. errorcount++;
  981. break;
  982. }
  983. hr->r.refseg = seg;
  984. rdfaddheader(rdfheader, hr);
  985. break;
  986. case RDFREC_COMMON: /* Common variable */
  987. /* Is this symbol already in the table? */
  988. se = symtabFind(symtab, hr->c.label);
  989. if (!se) {
  990. printf("%s is not in symtab yet\n", hr->c.label);
  991. break;
  992. }
  993. /* Add segment location */
  994. add_seglocation(&segs, hr->c.segment, se->segment,
  995. se->offset);
  996. break;
  997. }
  998. }
  999. nasm_free(header);
  1000. done_seglocations(&segs);
  1001. }
  1002. /*
  1003. * combined BSS reservation for the entire results
  1004. */
  1005. newrec.type = RDFREC_BSS;
  1006. newrec.b.reclen = 4;
  1007. newrec.b.amount = bss_length;
  1008. rdfaddheader(rdfheader, &newrec);
  1009. /*
  1010. * Write the header
  1011. */
  1012. for (i = 0; i < nsegs; i++) {
  1013. if (i == 2)
  1014. continue;
  1015. rdfaddsegment(rdfheader, outputseg[i].length);
  1016. }
  1017. rdfwriteheader(f, rdfheader);
  1018. rdfdoneheader(rdfheader);
  1019. /*
  1020. * Step through the segments, one at a time, writing out into
  1021. * the output file
  1022. */
  1023. for (i = 0; i < nsegs; i++) {
  1024. if (i == 2)
  1025. continue;
  1026. fwriteint16_t(outputseg[i].type, f);
  1027. fwriteint16_t(outputseg[i].number, f);
  1028. fwriteint16_t(outputseg[i].reserved, f);
  1029. fwriteint32_t(outputseg[i].length, f);
  1030. nasm_write(outputseg[i].data, outputseg[i].length, f);
  1031. }
  1032. fwritezero(10, f);
  1033. }
  1034. /* =========================================================================
  1035. * Main program
  1036. */
  1037. static void usage(void)
  1038. {
  1039. printf("usage:\n"
  1040. " ldrdf [options] object modules ... [-llibrary ...]\n"
  1041. " ldrdf -r\n"
  1042. "options:\n"
  1043. " -v[=n] increase verbosity by 1, or set it to n\n"
  1044. " -a nn set segment alignment value (default 16)\n"
  1045. " -s strip public symbols\n"
  1046. " -dy Unix-style dynamic linking\n"
  1047. " -o name write output in file 'name'\n"
  1048. " -j path specify objects search path\n"
  1049. " -L path specify libraries search path\n"
  1050. " -g file embed 'file' as a first header record with type 'generic'\n"
  1051. " -mn name add module name record at the beginning of output file\n");
  1052. exit(0);
  1053. }
  1054. int main(int argc, char **argv)
  1055. {
  1056. char *outname = "aout.rdf";
  1057. int moduleloaded = 0;
  1058. char *respstrings[128] = { 0, };
  1059. rdoff_init();
  1060. options.verbose = 0;
  1061. options.align = 16;
  1062. options.dynalink = 0;
  1063. options.strip = 0;
  1064. error_file = stderr;
  1065. argc--, argv++;
  1066. if (argc == 0)
  1067. usage();
  1068. while (argc && *argv && **argv == '-' && argv[0][1] != 'l') {
  1069. switch (argv[0][1]) {
  1070. case 'r':
  1071. printf("ldrdf (linker for RDF files) version " LDRDF_VERSION
  1072. "\n");
  1073. printf("RDOFF2 revision %s\n", RDOFF2_REVISION);
  1074. exit(0);
  1075. case 'v':
  1076. if (argv[0][2] == '=') {
  1077. options.verbose = argv[0][3] - '0';
  1078. if (options.verbose < 0 || options.verbose > 9) {
  1079. fprintf(stderr,
  1080. "ldrdf: verbosity level must be a number"
  1081. " between 0 and 9\n");
  1082. exit(1);
  1083. }
  1084. } else
  1085. options.verbose++;
  1086. break;
  1087. case 'a':
  1088. options.align = atoi(argv[1]);
  1089. if (options.align <= 0) {
  1090. fprintf(stderr,
  1091. "ldrdf: -a expects a positive number argument\n");
  1092. exit(1);
  1093. }
  1094. argv++, argc--;
  1095. break;
  1096. case 's':
  1097. options.strip = 1;
  1098. break;
  1099. case 'd':
  1100. if (argv[0][2] == 'y')
  1101. options.dynalink = 1;
  1102. break;
  1103. case 'm':
  1104. if (argv[0][2] == 'n') {
  1105. modname_specified = argv[1];
  1106. argv++, argc--;
  1107. if (!argc) {
  1108. fprintf(stderr, "ldrdf: -mn expects a module name\n");
  1109. exit(1);
  1110. }
  1111. }
  1112. break;
  1113. case 'o':
  1114. outname = argv[1];
  1115. argv++, argc--;
  1116. break;
  1117. case 'j':
  1118. if (!objpath) {
  1119. options.objpath = 1;
  1120. objpath = argv[1];
  1121. argv++, argc--;
  1122. break;
  1123. } else {
  1124. fprintf(stderr,
  1125. "ldrdf: more than one objects search path specified\n");
  1126. exit(1);
  1127. }
  1128. case 'L':
  1129. if (!libpath) {
  1130. options.libpath = 1;
  1131. libpath = argv[1];
  1132. argv++, argc--;
  1133. break;
  1134. } else {
  1135. fprintf(stderr,
  1136. "ldrdf: more than one libraries search path specified\n");
  1137. exit(1);
  1138. }
  1139. case '@':{
  1140. int i = 0;
  1141. char buf[256];
  1142. FILE *f;
  1143. options.respfile = 1;
  1144. if (argv[1] != NULL)
  1145. f = fopen(argv[1], "r");
  1146. else {
  1147. fprintf(stderr,
  1148. "ldrdf: no response file name specified\n");
  1149. exit(1);
  1150. }
  1151. if (f == NULL) {
  1152. fprintf(stderr,
  1153. "ldrdf: unable to open response file\n");
  1154. exit(1);
  1155. }
  1156. argv++, argc--;
  1157. while (fgets(buf, sizeof(buf), f) != NULL) {
  1158. char *p;
  1159. if (buf[0] == '\n')
  1160. continue;
  1161. if ((p = strchr(buf, '\n')) != NULL)
  1162. *p = '\0';
  1163. if (i >= 128) {
  1164. fclose(f);
  1165. fprintf(stderr, "ldrdf: too many input files\n");
  1166. exit(1);
  1167. }
  1168. *(respstrings + i) = nasm_strdup(buf);
  1169. argc++, i++;
  1170. }
  1171. fclose(f);
  1172. break;
  1173. }
  1174. case '2':
  1175. options.stderr_redir = 1;
  1176. error_file = stdout;
  1177. break;
  1178. case 'g':
  1179. generic_rec_file = argv[1];
  1180. argv++, argc--;
  1181. if (!argc) {
  1182. fprintf(stderr, "ldrdf: -g expects a file name\n");
  1183. exit(1);
  1184. }
  1185. break;
  1186. default:
  1187. usage();
  1188. }
  1189. argv++, argc--;
  1190. }
  1191. if (options.verbose > 4) {
  1192. printf("ldrdf invoked with options:\n");
  1193. printf(" section alignment: %d bytes\n", options.align);
  1194. printf(" output name: `%s'\n", outname);
  1195. if (options.strip)
  1196. printf(" strip symbols\n");
  1197. if (options.dynalink)
  1198. printf(" Unix-style dynamic linking\n");
  1199. if (options.objpath)
  1200. printf(" objects search path: %s\n", objpath);
  1201. if (options.libpath)
  1202. printf(" libraries search path: %s\n", libpath);
  1203. printf("\n");
  1204. }
  1205. symtab = symtabNew();
  1206. initsegments();
  1207. if (!symtab) {
  1208. fprintf(stderr, "ldrdf: out of memory\n");
  1209. exit(1);
  1210. }
  1211. while (argc) {
  1212. if (!*argv)
  1213. argv = respstrings;
  1214. if (!*argv)
  1215. break;
  1216. if (!strncmp(*argv, "-l", 2)) {
  1217. if (libpath && (argv[0][2] != '/'))
  1218. add_library(nasm_strcat(libpath, *argv + 2));
  1219. else
  1220. add_library(*argv + 2);
  1221. } else {
  1222. if (objpath && (argv[0][0] != '/'))
  1223. loadmodule(nasm_strcat(objpath, *argv));
  1224. else
  1225. loadmodule(*argv);
  1226. moduleloaded = 1;
  1227. }
  1228. argv++, argc--;
  1229. }
  1230. if (!moduleloaded) {
  1231. printf("ldrdf: nothing to do. ldrdf -h for usage\n");
  1232. return 0;
  1233. }
  1234. search_libraries();
  1235. if (options.verbose > 2) {
  1236. printf("symbol table:\n");
  1237. symtabDump(symtab, stdout);
  1238. }
  1239. write_output(outname);
  1240. if (errorcount > 0) {
  1241. remove(outname);
  1242. exit(1);
  1243. }
  1244. return 0;
  1245. }