157 lines
3.4 KiB
C
157 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 = §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);
|
||
|
}
|