summaryrefslogtreecommitdiff
path: root/mld/segtab.c
diff options
context:
space:
mode:
Diffstat (limited to 'mld/segtab.c')
-rw-r--r--mld/segtab.c147
1 files changed, 147 insertions, 0 deletions
diff --git a/mld/segtab.c b/mld/segtab.c
new file mode 100644
index 0000000..22356d5
--- /dev/null
+++ b/mld/segtab.c
@@ -0,0 +1,147 @@
+#include <stdlib.h>
+#include <merror.h>
+
+#include "link.h"
+
+#define SEGTAB_INIT_SIZE 8
+
+int segtab_init(struct segment_table *segtab)
+{
+ segtab->len = 0;
+ segtab->size = SEGTAB_INIT_SIZE;
+ segtab->entries = malloc(sizeof(struct segment_table_entry) *
+ SEGTAB_INIT_SIZE);
+
+ if (segtab->entries == NULL) {
+ PERROR("cannot alloc");
+ return M_ERROR;
+ }
+
+ return M_SUCCESS;
+}
+
+void segtab_free(struct segment_table *segtab)
+{
+ for (uint32_t i = 0; i < segtab->len; i++) {
+ segtab_ent_free(&segtab->entries[i]);
+ }
+ free(segtab->entries);
+}
+
+/* create a new entry with <seg> as its first segment part */
+int segtab_push(struct segment_table *segtab, struct segment_table_entry **res,
+ struct segment *seg)
+{
+ if (segtab->len >= segtab->size) {
+ uint32_t size = segtab->size * 2;
+ void *new = realloc(segtab->entries,
+ sizeof(struct segment_table_entry) * size);
+ if (new == NULL) {
+ PERROR("cannot relloc");
+ return M_ERROR;
+ }
+ segtab->size = size;
+ segtab->entries = new;
+ }
+
+ struct segment_table_entry ent;
+ if (segtab_ent_init(&ent))
+ return M_ERROR;
+ ent.name = seg->name;
+ ent.vaddr = seg->vaddr;
+ ent.off = seg->off;
+
+ if (segtab_ent_push(&ent, seg)) {
+ segtab_ent_free(&ent);
+ return M_ERROR;
+ }
+
+ segtab->entries[segtab->len] = ent;
+
+ if (res != NULL)
+ *res = &segtab->entries[segtab->len];
+
+ segtab->len++;
+
+ return M_SUCCESS;
+}
+
+/* find a segment table entry with a given name */
+int segtab_get(struct segment_table *segtab, struct segment_table_entry **ent,
+ const char *name)
+{
+ for (uint32_t i = 0; i < segtab->len; i++) {
+ const char *segname = segtab->entries[i].name;
+ if (strcmp(name, segname) != 0)
+ continue;
+
+ *ent = &segtab->entries[i];
+ return M_SUCCESS;
+ }
+
+ return M_ERROR;
+}
+
+int segtab_ent_init(struct segment_table_entry *ent)
+{
+ ent->len = 0;
+ ent->size = SEGTAB_INIT_SIZE;
+ ent->parts = malloc(sizeof(struct segment *) *
+ SEGTAB_INIT_SIZE);
+
+ if (ent->parts == NULL) {
+ PERROR("cannot alloc");
+ return M_ERROR;
+ }
+
+ return M_SUCCESS;
+}
+
+void segtab_ent_free(struct segment_table_entry *ent)
+{
+ free(ent->parts);
+}
+
+int segtab_ent_push(struct segment_table_entry *ent, struct segment *seg)
+{
+ if (ent->len >= ent->size) {
+ uint32_t size = ent->size * 2;
+ void *new = realloc(ent->parts,
+ sizeof(struct segment *) * size);
+ if (new == NULL) {
+ PERROR("cannot relloc");
+ return M_ERROR;
+ }
+ ent->size = size;
+ ent->parts = new;
+ }
+
+ if (ent->len > 0) {
+ struct segment *first = ent->parts[0];
+ if (first->align != seg->align) {
+ ERROR("segment '%s' doest not have matching alignment",
+ ent->name);
+ }
+ if (first->read != seg->read ||
+ first->write != seg->write ||
+ first->execute != seg->execute) {
+ ERROR("segment '%s' doest not have matching RWX",
+ ent->name);
+ }
+ } else {
+ ent->off = seg->new_off;
+ ent->vaddr = seg->new_vaddr;
+ }
+
+ ent->parts[ent->len++] = seg;
+ return M_SUCCESS;
+}
+
+uint32_t segtab_ent_size(struct segment_table_entry *ent)
+{
+ uint32_t size = 0;
+ for (uint32_t i = 0; i < ent->len; i++) {
+ size += ent->parts[i]->size;
+ }
+ return size;
+}