diff options
Diffstat (limited to 'masm/gen/section.c')
| -rw-r--r-- | masm/gen/section.c | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/masm/gen/section.c b/masm/gen/section.c new file mode 100644 index 0000000..44f83f8 --- /dev/null +++ b/masm/gen/section.c @@ -0,0 +1,156 @@ +#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 = §ion_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(§ion->reftab); + string_free(§ion->name); + free(section->data); +} |