rdf2bin.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /* ----------------------------------------------------------------------- *
  2. *
  3. * Copyright 1996-2009 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. * rdf2bin.c - convert an RDOFF object file to flat binary
  35. */
  36. #include "compiler.h"
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <ctype.h>
  41. #include <errno.h>
  42. #include "rdfload.h"
  43. #include "nasmlib.h"
  44. const char *progname;
  45. static uint32_t origin = 0;
  46. static bool origin_def = false;
  47. static uint32_t align = 16;
  48. static bool align_def = false;
  49. struct output_format {
  50. const char *name;
  51. const char *mode;
  52. int (*init)(FILE *f);
  53. int (*output)(FILE *f, void *data, uint32_t bytes, uint32_t where);
  54. int (*fini)(FILE *f);
  55. };
  56. static int null_init_fini(FILE *f)
  57. {
  58. (void)f;
  59. return 0;
  60. }
  61. static int com_init(FILE *f)
  62. {
  63. (void)f;
  64. if (!origin_def)
  65. origin = 0x100;
  66. return 0;
  67. }
  68. static int output_bin(FILE *f, void *data, uint32_t bytes, uint32_t where)
  69. {
  70. static uint32_t offset = 0; /* Current file offset, if applicable */
  71. size_t pad;
  72. if (where-origin < offset) {
  73. fprintf(stderr, "%s: internal error: backwards movement\n", progname);
  74. exit(1);
  75. }
  76. pad = (where-origin) - offset;
  77. fwritezero(pad, f);
  78. offset += pad;
  79. if (fwrite(data, 1, bytes, f) != bytes)
  80. return -1;
  81. offset += bytes;
  82. return 0;
  83. }
  84. static int write_ith_record(FILE *f, unsigned int len, uint16_t addr,
  85. uint8_t type, void *data)
  86. {
  87. char buf[1+2+4+2+255*2+2+2];
  88. char *p = buf;
  89. uint8_t csum, *dptr = data;
  90. unsigned int i;
  91. if (len > 255) {
  92. fprintf(stderr, "%s: internal error: invalid ith record size\n",
  93. progname);
  94. exit(1);
  95. }
  96. csum = len + addr + (addr >> 8) + type;
  97. for (i = 0; i < len; i++)
  98. csum += dptr[i];
  99. csum = -csum;
  100. p += sprintf(p, ":%02X%04X%02X", len, addr, type);
  101. for (i = 0; i < len; i++)
  102. p += sprintf(p, "%02X", dptr[i]);
  103. p += sprintf(p, "%02X\n", csum);
  104. if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
  105. return -1;
  106. return 0;
  107. }
  108. static int output_ith(FILE *f, void *data, uint32_t bytes, uint32_t where)
  109. {
  110. static uint32_t last = 0; /* Last address written */
  111. uint8_t abuf[2];
  112. uint8_t *dbuf = data;
  113. uint32_t chunk;
  114. while (bytes) {
  115. if ((where ^ last) & ~0xffff) {
  116. abuf[0] = where >> 24;
  117. abuf[1] = where >> 16;
  118. if (write_ith_record(f, 2, 0, 4, abuf))
  119. return -1;
  120. }
  121. /* Output up to 32 bytes, but always end on an aligned boundary */
  122. chunk = 32 - (where & 31);
  123. if (bytes < chunk)
  124. chunk = bytes;
  125. if (write_ith_record(f, chunk, (uint16_t)where, 0, dbuf))
  126. return -1;
  127. dbuf += chunk;
  128. last = where + chunk - 1;
  129. where += chunk;
  130. bytes -= chunk;
  131. }
  132. return 0;
  133. }
  134. static int fini_ith(FILE *f)
  135. {
  136. /* XXX: entry point? */
  137. return write_ith_record(f, 0, 0, 1, NULL);
  138. }
  139. static int write_srecord(FILE *f, unsigned int len, unsigned int alen,
  140. uint32_t addr, uint8_t type, void *data)
  141. {
  142. char buf[2+2+8+255*2+2+2];
  143. char *p = buf;
  144. uint8_t csum, *dptr = data;
  145. unsigned int i;
  146. if (len > 255) {
  147. fprintf(stderr, "%s: internal error: invalid srec record size\n",
  148. progname);
  149. exit(1);
  150. }
  151. switch (alen) {
  152. case 2:
  153. addr &= 0xffff;
  154. break;
  155. case 3:
  156. addr &= 0xffffff;
  157. break;
  158. case 4:
  159. break;
  160. default:
  161. fprintf(stderr, "%s: internal error: invalid srec address length\n",
  162. progname);
  163. exit(1);
  164. }
  165. csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
  166. for (i = 0; i < len; i++)
  167. csum += dptr[i];
  168. csum = 0xff-csum;
  169. p += sprintf(p, "S%c%02X%0*X", type, len+alen+1, alen*2, addr);
  170. for (i = 0; i < len; i++)
  171. p += sprintf(p, "%02X", dptr[i]);
  172. p += sprintf(p, "%02X\n", csum);
  173. if (fwrite(buf, 1, p-buf, f) != (size_t)(p-buf))
  174. return -1;
  175. return 0;
  176. }
  177. static int init_srec(FILE *f)
  178. {
  179. return write_srecord(f, 0, 2, 0, '0', NULL);
  180. }
  181. static int fini_srec(FILE *f)
  182. {
  183. /* XXX: entry point? */
  184. return write_srecord(f, 0, 4, 0, '7', NULL);
  185. }
  186. static int output_srec(FILE *f, void *data, uint32_t bytes, uint32_t where)
  187. {
  188. uint8_t *dbuf = data;
  189. unsigned int chunk;
  190. while (bytes) {
  191. /* Output up to 32 bytes, but always end on an aligned boundary */
  192. chunk = 32 - (where & 31);
  193. if (bytes < chunk)
  194. chunk = bytes;
  195. if (write_srecord(f, chunk, 4, where, '3', dbuf))
  196. return -1;
  197. dbuf += chunk;
  198. where += chunk;
  199. bytes -= chunk;
  200. }
  201. return 0;
  202. }
  203. static struct output_format output_formats[] = {
  204. { "bin", "wb", null_init_fini, output_bin, null_init_fini },
  205. { "com", "wb", com_init, output_bin, null_init_fini },
  206. { "ith", "wt", null_init_fini, output_ith, fini_ith },
  207. { "ihx", "wt", null_init_fini, output_ith, fini_ith },
  208. { "srec", "wt", init_srec, output_srec, fini_srec },
  209. { NULL, NULL, NULL, NULL, NULL }
  210. };
  211. static const char *getformat(const char *pathname)
  212. {
  213. const char *p;
  214. static char fmt_buf[16];
  215. /*
  216. * Search backwards for the string "rdf2" followed by a string
  217. * of alphanumeric characters. This should handle path prefixes,
  218. * as well as extensions (e.g. C:\FOO\RDF2SREC.EXE).
  219. */
  220. for (p = strchr(pathname, '\0')-1 ; p >= pathname ; p--) {
  221. if (!nasm_stricmp(p, "rdf2")) {
  222. const char *q = p+4;
  223. char *r = fmt_buf;
  224. while (isalnum(*q) && r < fmt_buf+sizeof fmt_buf-1)
  225. *r++ = *q++;
  226. *r = '\0';
  227. if (fmt_buf[0])
  228. return fmt_buf;
  229. }
  230. }
  231. return NULL;
  232. }
  233. static void usage(void)
  234. {
  235. fprintf(stderr,
  236. "Usage: %s [options] input-file output-file\n"
  237. "Options:\n"
  238. " -o origin Specify the relocation origin\n"
  239. " -p alignment Specify minimum segment alignment\n"
  240. " -f format Select format (bin, com, ith, srec)\n"
  241. " -q Run quiet\n"
  242. " -v Run verbose\n",
  243. progname);
  244. }
  245. int main(int argc, char **argv)
  246. {
  247. rdfmodule *m;
  248. bool err;
  249. FILE *of;
  250. int codepad, datapad;
  251. const char *format = NULL;
  252. const struct output_format *fmt;
  253. bool quiet = false;
  254. progname = argv[0];
  255. if (argc < 2) {
  256. usage();
  257. return 1;
  258. }
  259. rdoff_init();
  260. argv++, argc--;
  261. while (argc > 2) {
  262. if (argv[0][0] == '-' && argv[0][1] && !argv[0][2]) {
  263. switch (argv[0][1]) {
  264. case 'o':
  265. argv++, argc--;
  266. origin = readnum(*argv, &err);
  267. if (err) {
  268. fprintf(stderr, "%s: invalid parameter: %s\n",
  269. progname, *argv);
  270. return 1;
  271. }
  272. origin_def = true;
  273. break;
  274. case 'p':
  275. argv++, argc--;
  276. align = readnum(*argv, &err);
  277. if (err) {
  278. fprintf(stderr, "%s: invalid parameter: %s\n",
  279. progname, *argv);
  280. return 1;
  281. }
  282. align_def = true;
  283. break;
  284. case 'f':
  285. argv++, argc--;
  286. format = *argv;
  287. break;
  288. case 'q':
  289. quiet = true;
  290. break;
  291. case 'v':
  292. quiet = false;
  293. break;
  294. case 'h':
  295. usage();
  296. return 0;
  297. default:
  298. fprintf(stderr, "%s: unknown option: %s\n",
  299. progname, *argv);
  300. return 1;
  301. }
  302. }
  303. argv++, argc--;
  304. }
  305. if (argc < 2) {
  306. usage();
  307. return 1;
  308. }
  309. if (!format)
  310. format = getformat(progname);
  311. if (!format) {
  312. fprintf(stderr, "%s: unable to determine desired output format\n",
  313. progname);
  314. return 1;
  315. }
  316. for (fmt = output_formats; fmt->name; fmt++) {
  317. if (!nasm_stricmp(format, fmt->name))
  318. break;
  319. }
  320. if (!fmt->name) {
  321. fprintf(stderr, "%s: unknown output format: %s\n", progname, format);
  322. return 1;
  323. }
  324. m = rdfload(*argv);
  325. if (!m) {
  326. rdfperror(progname, *argv);
  327. return 1;
  328. }
  329. if (!quiet)
  330. printf("relocating %s: origin=%"PRIx32", align=%d\n",
  331. *argv, origin, align);
  332. m->textrel = origin;
  333. m->datarel = origin + m->f.seg[0].length;
  334. if (m->datarel % align != 0) {
  335. codepad = align - (m->datarel % align);
  336. m->datarel += codepad;
  337. } else
  338. codepad = 0;
  339. m->bssrel = m->datarel + m->f.seg[1].length;
  340. if (m->bssrel % align != 0) {
  341. datapad = align - (m->bssrel % align);
  342. m->bssrel += datapad;
  343. } else
  344. datapad = 0;
  345. if (!quiet)
  346. printf("code: %08"PRIx32"\ndata: %08"PRIx32"\nbss: %08"PRIx32"\n",
  347. m->textrel, m->datarel, m->bssrel);
  348. rdf_relocate(m);
  349. argv++;
  350. of = fopen(*argv, fmt->mode);
  351. if (!of) {
  352. fprintf(stderr, "%s: could not open output file %s: %s\n",
  353. progname, *argv, strerror(errno));
  354. return 1;
  355. }
  356. if (fmt->init(of) ||
  357. fmt->output(of, m->t, m->f.seg[0].length, m->textrel) ||
  358. fmt->output(of, m->d, m->f.seg[1].length, m->datarel) ||
  359. fmt->fini(of)) {
  360. fprintf(stderr, "%s: error writing to %s: %s\n",
  361. progname, *argv, strerror(errno));
  362. return 1;
  363. }
  364. fclose(of);
  365. return 0;
  366. }