slas/asmdata.c

898 lines
30 KiB
C

#include "asmdata.h"
#include <stdlib.h>
//#include <stdio.h> //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-NULL-STRING>";
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-NULL-STRING>";
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;
}
}