blood-elf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /* -*- c-file-style: "linux";indent-tabs-mode:t -*- */
  2. /* Copyright (C) 2017 Jeremiah Orians
  3. * Copyright (C) 2017 Jan Nieuwenhuizen <janneke@gnu.org>
  4. * This file is part of mescc-tools
  5. *
  6. * mescc-tools is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * mescc-tools is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with mescc-tools. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <unistd.h>
  23. #include <sys/stat.h>
  24. #include "M2libc/bootstrappable.h"
  25. // CONSTANT max_string 4096
  26. #define max_string 4096
  27. int BITSIZE;
  28. int BigEndian;
  29. // CONSTANT HEX 16
  30. #define HEX 16
  31. // CONSTANT OCTAL 8
  32. #define OCTAL 8
  33. // CONSTANT BINARY 2
  34. #define BINARY 2
  35. /* Strings needed for constants */
  36. char* zero_8;
  37. char* zero_16;
  38. char* zero_32;
  39. char* one_16;
  40. char* one_32;
  41. char* two_8;
  42. char* two_32;
  43. char* three_32;
  44. char* six_32;
  45. char* sixteen_32;
  46. char* twentyfour_32;
  47. /* Imported from stringify.c */
  48. int stringify(char* s, int digits, int divisor, int value, int shift);
  49. void LittleEndian(char* start, int ByteMode);
  50. struct entry
  51. {
  52. struct entry* next;
  53. char* name;
  54. };
  55. FILE* output;
  56. struct entry* jump_table;
  57. int count;
  58. char* entry;
  59. void consume_token(FILE* source_file, char* s)
  60. {
  61. int i = 0;
  62. int c = fgetc(source_file);
  63. require(EOF != c, "Can not have an EOF token\n");
  64. do
  65. {
  66. s[i] = c;
  67. i = i + 1;
  68. require(max_string > i, "Token exceeds token length restriction\n");
  69. c = fgetc(source_file);
  70. if(EOF == c) break;
  71. } while(!in_set(c, " \t\n>"));
  72. }
  73. void storeLabel(FILE* source_file)
  74. {
  75. struct entry* entry = calloc(1, sizeof(struct entry));
  76. /* Prepend to list */
  77. entry->next = jump_table;
  78. jump_table = entry;
  79. /* Store string */
  80. entry->name = calloc((max_string + 1), sizeof(char));
  81. consume_token(source_file, entry->name);
  82. count = count + 1;
  83. }
  84. void line_Comment(FILE* source_file)
  85. {
  86. int c = fgetc(source_file);
  87. while(!in_set(c, "\n\r"))
  88. {
  89. if(EOF == c) break;
  90. c = fgetc(source_file);
  91. }
  92. }
  93. void purge_string(FILE* source_file)
  94. {
  95. int c = fgetc(source_file);
  96. while((EOF != c) && ('"' != c))
  97. {
  98. c = fgetc(source_file);
  99. }
  100. }
  101. void first_pass(struct entry* input)
  102. {
  103. if(NULL == input) return;
  104. first_pass(input->next);
  105. FILE* source_file = fopen(input->name, "r");
  106. if(NULL == source_file)
  107. {
  108. fputs("The file: ", stderr);
  109. fputs(input->name, stderr);
  110. fputs(" can not be opened!\n", stderr);
  111. exit(EXIT_FAILURE);
  112. }
  113. int c;
  114. for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
  115. {
  116. /* Check for and deal with label */
  117. if(58 == c)
  118. {
  119. storeLabel(source_file);
  120. }
  121. /* Check for and deal with line comments */
  122. else if (c == '#' || c == ';')
  123. {
  124. line_Comment(source_file);
  125. }
  126. else if ('"' == c)
  127. {
  128. purge_string(source_file);
  129. }
  130. }
  131. fclose(source_file);
  132. }
  133. void output_string_table(struct entry* node)
  134. {
  135. fputs("\n# Generated string table\n:ELF_str\n", output);
  136. fputs(zero_8, output);
  137. fputs("\t# NULL string\n", output);
  138. struct entry* i;
  139. for(i = node; NULL != i; i = i->next)
  140. {
  141. fputs(":ELF_str_", output);
  142. fputs(i->name, output);
  143. fputs("\t\"", output);
  144. fputs(i->name, output);
  145. fputs("\"\n", output);
  146. }
  147. fputs("# END Generated string table\n\n", output);
  148. }
  149. void output_symbol_table(struct entry* node)
  150. {
  151. fputs("\n# Generated symbol table\n:ELF_sym\n# Required NULL symbol entry\n", output);
  152. if(64 == BITSIZE)
  153. {
  154. fputs(zero_32, output);
  155. fputs("\t# st_name\n", output);
  156. fputs(zero_8, output);
  157. fputs("\t# st_info\n", output);
  158. fputs(zero_8, output);
  159. fputs("\t# st_other\n", output);
  160. fputs(one_16, output);
  161. fputs("\t# st_shndx\n", output);
  162. fputs(zero_32, output);
  163. fputc(' ', output);
  164. fputs(zero_32, output);
  165. fputs("\t# st_value\n", output);
  166. fputs(zero_32, output);
  167. fputc(' ', output);
  168. fputs(zero_32, output);
  169. fputs("\t# st_size\n\n", output);
  170. }
  171. else
  172. {
  173. fputs(zero_32, output);
  174. fputs("\t# st_name\n", output);
  175. fputs(zero_32, output);
  176. fputs("\t# st_value\n", output);
  177. fputs(zero_32, output);
  178. fputs("\t# st_size\n", output);
  179. fputs(zero_8, output);
  180. fputs("\t# st_info\n", output);
  181. fputs(zero_8, output);
  182. fputs("\t# st_other\n", output);
  183. fputs(one_16, output);
  184. fputs("\t# st_shndx\n\n", output);
  185. }
  186. struct entry* i;
  187. for(i = node; NULL != i; i = i->next)
  188. {
  189. fputs("%ELF_str_", output);
  190. fputs(i->name, output);
  191. fputs(">ELF_str\t# st_name\n", output);
  192. if(64 == BITSIZE)
  193. {
  194. fputs(two_8, output);
  195. fputs("\t# st_info (FUNC)\n", output);
  196. if(('_' == i->name[0]) && !match(entry, i->name))
  197. {
  198. fputs(two_8, output);
  199. fputs("\t# st_other (hidden)\n", output);
  200. }
  201. else
  202. {
  203. fputs(zero_8, output);
  204. fputs("\t# st_other (other)\n", output);
  205. }
  206. fputs(one_16, output);
  207. fputs("\t# st_shndx\n", output);
  208. fputs("&", output);
  209. fputs(i->name, output);
  210. fputc(' ', output);
  211. fputs(zero_32, output);
  212. fputs("\t# st_value\n", output);
  213. fputs(zero_32, output);
  214. fputc(' ', output);
  215. fputs(zero_32, output);
  216. fputs("\t# st_size (unknown size)\n\n", output);
  217. }
  218. else
  219. {
  220. fputs("&", output);
  221. fputs(i->name, output);
  222. fputs("\t#st_value\n", output);
  223. fputs(zero_32, output);
  224. fputs("\t# st_size (unknown size)\n", output);
  225. fputs(two_8, output);
  226. fputs("\t# st_info (FUNC)\n", output);
  227. if(('_' == i->name[0]) && !match(entry, i->name))
  228. {
  229. fputs(two_8, output);
  230. fputs("\t# st_other (hidden)\n", output);
  231. }
  232. else
  233. {
  234. fputs(zero_8, output);
  235. fputs("\t# st_other (default)\n", output);
  236. }
  237. fputs(one_16, output);
  238. fputs("\t# st_shndx\n\n", output);
  239. }
  240. }
  241. fputs("# END Generated symbol table\n", output);
  242. }
  243. struct entry* reverse_list(struct entry* head)
  244. {
  245. struct entry* root = NULL;
  246. struct entry* next;
  247. while(NULL != head)
  248. {
  249. next = head->next;
  250. head->next = root;
  251. root = head;
  252. head = next;
  253. }
  254. return root;
  255. }
  256. void write_int(char* field, char* label)
  257. {
  258. fputs(field, output);
  259. fputs("\t#", output);
  260. fputs(label, output);
  261. fputc('\n', output);
  262. }
  263. void write_register(char* field, char* label)
  264. {
  265. /* $field section in the section headers are different size for 32 and 64bits */
  266. /* The below is broken for BigEndian */
  267. fputs(field, output);
  268. if(64 == BITSIZE)
  269. {
  270. fputc(' ', output);
  271. fputs(zero_32, output);
  272. }
  273. fputs("\t#", output);
  274. fputs(label, output);
  275. fputc('\n', output);
  276. }
  277. void write_section(char* label, char* name, char* type, char* flags, char* address, char* offset, char* size, char* link, char* info, char* entry)
  278. {
  279. /* Write label */
  280. fputc('\n', output);
  281. fputs(label, output);
  282. fputc('\n', output);
  283. write_int(name, "sh_name");
  284. write_int(type, "sh_type");
  285. write_register(flags, "sh_flags");
  286. write_register(address, "sh_addr");
  287. write_register(offset, "sh_offset");
  288. write_register(size, "sh_size");
  289. write_int(link, "sh_link");
  290. /* Deal with the ugly case of stubs */
  291. fputs(info, output);
  292. fputs("\t#sh_info\n", output);
  293. /* Alignment section in the section headers are different size for 32 and 64bits */
  294. /* The below is broken for BigEndian */
  295. if(64 == BITSIZE)
  296. {
  297. fputs(one_32, output);
  298. fputc(' ', output);
  299. fputs(zero_32, output);
  300. fputs("\t#sh_addralign\n", output);
  301. }
  302. else
  303. {
  304. fputs(one_32, output);
  305. fputs("\t#sh_addralign\n", output);
  306. }
  307. write_register(entry, "sh_entsize");
  308. }
  309. char* get_string(int value, int size, int ByteMode, int shift)
  310. {
  311. char* ch = calloc(42, sizeof(char));
  312. require(NULL != ch, "Exhausted available memory\n");
  313. ch[0] = '\'';
  314. stringify(ch+1, size, ByteMode, value, shift);
  315. if(!BigEndian) LittleEndian(ch+1, ByteMode);
  316. int i = 0;
  317. while(0 != ch[i])
  318. {
  319. i = i + 1;
  320. }
  321. ch[i] = '\'';
  322. return ch;
  323. }
  324. char* setup_string(int value, int number_of_bytes, int ByteMode)
  325. {
  326. int shift;
  327. int size;
  328. if(HEX == ByteMode)
  329. {
  330. size = 2;
  331. shift = 4;
  332. }
  333. else if(OCTAL == ByteMode)
  334. {
  335. size = 3;
  336. shift = 3;
  337. }
  338. else if(BINARY == ByteMode)
  339. {
  340. size = 8;
  341. shift = 1;
  342. }
  343. else
  344. {
  345. fputs("reached impossible mode\n", stderr);
  346. exit(EXIT_FAILURE);
  347. }
  348. return get_string(value, number_of_bytes *size, ByteMode, shift);
  349. }
  350. void setup_strings(int ByteMode)
  351. {
  352. zero_8 = setup_string(0, 1, ByteMode);
  353. zero_16 = setup_string(0, 2, ByteMode);
  354. zero_32 = setup_string(0, 4, ByteMode);
  355. one_16 = setup_string(1, 2, ByteMode);
  356. one_32 = setup_string(1, 4, ByteMode);
  357. two_8 = setup_string(2, 1, ByteMode);
  358. two_32 = setup_string(2, 4, ByteMode);
  359. three_32 = setup_string(3, 4, ByteMode);
  360. six_32 = setup_string(6, 4, ByteMode);
  361. sixteen_32 = setup_string(16, 4, ByteMode);
  362. twentyfour_32 = setup_string(24, 4, ByteMode);
  363. }
  364. /* Standard C main program */
  365. int main(int argc, char **argv)
  366. {
  367. jump_table = NULL;
  368. struct entry* input = NULL;
  369. output = stdout;
  370. char* output_file = "";
  371. entry = "";
  372. BITSIZE = 32;
  373. count = 1;
  374. BigEndian = TRUE;
  375. int ByteMode = HEX;
  376. int set = FALSE;
  377. struct entry* temp;
  378. struct entry* head;
  379. int option_index = 1;
  380. while(option_index <= argc)
  381. {
  382. if(NULL == argv[option_index])
  383. {
  384. option_index = option_index + 1;
  385. }
  386. else if(match(argv[option_index], "-h") || match(argv[option_index], "--help"))
  387. {
  388. fputs("Usage: ", stderr);
  389. fputs(argv[0], stderr);
  390. fputs(" --file FILENAME1 {--file FILENAME2} --output FILENAME\n", stderr);
  391. exit(EXIT_SUCCESS);
  392. }
  393. else if(match(argv[option_index], "--64"))
  394. {
  395. BITSIZE = 64;
  396. option_index = option_index + 1;
  397. }
  398. else if(match(argv[option_index], "-f") || match(argv[option_index], "--file"))
  399. {
  400. temp = calloc(1, sizeof(struct entry));
  401. temp->name = argv[option_index + 1];
  402. temp->next = input;
  403. input = temp;
  404. option_index = option_index + 2;
  405. }
  406. else if(match(argv[option_index], "-o") || match(argv[option_index], "--output"))
  407. {
  408. output_file = argv[option_index + 1];
  409. output = fopen(output_file, "w");
  410. if(NULL == output)
  411. {
  412. fputs("The file: ", stderr);
  413. fputs(input->name, stderr);
  414. fputs(" can not be opened!\n", stderr);
  415. exit(EXIT_FAILURE);
  416. }
  417. option_index = option_index + 2;
  418. }
  419. else if(match(argv[option_index], "-b") || match(argv[option_index], "--binary"))
  420. {
  421. ByteMode = BINARY;
  422. option_index = option_index + 1;
  423. }
  424. else if(match(argv[option_index], "-O") || match(argv[option_index], "--octal"))
  425. {
  426. ByteMode = OCTAL;
  427. option_index = option_index + 1;
  428. }
  429. else if(match(argv[option_index], "-X") || match(argv[option_index], "--hex"))
  430. {
  431. ByteMode = HEX;
  432. option_index = option_index + 1;
  433. }
  434. else if(match(argv[option_index], "--big-endian"))
  435. {
  436. BigEndian = TRUE;
  437. set = TRUE;
  438. option_index = option_index + 1;
  439. }
  440. else if(match(argv[option_index], "--little-endian"))
  441. {
  442. BigEndian = FALSE;
  443. set = TRUE;
  444. option_index = option_index + 1;
  445. }
  446. else if(match(argv[option_index], "-V") || match(argv[option_index], "--version"))
  447. {
  448. fputs("blood-elf 2.0.1\n(Basically Launches Odd Object Dump ExecutabLe Files\n", stdout);
  449. exit(EXIT_SUCCESS);
  450. }
  451. else if(match(argv[option_index], "--entry"))
  452. {
  453. head = calloc(1, sizeof(struct entry));
  454. /* Include _start or any other entry from your .hex2 */
  455. head->next = jump_table;
  456. jump_table = head;
  457. jump_table->name = argv[option_index + 1];
  458. /* However only the last one will be exempt from the _name hidden rule */
  459. entry = argv[option_index + 1];
  460. option_index = option_index + 2;
  461. count = count + 1;
  462. }
  463. else
  464. {
  465. fputs("Unknown option\n", stderr);
  466. exit(EXIT_FAILURE);
  467. }
  468. }
  469. /* Make sure we have a program tape to run */
  470. if (NULL == input)
  471. {
  472. return EXIT_FAILURE;
  473. }
  474. /* Force setting of endianness */
  475. if(!set)
  476. {
  477. fputs("either --little-endian or --big-endian MUST be set\n", stderr);
  478. return EXIT_FAILURE;
  479. }
  480. /* Setup the ugly formating because RISC-V sucks */
  481. setup_strings(ByteMode);
  482. /* Get all of the labels */
  483. first_pass(input);
  484. /* Reverse their order */
  485. jump_table = reverse_list(jump_table);
  486. /* Create sections */
  487. /* Create string names for sections */
  488. fputs("# Generated sections\n:ELF_shstr\n", output);
  489. fputs(zero_8, output);
  490. fputs("\t# NULL\n", output);
  491. fputs(":ELF_shstr__text\n\".text\"\n", output);
  492. fputs(":ELF_shstr__shstr\n\".shstrtab\"\n", output);
  493. fputs(":ELF_shstr__sym\n\".symtab\"\n", output);
  494. fputs(":ELF_shstr__str\n\".strtab\"\n", output);
  495. /* Create NULL section header as is required by the Spec. So dumb and waste of bytes*/
  496. write_section(":ELF_section_headers", zero_32, zero_32, zero_32, zero_32, zero_32, zero_32, zero_32, zero_32, zero_32);
  497. write_section(":ELF_section_header_text", "%ELF_shstr__text>ELF_shstr", one_32, six_32, "&ELF_text", "%ELF_text>ELF_base", "%ELF_data>ELF_text", zero_32, zero_32, zero_32);
  498. write_section(":ELF_section_header_shstr", "%ELF_shstr__shstr>ELF_shstr", three_32, zero_32, "&ELF_shstr", "%ELF_shstr>ELF_base", "%ELF_section_headers>ELF_shstr", zero_32, zero_32, zero_32);
  499. write_section(":ELF_section_header_str", "%ELF_shstr__str>ELF_shstr", three_32, zero_32, "&ELF_str", "%ELF_str>ELF_base", "%ELF_sym>ELF_str", zero_32, zero_32, zero_32);
  500. if(64 == BITSIZE) write_section(":ELF_section_header_sym", "%ELF_shstr__sym>ELF_shstr", two_32, zero_32, "&ELF_sym", "%ELF_sym>ELF_base", "%ELF_end>ELF_sym", three_32, setup_string(count, 4, ByteMode), twentyfour_32);
  501. else write_section(":ELF_section_header_sym", "%ELF_shstr__sym>ELF_shstr", two_32, zero_32, "&ELF_sym", "%ELF_sym>ELF_base", "%ELF_end>ELF_sym", three_32, setup_string(count, 4, ByteMode), sixteen_32);
  502. /* Create dwarf stubs needed for objdump -d to get function names */
  503. output_string_table(jump_table);
  504. output_symbol_table(jump_table);
  505. fputs("\n:ELF_end\n", output);
  506. /* Close output file */
  507. fclose(output);
  508. return EXIT_SUCCESS;
  509. }