summaryrefslogtreecommitdiff
path: root/masm/gen/section.c
diff options
context:
space:
mode:
Diffstat (limited to 'masm/gen/section.c')
-rw-r--r--masm/gen/section.c156
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 = &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);
+}