mips/masm/gen/section.c
2024-10-21 12:27:18 -04:00

156 lines
3.4 KiB
C

#include "../gen.h"
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <merror.h>
struct section_default {
char *name;
int name_len;
bool read;
bool write;
bool execute;
int alignment;
};
#define SECTION_DEFAULTS_LEN 7
#define MAPPING(name, ...) {name, sizeof(name), __VA_ARGS__}
static const struct section_default section_defaults[SECTION_DEFAULTS_LEN] = {
MAPPING(".text", true, false, true, 4),
MAPPING(".code", true, false, true, 4),
MAPPING(".data", true, true, false, 1),
MAPPING(".stack", true, true, false, 1),
MAPPING(".rodata", true, false, false, 1),
MAPPING(".bss", true, true, false, 1),
MAPPING(".robss", true, false, false, 1),
};
static void section_get_default_perm(struct section *sec, const char *name)
{
for (int i = 0; i < SECTION_DEFAULTS_LEN; i++) {
const struct section_default *defaults = &section_defaults[i];
if (strncasecmp(name, defaults->name, defaults->name_len))
continue;
sec->read = defaults->read;
sec->write = defaults->write;
sec->execute = defaults->execute;
sec->align = defaults->alignment;
break;
}
}
int gen_get_section(struct generator *gen, struct section **res,
struct string *name)
{
/// find the section if it exists
for (size_t i = 0; i < gen->sections_len; i++) {
struct section *sec = &gen->sections[i];
if (sec->name.len != name->len)
continue;
if (strcmp(sec->name.str, name->str) != 0)
continue;
*res = sec;
return 0;
}
/// allocate a new one if it doesnt
size_t size = gen->sections_size ? gen->sections_size * 2 : 8;
void *new = realloc(gen->sections, size * sizeof(struct section));
if (new == NULL) {
PERROR("cannot realloc");
return 1;
}
gen->sections_size = size;
gen->sections = new;
struct section *sec = &gen->sections[gen->sections_len++];
if (section_init(sec, name))
return 1;
*res = sec;
return 0;
}
int section_init(struct section *sec, struct string *name)
{
sec->len = 0;
sec->size = 0;
sec->align = 1;
sec->data = NULL;
sec->read = true;
sec->write = true;
sec->execute = false;
// set defaults
section_get_default_perm(sec, name->str);
// alloc reftab
if (reftab_init(&sec->reftab))
return 1;
// copy name
if (string_clone(&sec->name, name))
return 1;
return 0;
}
int section_extend(struct section *section, size_t space)
{
size_t newlen = section->len + space;
if (newlen < section->size)
return M_SUCCESS;
size_t size = section->size ? section->size * 2 + newlen : newlen * 2;
void *new = realloc(section->data, size);
if (new == NULL) {
PERROR("cannot realloc");
return M_ERROR;
}
section->size = size;
section->data = new;
return M_SUCCESS;
}
int section_push(struct section *section, void *data, size_t len)
{
size_t newlen = section->len + len;
size_t zeros = newlen % section->align;
if (zeros)
zeros = section->align - zeros;
if (section_extend(section, len + zeros))
return M_ERROR;
memset(section->data + section->len, 0, zeros);
memcpy(section->data + section->len + zeros, data, len);
section->len += len + zeros;
return M_SUCCESS;
}
int section_zero(struct section *section, size_t len)
{
size_t zeros = section->len % section->align;
if (zeros)
zeros = section->align - zeros;
if (section_extend(section, len + zeros))
return M_ERROR;
memset(section->data + section->len, 0, len + zeros);
section->len += len + zeros;
return M_SUCCESS;
}
void section_free(struct section *section)
{
reftab_free(&section->reftab);
string_free(&section->name);
free(section->data);
}