hex2_linker.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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. #define max_string 4096
  25. //CONSTANT max_string 4096
  26. #define TRUE 1
  27. //CONSTANT TRUE 1
  28. #define FALSE 0
  29. //CONSTANT FALSE 0
  30. // CONSTANT KNIGHT 0
  31. #define KNIGHT 0
  32. // CONSTANT X86 1
  33. #define X86 1
  34. // CONSTANT AMD64 2
  35. #define AMD64 2
  36. // CONSTANT ARMV7L 40
  37. #define ARMV7L 40
  38. // CONSTANT AARM64 80
  39. #define AARM64 80
  40. void file_print(char* s, FILE* f);
  41. int match(char* a, char* b);
  42. char* numerate_number(int a);
  43. int numerate_string(char *a);
  44. int in_set(int c, char* s);
  45. struct input_files
  46. {
  47. struct input_files* next;
  48. char* filename;
  49. };
  50. struct entry
  51. {
  52. struct entry* next;
  53. unsigned target;
  54. char* name;
  55. };
  56. FILE* output;
  57. struct entry* jump_table;
  58. int BigEndian;
  59. int Base_Address;
  60. int Architecture;
  61. int ByteMode;
  62. int exec_enable;
  63. int ip;
  64. char* scratch;
  65. char* filename;
  66. int linenumber;
  67. int ALIGNED;
  68. void line_error()
  69. {
  70. file_print(filename, stderr);
  71. file_print(":", stderr);
  72. file_print(numerate_number(linenumber), stderr);
  73. file_print(" :", stderr);
  74. }
  75. int consume_token(FILE* source_file)
  76. {
  77. int i = 0;
  78. int c = fgetc(source_file);
  79. while(!in_set(c, " \t\n>"))
  80. {
  81. scratch[i] = c;
  82. i = i + 1;
  83. c = fgetc(source_file);
  84. }
  85. return c;
  86. }
  87. int Throwaway_token(FILE* source_file)
  88. {
  89. int c;
  90. do
  91. {
  92. c = fgetc(source_file);
  93. } while(!in_set(c, " \t\n>"));
  94. return c;
  95. }
  96. int length(char* s)
  97. {
  98. int i = 0;
  99. while(0 != s[i]) i = i + 1;
  100. return i;
  101. }
  102. void Clear_Scratch(char* s)
  103. {
  104. do
  105. {
  106. s[0] = 0;
  107. s = s + 1;
  108. } while(0 != s[0]);
  109. }
  110. void Copy_String(char* a, char* b)
  111. {
  112. while(0 != a[0])
  113. {
  114. b[0] = a[0];
  115. a = a + 1;
  116. b = b + 1;
  117. }
  118. }
  119. unsigned GetTarget(char* c)
  120. {
  121. struct entry* i;
  122. for(i = jump_table; NULL != i; i = i->next)
  123. {
  124. if(match(c, i->name))
  125. {
  126. return i->target;
  127. }
  128. }
  129. file_print("Target label ", stderr);
  130. file_print(c, stderr);
  131. file_print(" is not valid\n", stderr);
  132. exit(EXIT_FAILURE);
  133. }
  134. int storeLabel(FILE* source_file, int ip)
  135. {
  136. struct entry* entry = calloc(1, sizeof(struct entry));
  137. /* Ensure we have target address */
  138. entry->target = ip;
  139. /* Prepend to list */
  140. entry->next = jump_table;
  141. jump_table = entry;
  142. /* Store string */
  143. int c = consume_token(source_file);
  144. entry->name = calloc(length(scratch) + 1, sizeof(char));
  145. Copy_String(scratch, entry->name);
  146. Clear_Scratch(scratch);
  147. return c;
  148. }
  149. void range_check(int displacement, int number_of_bytes)
  150. {
  151. if(4 == number_of_bytes) return;
  152. else if (3 == number_of_bytes)
  153. {
  154. if((8388607 < displacement) || (displacement < -8388608))
  155. {
  156. file_print("A displacement of ", stderr);
  157. file_print(numerate_number(displacement), stderr);
  158. file_print(" does not fit in 3 bytes\n", stderr);
  159. exit(EXIT_FAILURE);
  160. }
  161. return;
  162. }
  163. else if (2 == number_of_bytes)
  164. {
  165. if((32767 < displacement) || (displacement < -32768))
  166. {
  167. file_print("A displacement of ", stderr);
  168. file_print(numerate_number(displacement), stderr);
  169. file_print(" does not fit in 2 bytes\n", stderr);
  170. exit(EXIT_FAILURE);
  171. }
  172. return;
  173. }
  174. else if (1 == number_of_bytes)
  175. {
  176. if((127 < displacement) || (displacement < -128))
  177. {
  178. file_print("A displacement of ", stderr);
  179. file_print(numerate_number(displacement), stderr);
  180. file_print(" does not fit in 1 byte\n", stderr);
  181. exit(EXIT_FAILURE);
  182. }
  183. return;
  184. }
  185. file_print("Invalid number of bytes given\n", stderr);
  186. exit(EXIT_FAILURE);
  187. }
  188. void outputPointer(int displacement, int number_of_bytes)
  189. {
  190. unsigned value = displacement;
  191. /* HALT HARD if we are going to do something BAD*/
  192. range_check(displacement, number_of_bytes);
  193. if(BigEndian)
  194. { /* Deal with BigEndian */
  195. if(4 == number_of_bytes) fputc((value >> 24), output);
  196. if(3 <= number_of_bytes) fputc(((value >> 16)%256), output);
  197. if(2 <= number_of_bytes) fputc(((value >> 8)%256), output);
  198. if(1 <= number_of_bytes) fputc((value % 256), output);
  199. }
  200. else
  201. { /* Deal with LittleEndian */
  202. while(number_of_bytes > 0)
  203. {
  204. unsigned byte = value % 256;
  205. value = value / 256;
  206. fputc(byte, output);
  207. number_of_bytes = number_of_bytes - 1;
  208. }
  209. }
  210. }
  211. int Architectural_displacement(int target, int base)
  212. {
  213. if(KNIGHT == Architecture) return (target - base);
  214. else if(X86 == Architecture) return (target - base);
  215. else if(AMD64 == Architecture) return (target - base);
  216. else if(ALIGNED && (ARMV7L == Architecture))
  217. {
  218. ALIGNED = FALSE;
  219. /* Note: Branch displacements on ARM are in number of instructions to skip, basically. */
  220. if (target & 3)
  221. {
  222. line_error();
  223. file_print("error: Unaligned branch target: ", stderr);
  224. file_print(scratch, stderr);
  225. file_print(", aborting\n", stderr);
  226. exit(EXIT_FAILURE);
  227. }
  228. /*
  229. * The "fetch" stage already moved forward by 8 from the
  230. * beginning of the instruction because it is already
  231. * prefetching the next instruction.
  232. * Compensate for it by subtracting the space for
  233. * two instructions (including the branch instruction).
  234. * and the size of the aligned immediate.
  235. */
  236. return (((target - base + (base & 3)) >> 2) - 2);
  237. }
  238. else if(ARMV7L == Architecture)
  239. {
  240. /*
  241. * The size of the offset is 8 according to the spec but that value is
  242. * based on the end of the immediate, which the documentation gets wrong
  243. * and needs to be adjusted to the size of the immediate.
  244. * Eg 1byte immediate => -8 + 1 = -7
  245. */
  246. return ((target - base) - 8 + (3 & base));
  247. }
  248. else if (AARM64 == Architecture)
  249. {
  250. return ((target - base) - 8 + (3 & base));
  251. }
  252. file_print("Unknown Architecture, aborting before harm is done\n", stderr);
  253. exit(EXIT_FAILURE);
  254. }
  255. void Update_Pointer(char ch)
  256. {
  257. /* Calculate pointer size*/
  258. if(in_set(ch, "%&")) ip = ip + 4; /* Deal with % and & */
  259. else if(in_set(ch, "@$")) ip = ip + 2; /* Deal with @ and $ */
  260. else if('~' == ch) ip = ip + 3; /* Deal with ~ */
  261. else if('!' == ch) ip = ip + 1; /* Deal with ! */
  262. else
  263. {
  264. line_error();
  265. file_print("storePointer given unknown\n", stderr);
  266. exit(EXIT_FAILURE);
  267. }
  268. }
  269. void storePointer(char ch, FILE* source_file)
  270. {
  271. /* Get string of pointer */
  272. Clear_Scratch(scratch);
  273. Update_Pointer(ch);
  274. int base_sep_p = consume_token(source_file);
  275. /* Lookup token */
  276. int target = GetTarget(scratch);
  277. int displacement;
  278. int base = ip;
  279. /* Change relative base address to :<base> */
  280. if ('>' == base_sep_p)
  281. {
  282. Clear_Scratch(scratch);
  283. consume_token (source_file);
  284. base = GetTarget (scratch);
  285. /* Force universality of behavior */
  286. displacement = (target - base);
  287. }
  288. else
  289. {
  290. displacement = Architectural_displacement(target, base);
  291. }
  292. /* output calculated difference */
  293. if('!' == ch) outputPointer(displacement, 1); /* Deal with ! */
  294. else if('$' == ch) outputPointer(target, 2); /* Deal with $ */
  295. else if('@' == ch) outputPointer(displacement, 2); /* Deal with @ */
  296. else if('~' == ch) outputPointer(displacement, 3); /* Deal with ~ */
  297. else if('&' == ch) outputPointer(target, 4); /* Deal with & */
  298. else if('%' == ch) outputPointer(displacement, 4); /* Deal with % */
  299. else
  300. {
  301. line_error();
  302. file_print("error: storePointer reached impossible case: ch=", stderr);
  303. fputc(ch, stderr);
  304. file_print("\n", stderr);
  305. exit(EXIT_FAILURE);
  306. }
  307. }
  308. void line_Comment(FILE* source_file)
  309. {
  310. int c = fgetc(source_file);
  311. while(!in_set(c, "\n\r"))
  312. {
  313. if(EOF == c) break;
  314. c = fgetc(source_file);
  315. }
  316. linenumber = linenumber + 1;
  317. }
  318. int hex(int c, FILE* source_file)
  319. {
  320. if (in_set(c, "0123456789")) return (c - 48);
  321. else if (in_set(c, "abcdef")) return (c - 87);
  322. else if (in_set(c, "ABCDEF")) return (c - 55);
  323. else if (in_set(c, "#;")) line_Comment(source_file);
  324. else if ('\n' == c) linenumber = linenumber + 1;
  325. return -1;
  326. }
  327. int octal(int c, FILE* source_file)
  328. {
  329. if (in_set(c, "01234567")) return (c - 48);
  330. else if (in_set(c, "#;")) line_Comment(source_file);
  331. else if ('\n' == c) linenumber = linenumber + 1;
  332. return -1;
  333. }
  334. int binary(int c, FILE* source_file)
  335. {
  336. if (in_set(c, "01")) return (c - 48);
  337. else if (in_set(c, "#;")) line_Comment(source_file);
  338. else if ('\n' == c) linenumber = linenumber + 1;
  339. return -1;
  340. }
  341. int hold;
  342. int toggle;
  343. void process_byte(char c, FILE* source_file, int write)
  344. {
  345. if(16 == ByteMode)
  346. {
  347. if(0 <= hex(c, source_file))
  348. {
  349. if(toggle)
  350. {
  351. if(write) fputc(((hold * 16)) + hex(c, source_file), output);
  352. ip = ip + 1;
  353. hold = 0;
  354. }
  355. else
  356. {
  357. hold = hex(c, source_file);
  358. }
  359. toggle = !toggle;
  360. }
  361. }
  362. else if(8 ==ByteMode)
  363. {
  364. if(0 <= octal(c, source_file))
  365. {
  366. if(2 == toggle)
  367. {
  368. if(write) fputc(((hold * 8)) + octal(c, source_file), output);
  369. ip = ip + 1;
  370. hold = 0;
  371. toggle = 0;
  372. }
  373. else if(1 == toggle)
  374. {
  375. hold = ((hold * 8) + octal(c, source_file));
  376. toggle = 2;
  377. }
  378. else
  379. {
  380. hold = octal(c, source_file);
  381. toggle = 1;
  382. }
  383. }
  384. }
  385. else if(2 == ByteMode)
  386. {
  387. if(0 <= binary(c, source_file))
  388. {
  389. if(7 == toggle)
  390. {
  391. if(write) fputc((hold * 2) + binary(c, source_file), output);
  392. ip = ip + 1;
  393. hold = 0;
  394. toggle = 0;
  395. }
  396. else
  397. {
  398. hold = ((hold * 2) + binary(c, source_file));
  399. toggle = toggle + 1;
  400. }
  401. }
  402. }
  403. }
  404. void pad_to_align(int write)
  405. {
  406. if((ARMV7L == Architecture) || (AARM64 == Architecture))
  407. {
  408. if(1 == (ip & 0x1))
  409. {
  410. ip = ip + 1;
  411. if(write) fputc('\0', output);
  412. }
  413. if(2 == (ip & 0x2))
  414. {
  415. ip = ip + 2;
  416. if(write)
  417. {
  418. fputc('\0', output);
  419. fputc('\0', output);
  420. }
  421. }
  422. }
  423. }
  424. void first_pass(struct input_files* input)
  425. {
  426. if(NULL == input) return;
  427. first_pass(input->next);
  428. filename = input->filename;
  429. linenumber = 1;
  430. FILE* source_file = fopen(filename, "r");
  431. if(NULL == source_file)
  432. {
  433. file_print("The file: ", stderr);
  434. file_print(input->filename, stderr);
  435. file_print(" can not be opened!\n", stderr);
  436. exit(EXIT_FAILURE);
  437. }
  438. toggle = FALSE;
  439. int c;
  440. for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
  441. {
  442. /* Check for and deal with label */
  443. if(':' == c)
  444. {
  445. c = storeLabel(source_file, ip);
  446. }
  447. /* check for and deal with relative/absolute pointers to labels */
  448. if(in_set(c, "!@$~%&"))
  449. { /* deal with 1byte pointer !; 2byte pointers (@ and $); 3byte pointers ~; 4byte pointers (% and &) */
  450. Update_Pointer(c);
  451. c = Throwaway_token(source_file);
  452. if ('>' == c)
  453. { /* deal with label>base */
  454. c = Throwaway_token(source_file);
  455. }
  456. }
  457. else if('<' == c)
  458. {
  459. pad_to_align(FALSE);
  460. }
  461. else if('^' == c)
  462. {
  463. /* Just ignore */
  464. continue;
  465. }
  466. else process_byte(c, source_file, FALSE);
  467. }
  468. fclose(source_file);
  469. }
  470. void second_pass(struct input_files* input)
  471. {
  472. if(NULL == input) return;
  473. second_pass(input->next);
  474. filename = input->filename;
  475. linenumber = 1;
  476. FILE* source_file = fopen(filename, "r");
  477. /* Something that should never happen */
  478. if(NULL == source_file)
  479. {
  480. file_print("The file: ", stderr);
  481. file_print(input->filename, stderr);
  482. file_print(" can not be opened!\nWTF-pass2\n", stderr);
  483. exit(EXIT_FAILURE);
  484. }
  485. toggle = FALSE;
  486. hold = 0;
  487. int c;
  488. for(c = fgetc(source_file); EOF != c; c = fgetc(source_file))
  489. {
  490. if(':' == c) c = Throwaway_token(source_file); /* Deal with : */
  491. else if(in_set(c, "!@$~%&")) storePointer(c, source_file); /* Deal with !, @, $, ~, % and & */
  492. else if('<' == c) pad_to_align(TRUE);
  493. else if('^' == c) ALIGNED = TRUE;
  494. else process_byte(c, source_file, TRUE);
  495. }
  496. fclose(source_file);
  497. }
  498. /* Standard C main program */
  499. int main(int argc, char **argv)
  500. {
  501. ALIGNED = FALSE;
  502. BigEndian = TRUE;
  503. jump_table = NULL;
  504. Architecture = KNIGHT;
  505. Base_Address = 0;
  506. struct input_files* input = NULL;
  507. output = stdout;
  508. char* output_file = "";
  509. exec_enable = FALSE;
  510. ByteMode = 16;
  511. scratch = calloc(max_string + 1, sizeof(char));
  512. char* arch;
  513. int option_index = 1;
  514. while(option_index <= argc)
  515. {
  516. if(NULL == argv[option_index])
  517. {
  518. option_index = option_index + 1;
  519. }
  520. else if(match(argv[option_index], "--BigEndian"))
  521. {
  522. BigEndian = TRUE;
  523. option_index = option_index + 1;
  524. }
  525. else if(match(argv[option_index], "--LittleEndian"))
  526. {
  527. BigEndian = FALSE;
  528. option_index = option_index + 1;
  529. }
  530. else if(match(argv[option_index], "--exec_enable"))
  531. {
  532. exec_enable = TRUE;
  533. option_index = option_index + 1;
  534. }
  535. else if(match(argv[option_index], "-A") || match(argv[option_index], "--architecture"))
  536. {
  537. arch = argv[option_index + 1];
  538. if(match("knight-native", arch) || match("knight-posix", arch)) Architecture = KNIGHT;
  539. else if(match("x86", arch)) Architecture = X86;
  540. else if(match("amd64", arch)) Architecture = AMD64;
  541. else if(match("armv7l", arch)) Architecture = ARMV7L;
  542. else if(match("aarch64", arch)) Architecture = AARM64;
  543. else
  544. {
  545. file_print("Unknown architecture: ", stderr);
  546. file_print(arch, stderr);
  547. file_print(" know values are: knight-native, knight-posix, x86, amd64 and armv7l", stderr);
  548. }
  549. option_index = option_index + 2;
  550. }
  551. else if(match(argv[option_index], "-b") || match(argv[option_index], "--binary"))
  552. {
  553. ByteMode = 2;
  554. option_index = option_index + 1;
  555. }
  556. else if(match(argv[option_index], "-B") || match(argv[option_index], "--BaseAddress"))
  557. {
  558. Base_Address = numerate_string(argv[option_index + 1]);
  559. option_index = option_index + 2;
  560. }
  561. else if(match(argv[option_index], "-h") || match(argv[option_index], "--help"))
  562. {
  563. file_print("Usage: ", stderr);
  564. file_print(argv[0], stderr);
  565. file_print(" -f FILENAME1 {-f FILENAME2} (--BigEndian|--LittleEndian)", stderr);
  566. file_print(" [--BaseAddress 12345] [--architecture name]\nArchitecture:", stderr);
  567. file_print(" knight-native, knight-posix, x86, amd64 and armv7\n", stderr);
  568. file_print("To leverage octal or binary input: --octal, --binary\n", stderr);
  569. exit(EXIT_SUCCESS);
  570. }
  571. else if(match(argv[option_index], "-f") || match(argv[option_index], "--file"))
  572. {
  573. struct input_files* temp = calloc(1, sizeof(struct input_files));
  574. temp->filename = argv[option_index + 1];
  575. temp->next = input;
  576. input = temp;
  577. option_index = option_index + 2;
  578. }
  579. else if(match(argv[option_index], "-o") || match(argv[option_index], "--output"))
  580. {
  581. output_file = argv[option_index + 1];
  582. output = fopen(output_file, "w");
  583. if(NULL == output)
  584. {
  585. file_print("The file: ", stderr);
  586. file_print(argv[option_index + 1], stderr);
  587. file_print(" can not be opened!\n", stderr);
  588. exit(EXIT_FAILURE);
  589. }
  590. option_index = option_index + 2;
  591. }
  592. else if(match(argv[option_index], "-O") || match(argv[option_index], "--octal"))
  593. {
  594. ByteMode = 8;
  595. option_index = option_index + 1;
  596. }
  597. else if(match(argv[option_index], "-V") || match(argv[option_index], "--version"))
  598. {
  599. file_print("hex2 0.6.0\n", stdout);
  600. exit(EXIT_SUCCESS);
  601. }
  602. else
  603. {
  604. file_print("Unknown option\n", stderr);
  605. exit(EXIT_FAILURE);
  606. }
  607. }
  608. /* Make sure we have a program tape to run */
  609. if (NULL == input)
  610. {
  611. return EXIT_FAILURE;
  612. }
  613. /* Get all of the labels */
  614. ip = Base_Address;
  615. first_pass(input);
  616. /* Fix all the references*/
  617. ip = Base_Address;
  618. second_pass(input);
  619. /* Set file as executable */
  620. if(exec_enable)
  621. {
  622. /* 488 = 750 in octal */
  623. if(0 != chmod(output_file, 488))
  624. {
  625. file_print("Unable to change permissions\n", stderr);
  626. exit(EXIT_FAILURE);
  627. }
  628. }
  629. return EXIT_SUCCESS;
  630. }