#include "asmdata.h" #include //#include //Just for debuging. TODO: Remove. static int32_t asmdata_strlen_(const char* str) { if (str == NULL) { return 0; } int32_t l = 0; while (str[l] != 0) { l++; } return l; } static const char* asmdata_strndup_(const char* str, int maxlen) { char* result = calloc(maxlen + 1, 1); if (result != NULL && str != NULL) { int32_t i; for (i = 0; i < maxlen; i++) { if (str[i] == 0) { return (const char*)result; } result[i] = str[i]; } } return (const char*)result; } char* asmdata_strdup_(const char* str) { /*if (str == NULL) { return NULL; }*/ return asmdata_strndup_(str, asmdata_strlen_(str)); } bool asmdata_streq_(const char* a, const char* b) { if (a == b) { return true; } int32_t la = asmdata_strlen_(a); int32_t lb = asmdata_strlen_(b); if (la != lb) { return false; } int32_t i; for (i = 0; i < la; i++) { if (a[i] != b[i]) { return false; } } return true; } int asmdata_atoll_val_(char a, int r) { switch (a) { case '0': return 0; case '1': return 1; case '2': return (r >= 2) ? 2 : -1; case '3': return (r >= 3) ? 3 : -1; case '4': return (r >= 4) ? 4 : -1; case '5': return (r >= 5) ? 5 : -1; case '6': return (r >= 6) ? 6 : -1; case '7': return (r >= 7) ? 7 : -1; case '8': return (r >= 8) ? 8 : -1; case '9': return (r >= 9) ? 9 : -1; case 'a': case 'A': return (r >= 0xA) ? 0xA : -1; case 'b': case 'B': return (r >= 0xB) ? 0xB : -1; case 'c': case 'C': return (r >= 0xC) ? 0xC : -1; case 'd': case 'D': return (r >= 0xD) ? 0xD : -1; case 'e': case 'E': return (r >= 0xE) ? 0xE : -1; case 'f': case 'F': return (r >= 0xF) ? 0xF : -1; default: return -1; } } long long asmdata_atoll_r_(const char* a, int r) { long long result = 0; int v = -1; while (*a != 0 && (v = asmdata_atoll_val_(*a, r)) >= 0) { result *= r; result += v; a++; } return result; } long long atoll(const char*a); long long asmdata_atoll_(const char* a) { if (a == NULL) { return 0; } if (a[0] == '0' && a[1] == 'x') { return asmdata_atoll_r_(a+2, 16); } else if (a[0] == '0' && a[1] == 'b') { return asmdata_atoll_r_(a+2, 2); } else { return atoll(a); } } asmdata_map_t* asmdata_map_new(int n, asmdata_iterf_t deletef) { asmdata_map_t* map = malloc(sizeof(asmdata_map_t)); if (map == NULL) { return NULL; } map->table = calloc(n, sizeof(void*)); if (map->table == NULL) { free(map); return NULL; } map->ntable = n; map->deletef = deletef; //TODO map->udata = 0; return map; } int asmdata_map_hash(char* key) { int i = 0; int h = 456123; while (key[i] != 0) { h = (h * 33) + key[i]; i++; } return h & 0x0FFFFFFF; } void asmdata_map_set(asmdata_map_t* map, char* key, void* value) { int hash = asmdata_map_hash(key); int idx = hash % map->ntable; asmdata_mapentry_t* e = map->table[idx]; while (e != NULL) { if (e->hash == hash && asmdata_streq_(key, e->key)) { asmdata_iterf_t deletef = map->deletef; if (deletef != NULL) { deletef(map, e->key, e->value); } e->key = key; e->value = value; return; } e = e->next; } // If not present, create a new one. e = malloc(sizeof(asmdata_mapentry_t)); if (e == NULL) { // TODO: Report fatal error. } e->hash = hash; e->key = key; e->value = value; e->next = map->table[idx]; map->table[idx] = e; } void* asmdata_map_get(asmdata_map_t* map, char* key) { int hash = asmdata_map_hash(key); asmdata_mapentry_t* e = map->table[hash % map->ntable]; while (e != NULL) { if (e->hash == hash && asmdata_streq_(key, e->key)) { return e->value; } e = e->next; } return NULL; } void asmdata_map_delete(asmdata_map_t* map) { asmdata_iterf_t deletef = map->deletef; int i; for (i = 0; i < map->ntable; i++) { asmdata_mapentry_t* e = map->table[i]; while (e != NULL) { //if (deletef != NULL) { // deletef(map, e->key, e->value); //} void* oldptr = e; e = e->next; free(e); } } free(map); } asmdata_section_t* asmdata_section_new(const char* name) { asmdata_section_t* result = calloc(1, sizeof(asmdata_section_t)); if (result != NULL) { result->namecopy = asmdata_strdup_(name); } return result; } bool asmdata_section_reserveextra(asmdata_section_t* section, int64_t nbytes, bool willfill) { int32_t granularity = 1024; // Resize the buffer about kilobyte or so at a time to prevent unnecessary realloc calls /* Firstly, the reserved total needs to be incremented whether filled or not. */ section->reservedsize += nbytes; /* If we're not filling it, we can just leave it on the reserved total (not necessarily any need to allocate/use extra memory!). */ if (!willfill) { return true; } /* Make sure it fits in 32 bits (so we don't have to worry whether size_t is 32- or 64- bits) and is below the maximum. */ if (((int64_t)((int32_t)(section->reservedsize))) != section->reservedsize || section->reservedsize > ASMDATA_MAXFILLED) { return false; } if (section->reservedsize > section->buffersize) { section->buffersize = (int32_t)(section->reservedsize); // Already checked that it can fit in 32 bits if filled while (section->buffersize % granularity != 0) { section->buffersize++; } if (section->buffer == NULL) { section->buffer = calloc(1, section->buffersize); } else { section->buffer = realloc(section->buffer, section->buffersize); } if (section->buffer == NULL) { return false; } } section->bufferfilled = (int32_t)(section->reservedsize); return true; } void* asmdata_section_delete(asmdata_section_t* section) { if (section != NULL) { if (section->namecopy != NULL) { free(section->namecopy); section->namecopy = NULL; } if (section->buffer != NULL) { free(section->buffer); section->buffer = NULL; section->bigendian = false; section->bufferfilled = 0; section->buffersize = 0; section->reservedsize = 0; section->virtualoffset = 0; } free(section); } return NULL; } asmdata_t* asmdata_new() { asmdata_t* result = calloc(1, sizeof(asmdata_t)); if (result != NULL) { result->extsyntax = true; result->sections = calloc(ASMDATA_MAXSECTIONS, sizeof(asmdata_section_t*)); if (!result->sections) { free(result); return NULL; } result->symbols = calloc(ASMDATA_MAXSYMBOLS, sizeof(asmdata_symbol_t)); if (!result->sections) { free(result->sections); free(result); return NULL; } result->references = calloc(ASMDATA_MAXREFERENCES, sizeof(asmdata_reference_t)); if (!result->sections) { free(result->sections); free(result->references); free(result); return NULL; } } return result; } void* asmdata_delete(asmdata_t* asmdata) { if (asmdata != NULL) { asmdata->activesection = NULL; int32_t i; for (i = 0; i < asmdata->nsections; i++) { asmdata->sections[i] = asmdata_section_delete(asmdata->sections[i]); } asmdata->nsections = 0; free(asmdata); } return NULL; } bool asmdata_finalise(asmdata_t* asmdata) { /* Finalisation will fail if there's any hint that the code has already been finalised (even if it was done manually by defining symbol * table sections in assembly code). */ if (asmdata->finalised || asmdata_hassection(asmdata, "asmdata.strings") || asmdata_hassection(asmdata, "asmdata.symbols") || asmdata_hassection(asmdata, "asmdata.references")) { return false; } /* The three linkage sections are created in "optimised" order: You generally need to have read the symbols section to make sense of the * references section, so symbols are written before references. Strings (and maybe later extra debug info) are written last because they * need not actually be read in many cases. */ if (asmdata_selectsection(asmdata, "asmdata.symbols") == NULL) { return false; } if (asmdata_selectsection(asmdata, "asmdata.references") == NULL) { return false; } if (asmdata_selectsection(asmdata, "asmdata.strings") == NULL) { return false; } /* The first string will be at offset 0 (which might also imply NULL), so we can start by adding a NULL string there. An interpreter * should generally handle NULL strings differently, but in case any are automatically read the result will be a marker: */ asmdata_selectsection(asmdata, "asmdata.strings"); const char* nullstr = ""; asmdata_appendbytes(asmdata, (uint8_t*)nullstr, asmdata_strlen_(nullstr) + 1); // Be sure to include the terminating zero byte! int32_t i; for (i = 0; i < asmdata->nsymbols; i++) { asmdata_section_t* str = asmdata_selectsection(asmdata, "asmdata.strings"); int64_t stroffset = str->reservedsize; int32_t strlen = asmdata_strlen_(asmdata->symbols[i].namecopy); asmdata_appendbytes(asmdata, (uint8_t*)(asmdata->symbols[i].namecopy), strlen + 1); // Make sure we include terminating zero. asmdata_section_t* sym = asmdata_selectsection(asmdata, "asmdata.symbols"); asmdata_appendword(asmdata, asmdata->symbols[i].flags, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->symbols[i].sectionindex, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->symbols[i].sectionoffset, ASMDATA_SIZE_64BIT); asmdata_appendword(asmdata, stroffset, ASMDATA_SIZE_64BIT); asmdata_appendword(asmdata, asmdata->symbols[i].x_lhs, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->symbols[i].x_op, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->symbols[i].x_rhs, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->symbols[i].reserved, ASMDATA_SIZE_32BIT); } asmdata_section_t* refs = asmdata_selectsection(asmdata, "asmdata.references"); for (i = 0; i < asmdata->nreferences; i++) { asmdata_appendword(asmdata, asmdata->references[i].baseflags, ASMDATA_SIZE_8BIT); asmdata_appendword(asmdata, asmdata->references[i].size, ASMDATA_SIZE_8BIT); asmdata_appendword(asmdata, asmdata->references[i].extflags, ASMDATA_SIZE_16BIT); asmdata_appendword(asmdata, asmdata->references[i].sectionindex, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->references[i].sectionoffset, ASMDATA_SIZE_64BIT); asmdata_appendword(asmdata, asmdata->references[i].symbolindex, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->references[i].extdata, ASMDATA_SIZE_32BIT); } asmdata->finalised = true; return true; } bool asmdata_produceheader(asmdata_t* asmdata, int32_t pagesize, const char* hint1, const char* hint2, int32_t inthint) { /* Exclude any unreasonably small/large page sizes, but allow weird/unaligned ones just in case. */ if (pagesize < 1 || pagesize >(1024 * 1024 * 1024)) { return false; } /* The header can only be produced once, otherwise it would get too confusing... */ if (asmdata_hassection(asmdata, "asmdata.fileheader")) { return false; } /* If the strings section hasn't already been initialised, we should do the same initialisation that would happen in * asmdata_finalise(), ensuring that the strings section is created before the file header. */ if (!asmdata_hassection(asmdata, "asmdata.strings")) { /* The first string will be at offset 0 (which might also imply NULL), so we can start by adding a NULL string there. An interpreter * should generally handle NULL strings differently, but in case any are automatically read the result will be a marker: */ if (asmdata_selectsection(asmdata, "asmdata.strings") == NULL) { return false; } const char* nullstr = ""; asmdata_appendbytes(asmdata, (uint8_t*)nullstr, asmdata_strlen_(nullstr) + 1); // Be sure to include the terminating zero byte! } int32_t nstrsection = asmdata_selectsection(asmdata, "asmdata.strings")->sectionnumber; /* Now we can start with the file header itself: */ if (asmdata_selectsection(asmdata, "asmdata.fileheader") == NULL) { return false; } int32_t nhdrsection = asmdata_selectsection(asmdata, "asmdata.fileheader")->sectionnumber; asmdata_appendbytes(asmdata, (uint8_t*)"ASMDATA1", 8); asmdata_appendword(asmdata, 1, ASMDATA_SIZE_32BIT); // Version number asmdata_appendword(asmdata, pagesize, ASMDATA_SIZE_32BIT); if (hint1 == NULL) { asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); } else { int64_t stroffset = asmdata_selectsection(asmdata, "asmdata.strings")->reservedsize; asmdata_appendbytes(asmdata, (uint8_t*)hint1, asmdata_strlen_(hint1) + 1); // Include terminating zero byte asmdata_selectsection(asmdata, "asmdata.fileheader"); asmdata_appendword(asmdata, stroffset, ASMDATA_SIZE_64BIT); } if (hint2 == NULL) { asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); } else { int64_t stroffset = asmdata_selectsection(asmdata, "asmdata.strings")->reservedsize; asmdata_appendbytes(asmdata, (uint8_t*)hint2, asmdata_strlen_(hint2) + 1); // Include terminating zero byte asmdata_selectsection(asmdata, "asmdata.fileheader"); asmdata_appendword(asmdata, stroffset, ASMDATA_SIZE_64BIT); } asmdata_appendword(asmdata, inthint, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, nstrsection, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, nhdrsection, ASMDATA_SIZE_32BIT); asmdata_appendword(asmdata, asmdata->nsections, ASMDATA_SIZE_32BIT); /* We need to add the section name strings before generating the section list, otherwise the newly-added strings * won't all get added to the string section before it's totals are recorded in the header. */ int64_t nameoffsets[ASMDATA_MAXSECTIONS]; int32_t i; for (i = 0; i < asmdata->nsections; i++) { nameoffsets[i] = asmdata_selectsection(asmdata, "asmdata.strings")->reservedsize; asmdata_appendbytes(asmdata, (uint8_t*)(asmdata->sections[i]->namecopy), asmdata_strlen_(asmdata->sections[i]->namecopy) + 1); // Include terminating zero byte } /* TODO: Hash values. */ int64_t hdrsize = asmdata_selectsection(asmdata, "asmdata.fileheader")->reservedsize; hdrsize += asmdata->nsections * 8 * 8; hdrsize += 16; // Final file size and checksum fields // NOTE: The header size is double-checked against the produced header at the end of this function int64_t sectionoffset = hdrsize; while (sectionoffset % pagesize != 0) { sectionoffset++; } for (i = 0; i < asmdata->nsections; i++) { asmdata_section_t* s = asmdata->sections[i]; asmdata_appendword(asmdata, s->bigendian ? 1 : 0, ASMDATA_SIZE_32BIT); // Encoding flags (in future may also specify compression etc.) asmdata_appendword(asmdata, 0, ASMDATA_SIZE_32BIT); // Content flags (in future may specify mapped/unmapped/executable/writable/etc.) asmdata_appendword(asmdata, sectionoffset, ASMDATA_SIZE_64BIT); // Offset in file asmdata_appendword(asmdata, s->virtualoffset, ASMDATA_SIZE_64BIT); if (s == asmdata->activesection) { /* The size field needs to be hard-coded for the header since we're still creating it! */ asmdata_appendword(asmdata, hdrsize, ASMDATA_SIZE_64BIT); // Size in file (not including page boundary padding) asmdata_appendword(asmdata, hdrsize, ASMDATA_SIZE_64BIT); // Size in memory (for header section, is the same as asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); // Reserved asmdata_appendword(asmdata, nameoffsets[i], ASMDATA_SIZE_64BIT); asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); // Hash (TODO) sectionoffset += hdrsize; } else { asmdata_appendword(asmdata, s->bufferfilled, ASMDATA_SIZE_64BIT); // Size in file (not including page boundary padding) asmdata_appendword(asmdata, s->reservedsize, ASMDATA_SIZE_64BIT); // Size in memory (padded with zero by the loader) asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); // Reserved asmdata_appendword(asmdata, nameoffsets[i], ASMDATA_SIZE_64BIT); asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); // Hash (TODO) sectionoffset += s->bufferfilled; } while (sectionoffset % pagesize != 0) { sectionoffset++; } } asmdata_appendword(asmdata, sectionoffset, ASMDATA_SIZE_64BIT); // Total file size asmdata_appendword(asmdata, 0, ASMDATA_SIZE_64BIT); // Checksum (TODO) /* Make sure the written header size exactly matches the size we calculated before writing. */ if (asmdata->activesection->bufferfilled != hdrsize) { return false; } return true; } asmdata_section_t* asmdata_findsection(asmdata_t* asmdata, const char* sectionname, bool autocreate) { int32_t i; for (i = 0; i < asmdata->nsections; i++) { if (asmdata_streq_(asmdata->sections[i]->namecopy, sectionname)) { return asmdata->sections[i]; } } if (autocreate && asmdata->nsections < ASMDATA_MAXSECTIONS) { asmdata_section_t* result = asmdata_section_new(sectionname); if (result == NULL) { return NULL; } asmdata->sections[asmdata->nsections] = result; result->sectionnumber = asmdata->nsections; asmdata->nsections++; return result; } return NULL; } bool asmdata_beginfile(asmdata_t* asmdata, const char* name) { return true; // TODO init? } bool asmdata_endfile(asmdata_t* asmdata, const char* name) { return true; // TODO cleanup/checks? } static int32_t asmdata_dummysymbol(asmdata_t* asmdata, const char* dummyname) { int32_t i; if (asmdata->nsymbols >= ASMDATA_MAXSYMBOLS) { return -1; } i = asmdata->nsymbols; asmdata->symbols[i].flags |= ASMDATA_SYMBOL_DUMMY; asmdata->symbols[i].namecopy = asmdata_strdup_(dummyname); asmdata->symbols[i].sectionindex = -1; asmdata->nsymbols++; return i; } int32_t asmdata_findsymbol(asmdata_t* asmdata, const char* name, bool autocreate) { int32_t i; for (i = 0; i < asmdata->nsymbols; i++) { if (asmdata_streq_(asmdata->symbols[i].namecopy, name)) { return i; } } if (!autocreate || asmdata->nsymbols >= ASMDATA_MAXSYMBOLS) { return -1; } i = asmdata->nsymbols; asmdata->symbols[i].namecopy = asmdata_strdup_(name); asmdata->symbols[i].sectionindex = -1; asmdata->nsymbols++; return i; } int32_t asmdata_symbolhere(asmdata_t* asmdata, const char* name) { int32_t idx = asmdata_findsymbol(asmdata, name, true); if (idx < 0) { return idx; } asmdata_symbol_t* symbol = &(asmdata->symbols[idx]); if (symbol->sectionindex != -1) { return -1; // It's already defined? } symbol->sectionindex = asmdata_activesection(asmdata)->sectionnumber; symbol->sectionoffset = asmdata_activesection(asmdata)->reservedsize; // TODO: Clear flags etc.? return idx; } int32_t asmdata_appendreferenceword(asmdata_t* asmdata, const char* name, int8_t size) { int64_t startoffset = asmdata_activesection(asmdata)->reservedsize; if (!asmdata_appendword(asmdata, 0, size)) { return -1; } if (asmdata->nreferences >= ASMDATA_MAXREFERENCES) { return -1; } int32_t idx = asmdata->nreferences; asmdata_reference_t* reference = &(asmdata->references[idx]); reference->symbolindex = asmdata_findsymbol(asmdata, name, true); if (reference->symbolindex < 0) { return -1; } reference->sectionindex = asmdata_activesection(asmdata)->sectionnumber; //printf("Note: Reference '%s' at offset %d\n", name, startoffset); reference->sectionoffset = startoffset; reference->size = size; // TODO: Clear flags etc.? asmdata->nreferences++; return idx; } static int32_t asmdata_appendsubref_(asmdata_t* asmdata, int32_t symbol, int8_t size) { int64_t startoffset = asmdata_activesection(asmdata)->reservedsize; if (!asmdata_appendword(asmdata, 0, size)) { return -1; } if (asmdata->nreferences >= ASMDATA_MAXREFERENCES) { return -1; } int32_t idx = asmdata->nreferences; asmdata_reference_t* reference = &(asmdata->references[idx]); reference->symbolindex = symbol; if (reference->symbolindex < 0) { return -1; } reference->sectionindex = asmdata_activesection(asmdata)->sectionnumber; //printf("Note: Reference '%s' at offset %d\n", name, startoffset); reference->sectionoffset = startoffset; reference->size = size; // TODO: Clear flags etc.? asmdata->nreferences++; return idx; } int32_t asmdata_subx_(asmdata_t* asmdata, int32_t tt, const char* tokenstr, asmlnx_t* expr); int32_t asmdata_subx_(asmdata_t* asmdata, int32_t tt, const char* tokenstr, asmlnx_t* expr) { if (tt == ASMT_TOKENTYPE_NAME) { // Shortcut if this part of the expression is just a simple symbol name return asmdata_findsymbol(asmdata, tokenstr, true); } int32_t result = asmdata_dummysymbol(asmdata, tokenstr); if (result >= 0) { asmdata_symbol_t* sym = &asmdata->symbols[result]; switch (tt) { case ASMT_TOKENTYPE_NUMBER: sym->flags |= ASMDATA_SYMBOL_CONST; sym->sectionoffset = asmdata_atoll_(tokenstr); break; case ASMT_TOKENTYPE_OPENBR: sym->flags |= ASMDATA_SYMBOL_EXPR; sym->x_lhs = asmdata_subx_(asmdata, expr->lhstype, expr->lhscopy, expr->lhsx); if (sym->x_lhs < 0) { return -1; } sym->x_op = asmdata_dummysymbol(asmdata, expr->opcopy); if (sym->x_op < 0) { return -1; } asmdata->symbols[sym->x_op].flags |= ASMDATA_SYMBOL_OP; sym->x_rhs = asmdata_subx_(asmdata, expr->rhstype, expr->rhscopy, expr->rhsx); if (sym->x_rhs < 0) { return -1; } //sym->flags |= ASMDATA_SYMBOL_CONST; break; default: return -1; } } return result; } static bool asmdata_appendvalue_(asmdata_t* asmdata, int32_t tokentype, const char* tokenstr, asmlnx_t* expr, int8_t primsize) { if (tokentype == ASMT_TOKENTYPE_NUMBER) { long long x = asmdata_atoll_(tokenstr); //printf("Got number %lld\n", x); return asmdata_appendword(asmdata, (int64_t)x, primsize); } else if (tokentype == ASMT_TOKENTYPE_STRING) { int32_t l = asmdata_strlen_(tokenstr); int32_t i; for (i = 0; i < l; i++) { if (!asmdata_appendword(asmdata, (int64_t)((int8_t)(tokenstr[i])), primsize)) { return false; } } return true; } else if (tokentype == ASMT_TOKENTYPE_NAME) { int32_t refidx = asmdata_appendreferenceword(asmdata, tokenstr, primsize); if (refidx < 0) { return false; } else { return true; } } else if (tokentype == ASMT_TOKENTYPE_OPENBR) { int32_t exprsym = asmdata_subx_(asmdata, tokentype, tokenstr, expr); if (exprsym < 0) { return false; } int32_t ref = asmdata_appendsubref_(asmdata, exprsym, primsize); if (ref < 0) { return false; } else { return true; } } else { return false; } } bool asmdata_isvalidasmln(asmdata_t* asmdata, asmln_t* asmln) { if (asmln == NULL || asmln->errorcopy != NULL) { return false; // If there's a major error it's obviously not a valid data line } if (asmln->instrcopy == NULL) { return true; // If there's no "instruction" part then it's either a plain label or an empty/comment line, which is perfectly valid } if (asmdata->extsyntax) { if (asmdata_streq_(asmln->instrcopy, ".text") || asmdata_streq_(asmln->instrcopy, ".data")) { return true; } if (asmdata_streq_(asmln->instrcopy, ".string") && asmln->nparams == 1) { return true; } if (asmdata_streq_(asmln->instrcopy, ".long") || asmdata_streq_(asmln->instrcopy, ".long")) { return true; } } // For normal lines (with an "instruction" part) then we recognise anything that is data or simple section/symbol/linkage instruction return asmdata_streq_(asmln->instrcopy, "data8") || asmdata_streq_(asmln->instrcopy, "data16") || asmdata_streq_(asmln->instrcopy, "data32") || asmdata_streq_(asmln->instrcopy, "data64") || asmdata_streq_(asmln->instrcopy, "data.section") || asmdata_streq_(asmln->instrcopy, "data.symbol") || asmdata_streq_(asmln->instrcopy, "align") || asmdata_streq_(asmln->instrcopy, "reserve"); } bool asmdata_asmln(asmdata_t* asmdata, asmln_t* asmln) { if (!asmdata_isvalidasmln(asmdata, asmln)) { if (asmln != NULL && asmln->errorcopy == NULL) { asmln->errorcopy = asmdata_strdup_("Not a valid data instruction"); } return false; } if (asmln->labelcopy != NULL) { int32_t idx = asmdata_symbolhere(asmdata, asmln->labelcopy); //printf("SYMBOL '%s'\n", asmln->labelcopy); if (idx < 0) { asmln->errorcopy = asmdata_strdup_("Failed to create symbol (label already defined?)"); return false; } } if (asmln->instrcopy == NULL && asmln->nparams == 0) { // No instruction. We're done! (Parameters were also checked to be 0, just to be pedantic.) return true; } if (asmdata->extsyntax && (asmdata_streq_(asmln->instrcopy, ".text") || asmdata_streq_(asmln->instrcopy, ".data"))) { asmdata_selectsection(asmdata, asmln->instrcopy+1); return true; } else if (asmdata_streq_(asmln->instrcopy, "data.section")) { if (asmln->nparams == 0) { asmdata->activesection = NULL; // Reset the section return true; } else if (asmln->nparams == 1) { if (asmln->paramtype[0] != ASMT_TOKENTYPE_NAME && asmln->paramtype[0] != ASMT_TOKENTYPE_STRING) { asmln->errorcopy = asmdata_strdup_("section instruction expects section identified by a name or string (but got a different parameter)"); return false; } asmdata_selectsection(asmdata, asmln->paramcopy[0]); return true; } else { asmln->errorcopy = asmdata_strdup_("TODO: Additional section parameters"); return false; } } else if (asmdata_streq_(asmln->instrcopy, "data.symbol")) { if (asmln->nparams != 2 || asmln->paramtype[0] != ASMT_TOKENTYPE_NAME || asmln->paramtype[1] != ASMT_TOKENTYPE_NUMBER) { asmln->errorcopy = asmdata_strdup_("data.symbol special instruction requires a symbol name and flag integer"); return false; } int32_t idx = asmdata_findsymbol(asmdata, asmln->paramcopy[0], true); if (idx < 0) { return idx; } asmdata_symbol_t* symbol = &(asmdata->symbols[idx]); if (symbol->sectionindex != -1) { return -1; // It's already defined? } long x = asmdata_atoll_(asmln->paramcopy[1]); symbol->flags |= (int)x; return true; } else if (asmdata_streq_(asmln->instrcopy, "align")) { if (asmln->nparams != 1 || asmln->paramtype[0] != ASMT_TOKENTYPE_NUMBER) { asmln->errorcopy = asmdata_strdup_("align special instruction requires a simple integer"); return false; } long x = asmdata_atoll_(asmln->paramcopy[0]); while ((asmdata_activesection(asmdata)->reservedsize % x) != 0) { asmdata_activesection(asmdata)->reservedsize++; } return true; } else if (asmdata_streq_(asmln->instrcopy, "reserve")) { if (asmln->nparams != 1 || asmln->paramtype[0] != ASMT_TOKENTYPE_NUMBER) { asmln->errorcopy = asmdata_strdup_("reserve special instruction requires a simple integer"); return false; } long x = asmdata_atoll_(asmln->paramcopy[0]); while (x > 0) { asmdata_activesection(asmdata)->reservedsize++; x--; } return true; } else if (asmdata_streq_(asmln->instrcopy, "data8")) { if (asmln->nparams < 1) { asmln->errorcopy = asmdata_strdup_("data instructions generally expect at least one value, otherwise they are probably erroneous"); return false; } int32_t i; for (i = 0; i < asmln->nparams; i++) { //printf("DOING ARG %d\n", i); if (!asmdata_appendvalue_(asmdata, asmln->paramtype[i], asmln->paramcopy[i], asmln->paramx[i], ASMDATA_SIZE_8BIT)) { asmln->errorcopy = asmdata_strdup_("invalid data value"); return false; } } return true; } else if (asmdata->extsyntax && asmdata_streq_(asmln->instrcopy, ".string")) { if (asmln->nparams < 1) { asmln->errorcopy = asmdata_strdup_("data instructions generally expect at least one value, otherwise they are probably erroneous"); return false; } int32_t i; for (i = 0; i < asmln->nparams; i++) { //printf("DOING ARG %d\n", i); if (!asmdata_appendvalue_(asmdata, asmln->paramtype[i], asmln->paramcopy[i], asmln->paramx[i], ASMDATA_SIZE_8BIT)) { asmln->errorcopy = asmdata_strdup_("invalid data value"); return false; } } asmdata_appendvalue_(asmdata, ASMT_TOKENTYPE_NUMBER, "0", NULL, ASMDATA_SIZE_8BIT); return true; } else if (asmdata_streq_(asmln->instrcopy, "data16")) { if (asmln->nparams < 1) { asmln->errorcopy = asmdata_strdup_("data instructions generally expect at least one value, otherwise they are probably erroneous"); return false; } int32_t i; for (i = 0; i < asmln->nparams; i++) { if (!asmdata_appendvalue_(asmdata, asmln->paramtype[i], asmln->paramcopy[i], asmln->paramx[i], ASMDATA_SIZE_16BIT)) { asmln->errorcopy = asmdata_strdup_("invalid data value"); return false; } } return true; } else if (asmdata_streq_(asmln->instrcopy, "data32")) { if (asmln->nparams < 1) { asmln->errorcopy = asmdata_strdup_("data instructions generally expect at least one value, otherwise they are probably erroneous"); return false; } int32_t i; for (i = 0; i < asmln->nparams; i++) { if (!asmdata_appendvalue_(asmdata, asmln->paramtype[i], asmln->paramcopy[i], asmln->paramx[i], ASMDATA_SIZE_32BIT)) { asmln->errorcopy = asmdata_strdup_("invalid data value"); return false; } } return true; } else if (asmdata_streq_(asmln->instrcopy, "data64") || (asmdata->extsyntax && asmdata_streq_(asmln->instrcopy, ".long"))) { if (asmln->nparams < 1) { asmln->errorcopy = asmdata_strdup_("data instructions generally expect at least one value, otherwise they are probably erroneous"); return false; } int32_t i; for (i = 0; i < asmln->nparams; i++) { if (!asmdata_appendvalue_(asmdata, asmln->paramtype[i], asmln->paramcopy[i], asmln->paramx[i], ASMDATA_SIZE_64BIT)) { asmln->errorcopy = asmdata_strdup_("invalid data value"); return false; } } return true; } else { asmln->errorcopy = asmdata_strdup_("internal error, asmdata recognised input but didn't translate it properly"); return false; } }