123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882 |
- /* -*- c-file-style: "linux";indent-tabs-mode:t -*- */
- /* Copyright (C) 2016 Jeremiah Orians
- * Copyright (C) 2017 Jan Nieuwenhuizen <janneke@gnu.org>
- * This file is part of mescc-tools.
- *
- * mescc-tools is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * mescc-tools is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with mescc-tools. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- //CONSTANT max_string 4096
- #define max_string 4096
- //CONSTANT PROCESSED 1
- #define PROCESSED 1
- //CONSTANT STR 2
- #define STR 2
- //CONSTANT NEWLINE 3
- #define NEWLINE 3
- //CONSTANT TRUE 1
- #define TRUE 1
- //CONSTANT FALSE 0
- #define FALSE 0
- // CONSTANT KNIGHT 0
- #define KNIGHT 0
- // CONSTANT X86 1
- #define X86 1
- // CONSTANT AMD64 2
- #define AMD64 2
- // CONSTANT ARMV7L 40
- #define ARMV7L 40
- // CONSTANT AARM64 80
- #define AARM64 80
- // CONSTANT HEX 16
- #define HEX 16
- // CONSTANT OCTAL 8
- #define OCTAL 8
- // CONSTANT BINARY 2
- #define BINARY 2
- /* Imported functions */
- char* numerate_number(int a);
- int hex2char(int c);
- int in_set(int c, char* s);
- int match(char* a, char* b);
- int numerate_string(char *a);
- int string_length(char* a);
- void file_print(char* s, FILE* f);
- void require(int bool, char* error);
- struct blob
- {
- struct blob* next;
- int type;
- char* Text;
- char* Expression;
- struct blob* hash_next;
- };
- struct Token
- {
- struct Token* next;
- struct blob* contents;
- char* filename;
- int linenumber;
- };
- /* Globals */
- FILE* source_file;
- FILE* destination_file;
- int BigEndian;
- int BigBitEndian;
- int ByteMode;
- int Architecture;
- int linenumber;
- struct Token* token_list;
- struct blob* blob_list;
- struct blob* define_blob;
- struct blob* newline_blob;
- int blob_count;
- char* SCRATCH;
- struct blob** hash_table;
- void line_error(char* filename, int linenumber)
- {
- file_print(filename, stderr);
- file_print(":", stderr);
- file_print(numerate_number(linenumber), stderr);
- file_print(" :", stderr);
- }
- void ClearScratch()
- {
- int i = 0;
- int c = SCRATCH[i];
- while(0 != c)
- {
- SCRATCH[i] = 0;
- i = i + 1;
- c = SCRATCH[i];
- }
- }
- int GetHash(char* s)
- {
- int i = 5381;
- while(0 != s[0])
- {
- i = (i << 5) + i + s[0];
- s = s + 1;
- }
- return i & 0xFFFF;
- }
- struct blob* FindBlob()
- {
- int hash = GetHash(SCRATCH);
- struct blob* i = hash_table[hash];
- while(NULL != i)
- {
- if(match(SCRATCH, i->Text)) return i;
- i = i->hash_next;
- }
- return NULL;
- }
- void AddHash(struct blob* a, char* s)
- {
- int i = GetHash(s);
- a->hash_next = hash_table[i];
- hash_table[i] = a;
- }
- void NewBlob(int size)
- {
- blob_count = blob_count + 1;
- struct blob* a = calloc(1, sizeof(struct blob));
- require(NULL != a, "Exhusted available memory\n");
- a->Text = calloc(size + 1, sizeof(char));
- require(NULL != a->Text, "Exhusted available memory\n");
- int i = 0;
- while(i <= size)
- {
- a->Text[i] = SCRATCH[i];
- i = i + 1;
- }
- a->next = blob_list;
- blob_list = a;
- AddHash(a, SCRATCH);
- }
- struct Token* newToken(char* filename, int linenumber)
- {
- struct Token* p;
- p = calloc (1, sizeof (struct Token));
- require(NULL != p, "Exhusted available memory\n");
- p->filename = filename;
- p->linenumber = linenumber;
- return p;
- }
- struct Token* reverse_list(struct Token* head)
- {
- struct Token* root = NULL;
- struct Token* next;
- while(NULL != head)
- {
- next = head->next;
- head->next = root;
- root = head;
- head = next;
- }
- return root;
- }
- void purge_lineComment()
- {
- int c = fgetc(source_file);
- while(!in_set(c, "\n\r"))
- {
- if(EOF == c) break;
- c = fgetc(source_file);
- }
- }
- struct Token* append_newline(struct Token* head, char* filename)
- {
- linenumber = linenumber + 1;
- if(NULL == head) return NULL;
- if(NEWLINE == head->contents->type)
- {/* Don't waste whitespace*/
- return head;
- }
- struct Token* lf = newToken(filename, linenumber);
- lf->contents = newline_blob;
- lf->next = head;
- return lf;
- }
- struct Token* store_atom(struct Token* head, char c, char* filename)
- {
- ClearScratch();
- int ch = c;
- int i = 0;
- do
- {
- SCRATCH[i] = ch;
- ch = fgetc(source_file);
- i = i + 1;
- require(i < max_string, "storing atom of size larger than max_string\n");
- if(EOF == ch) break;
- } while (!in_set(ch, "\t\n "));
- head->contents = FindBlob();
- if(NULL == head->contents)
- {
- NewBlob(i);
- head->contents = blob_list;
- }
- if('\n' == ch)
- {
- return append_newline(head, filename);
- }
- return head;
- }
- struct blob* store_string(char c, char* filename)
- {
- ClearScratch();
- int ch = c;
- int i = 0;
- do
- {
- SCRATCH[i] = ch;
- i = i + 1;
- if('\n' == ch) linenumber = linenumber + 1;
- ch = fgetc(source_file);
- require(EOF != ch, "Unmatched \"!\n");
- if(max_string == i)
- {
- line_error(filename, linenumber);
- file_print("String: ", stderr);
- file_print(SCRATCH, stderr);
- file_print(" exceeds max string size\n", stderr);
- exit(EXIT_FAILURE);
- }
- } while(ch != c);
- struct blob* a = FindBlob();
- if(NULL == a)
- {
- NewBlob(i);
- a = blob_list;
- a->type = STR;
- }
- return a;
- }
- struct Token* Tokenize_Line(struct Token* head, char* filename)
- {
- int c;
- struct Token* p;
- linenumber = 1;
- do
- {
- restart:
- c = fgetc(source_file);
- if(in_set(c, ";#"))
- {
- purge_lineComment();
- head = append_newline(head, filename);
- goto restart;
- }
- if(in_set(c, "\t "))
- {
- goto restart;
- }
- if('\n' == c)
- {
- head = append_newline(head, filename);
- goto restart;
- }
- if(EOF == c)
- {
- head = append_newline(head, filename);
- goto done;
- }
- p = newToken(filename, linenumber);
- p->next = head;
- if(in_set(c, "'\""))
- {
- p->contents = store_string(c, filename);
- }
- else
- {
- p = store_atom(p, c, filename);
- }
- head = p;
- } while(TRUE);
- done:
- return head;
- }
- void line_macro(struct Token* p)
- {
- struct Token* i;
- for(i = p; NULL != i; i = i->next)
- {
- if(define_blob == i->contents)
- {
- require(NULL != i->next, "Macro name must exist\n");
- require(NULL != i->next->next, "Macro value must exist\n");
- if(PROCESSED == i->next->contents->type)
- {
- line_error(i->filename, i->linenumber);
- file_print("Multiple definitions for macro ", stderr);
- file_print(i->next->contents->Text, stderr);
- file_print("\n", stderr);
- exit(EXIT_FAILURE);
- }
- i->contents = newline_blob;
- if (STR == i->next->next->contents->type)
- {
- i->contents->Expression = i->next->next->contents->Text + 1;
- }
- else
- {
- i->next->contents->Expression = i->next->next->contents->Text;
- }
- i->next = i->next->next->next;
- }
- }
- }
- void hexify_string(struct blob* p)
- {
- char* table = "0123456789ABCDEF";
- int i = string_length(p->Text);
- int size;
- if(HEX == ByteMode) size = (((i << 1) + i) + 12);
- else if(OCTAL == ByteMode) size = (i << 2) + 1;
- else if(BINARY == ByteMode) size = (i << 3) + i + 1;
- else size = 1;
- require(1 != size, "hexify_string lacked a valid bytemode\n");
- char* d = calloc(size, sizeof(char));
- require(NULL != d, "Exhusted available memory\n");
- p->Expression = d;
- char* S = p->Text;
- if((KNIGHT == Architecture) && (HEX == ByteMode))
- {
- i = (((((i - 1) >> 2) + 1) << 3) + i);
- while( 0 < i)
- {
- i = i - 1;
- d[i] = '0';
- }
- }
- if(HEX == ByteMode)
- {
- while(0 != S[0])
- {
- S = S + 1;
- d[0] = table[S[0] >> 4];
- d[1] = table[S[0] & 0xF];
- d[2] = ' ';
- d = d + 3;
- }
- }
- else if(OCTAL == ByteMode)
- {
- while(0 != S[0])
- {
- S = S + 1;
- d[0] = table[S[0] >> 6];
- d[1] = table[(S[0] >> 3) & 0x7];
- d[2] = table[S[0] & 0x7];
- d[3] = ' ';
- d = d + 4;
- }
- }
- else if(BINARY == ByteMode)
- {
- while(0 != S[0])
- {
- S = S + 1;
- d[0] = table[S[0] >> 7];
- d[1] = table[(S[0] >> 6) & 0x1];
- d[2] = table[(S[0] >> 5) & 0x1];
- d[3] = table[(S[0] >> 4) & 0x1];
- d[4] = table[(S[0] >> 3) & 0x1];
- d[5] = table[(S[0] >> 2) & 0x1];
- d[6] = table[(S[0] >> 1) & 0x1];
- d[7] = table[S[0] & 0x1];
- d[8] = ' ';
- d = d + 9;
- }
- }
- }
- void process_string(struct blob* p)
- {
- struct blob* i;
- for(i = p; NULL != i; i = i->next)
- {
- if(STR == i->type)
- {
- if('\'' == i->Text[0])
- {
- i->Expression = i->Text + 1;
- }
- else if('"' == i->Text[0])
- {
- hexify_string(i);
- }
- }
- }
- }
- char* pad_nulls(int size, char* nil)
- {
- if(0 == size) return nil;
- require(size > 0, "negative null padding not possible\n");
- if(HEX == ByteMode) size = size * 2;
- else if (OCTAL == ByteMode) size = size * 3;
- else if (BINARY == ByteMode) size = size * 8;
- char* s = calloc(size + 1, sizeof(char));
- require(NULL != s, "Exhusted available memory\n");
- int i = 0;
- while(i < size)
- {
- s[i] = '0';
- i = i + 1;
- }
- return s;
- }
- void preserve_other(struct blob* p)
- {
- struct blob* i;
- char c;
- for(i = p; NULL != i; i = i->next)
- {
- if((NULL == i->Expression) && !(i->type & PROCESSED))
- {
- c = i->Text[0];
- if(in_set(c, "!@$~%&:^"))
- {
- i->Expression = i->Text;
- }
- else if('<' == c)
- {
- i->Expression = pad_nulls(numerate_string(i->Text + 1), i->Text);
- }
- }
- }
- }
- void bound_values(int displacement, int number_of_bytes, int low, int high)
- {
- if((high < displacement) || (displacement < low))
- {
- file_print("A displacement of ", stderr);
- file_print(numerate_number(displacement), stderr);
- file_print(" does not fit in ", stderr);
- file_print(numerate_number(number_of_bytes), stderr);
- file_print(" bytes\n", stderr);
- exit(EXIT_FAILURE);
- }
- }
- void range_check(int displacement, int number_of_bytes)
- {
- if(4 == number_of_bytes) return;
- else if(3 == number_of_bytes)
- {
- bound_values(displacement, number_of_bytes, -8388608, 16777216);
- return;
- }
- else if(2 == number_of_bytes)
- {
- bound_values(displacement, number_of_bytes, -32768, 65535);
- return;
- }
- else if(1 == number_of_bytes)
- {
- bound_values(displacement, number_of_bytes, -128, 255);
- return;
- }
- file_print("Received an invalid number of bytes in range_check\n", stderr);
- exit(EXIT_FAILURE);
- }
- void reverseBitOrder(char* c)
- {
- if(NULL == c) return;
- if(0 == c[1]) return;
- int hold = c[0];
- if(HEX == ByteMode)
- {
- c[0] = c[1];
- c[1] = hold;
- reverseBitOrder(c+2);
- }
- else if(OCTAL == ByteMode)
- {
- c[0] = c[2];
- c[2] = hold;
- reverseBitOrder(c+3);
- }
- else if(BINARY == ByteMode)
- {
- c[0] = c[7];
- c[7] = hold;
- hold = c[1];
- c[1] = c[6];
- c[6] = hold;
- hold = c[2];
- c[2] = c[5];
- c[5] = hold;
- hold = c[3];
- c[3] = c[4];
- c[4] = hold;
- reverseBitOrder(c+8);
- }
- }
- void LittleEndian(char* start)
- {
- char* end = start;
- char* c = start;
- while(0 != end[0]) end = end + 1;
- int hold;
- for(end = end - 1; start < end; start = start + 1)
- {
- hold = start[0];
- start[0] = end[0];
- end[0] = hold;
- end = end - 1;
- }
- if(BigBitEndian) reverseBitOrder(c);
- }
- int stringify(char* s, int digits, int divisor, int value, int shift)
- {
- int i = value;
- if(digits > 1)
- {
- i = stringify(s+1, (digits - 1), divisor, value, shift);
- }
- s[0] = hex2char(i & (divisor - 1));
- return (i >> shift);
- }
- char* express_number(int value, char c)
- {
- char* ch = calloc(42, sizeof(char));
- require(NULL != ch, "Exhusted available memory\n");
- int size;
- int number_of_bytes;
- int shift;
- if('!' == c)
- {
- number_of_bytes = 1;
- value = value & 0xFF;
- }
- else if('@' == c)
- {
- number_of_bytes = 2;
- value = value & 0xFFFF;
- }
- else if('~' == c)
- {
- number_of_bytes = 3;
- value = value & 0xFFFFFF;
- }
- else if('%' == c)
- {
- number_of_bytes = 4;
- value = value & 0xFFFFFFFF;
- }
- else
- {
- file_print("Given symbol ", stderr);
- fputc(c, stderr);
- file_print(" to express immediate value ", stderr);
- file_print(numerate_number(value), stderr);
- fputc('\n', stderr);
- exit(EXIT_FAILURE);
- }
- range_check(value, number_of_bytes);
- if(HEX == ByteMode)
- {
- size = number_of_bytes * 2;
- shift = 4;
- }
- else if(OCTAL == ByteMode)
- {
- size = number_of_bytes * 3;
- shift = 3;
- }
- else if(BINARY == ByteMode)
- {
- size = number_of_bytes * 8;
- shift = 1;
- }
- else
- {
- file_print("Got invalid ByteMode in express_number\n", stderr);
- exit(EXIT_FAILURE);
- }
- stringify(ch, size, ByteMode, value, shift);
- if(!BigEndian) LittleEndian(ch);
- else if(!BigBitEndian) reverseBitOrder(ch);
- return ch;
- }
- void eval_immediates(struct blob* p)
- {
- struct blob* i;
- int value;
- for(i = p; NULL != i; i = i->next)
- {
- if(PROCESSED == i->type) continue;
- else if(NEWLINE == i->type) continue;
- else if('<' == i->Text[0]) continue;
- else if(NULL == i->Expression)
- {
- if((X86 == Architecture) || (AMD64 == Architecture) || (ARMV7L == Architecture) || (AARM64 == Architecture))
- {
- if(in_set(i->Text[0], "%~@!"))
- {
- value = numerate_string(i->Text + 1);
- if(('0' == i->Text[1]) || (0 != value))
- {
- i->Expression = express_number(value, i->Text[0]);
- }
- }
- }
- else if(KNIGHT == Architecture)
- {
- value = numerate_string(i->Text);
- if(('0' == i->Text[0]) || (0 != value))
- {
- i->Expression = express_number(value, '@');
- }
- }
- else
- {
- file_print("Unknown architecture received in eval_immediates\n", stderr);
- exit(EXIT_FAILURE);
- }
- }
- }
- }
- void print_hex(struct Token* p)
- {
- struct Token* i;
- for(i = p; NULL != i; i = i->next)
- {
- if(NEWLINE == i->contents->type)
- {
- if(NULL == i->next) fputc('\n', destination_file);
- else if(NEWLINE != i->next->contents->type) fputc('\n', destination_file);
- }
- else if(NULL != i->contents->Expression)
- {
- file_print(i->contents->Expression, destination_file);
- if(NEWLINE != i->next->contents->type) fputc(' ', destination_file);
- }
- else
- {
- line_error(i->filename, i->linenumber);
- file_print("Received invalid other; ", stderr);
- file_print(i->contents->Text, stderr);
- file_print("\n", stderr);
- exit(EXIT_FAILURE);
- }
- }
- }
- /* Standard C main program */
- int main(int argc, char **argv)
- {
- BigEndian = TRUE;
- Architecture = KNIGHT;
- destination_file = stdout;
- BigBitEndian = TRUE;
- ByteMode = HEX;
- char* filename;
- char* arch;
- blob_count = 2;
- hash_table = calloc(65537, sizeof(struct blob*));
- /* Create newline blob */
- newline_blob = calloc(1, sizeof(struct blob));
- newline_blob->Text = "\n";
- newline_blob->Expression = "\n";
- newline_blob->type = NEWLINE;
- AddHash(newline_blob, "\n");
- /* Start the blob list with DEFINE and newline */
- blob_list = calloc(1, sizeof(struct blob));
- blob_list->Text = "DEFINE";
- define_blob = blob_list;
- blob_list->next = newline_blob;
- AddHash(define_blob, "DEFINE");
- /* Initialize scratch */
- SCRATCH = calloc(max_string + 1, sizeof(char));
- int option_index = 1;
- while(option_index <= argc)
- {
- if(NULL == argv[option_index])
- {
- option_index = option_index + 1;
- }
- else if(match(argv[option_index], "--BigEndian") || match(argv[option_index], "--big-endian"))
- {
- BigEndian = TRUE;
- option_index = option_index + 1;
- }
- else if(match(argv[option_index], "--LittleEndian") || match(argv[option_index], "--little-endian"))
- {
- BigEndian = FALSE;
- option_index = option_index + 1;
- }
- else if(match(argv[option_index], "-A") || match(argv[option_index], "--architecture"))
- {
- arch = argv[option_index + 1];
- if(match("knight-native", arch) || match("knight-posix", arch)) Architecture = KNIGHT;
- else if(match("x86", arch)) Architecture = X86;
- else if(match("amd64", arch)) Architecture = AMD64;
- else if(match("armv7l", arch)) Architecture = ARMV7L;
- else if(match("aarch64", arch)) Architecture = AARM64;
- else
- {
- file_print("Unknown architecture: ", stderr);
- file_print(arch, stderr);
- file_print(" know values are: knight-native, knight-posix, x86, amd64, armv7l and aarch64", stderr);
- exit(EXIT_FAILURE);
- }
- option_index = option_index + 2;
- }
- else if(match(argv[option_index], "-b") || match(argv[option_index], "--binary"))
- {
- ByteMode = BINARY;
- option_index = option_index + 1;
- }
- else if(match(argv[option_index], "-h") || match(argv[option_index], "--help"))
- {
- file_print("Usage: ", stderr);
- file_print(argv[0], stderr);
- file_print(" --file FILENAME1 {-f FILENAME2} (--big-endian|--little-endian) ", stderr);
- file_print("[--architecture name]\nArchitectures: knight-native, knight-posix, x86, amd64 and armv7\n", stderr);
- file_print("To leverage octal or binary output: --octal, --binary\n", stderr);
- exit(EXIT_SUCCESS);
- }
- else if(match(argv[option_index], "-f") || match(argv[option_index], "--file"))
- {
- filename = argv[option_index + 1];
- source_file = fopen(filename, "r");
- if(NULL == source_file)
- {
- file_print("The file: ", stderr);
- file_print(argv[option_index + 1], stderr);
- file_print(" can not be opened!\n", stderr);
- exit(EXIT_FAILURE);
- }
- token_list = Tokenize_Line(token_list, filename);
- fclose(source_file);
- option_index = option_index + 2;
- }
- else if(match(argv[option_index], "-o") || match(argv[option_index], "--output"))
- {
- destination_file = fopen(argv[option_index + 1], "w");
- if(NULL == destination_file)
- {
- file_print("The file: ", stderr);
- file_print(argv[option_index + 1], stderr);
- file_print(" can not be opened!\n", stderr);
- exit(EXIT_FAILURE);
- }
- option_index = option_index + 2;
- }
- else if(match(argv[option_index], "-O") || match(argv[option_index], "--octal"))
- {
- ByteMode = OCTAL;
- option_index = option_index + 1;
- }
- else if(match(argv[option_index], "-V") || match(argv[option_index], "--version"))
- {
- file_print("M1 1.0.0\n", stdout);
- exit(EXIT_SUCCESS);
- }
- else
- {
- file_print("Unknown option\n", stderr);
- exit(EXIT_FAILURE);
- }
- }
- if(NULL == token_list)
- {
- file_print("Either no input files were given or they were empty\n", stderr);
- exit(EXIT_FAILURE);
- }
- token_list = reverse_list(token_list);
- line_macro(token_list);
- process_string(blob_list);
- eval_immediates(blob_list);
- preserve_other(blob_list);
- print_hex(token_list);
- if (destination_file != stdout)
- {
- fclose(destination_file);
- }
- return EXIT_SUCCESS;
- }
|