111 lines
2.8 KiB
C
111 lines
2.8 KiB
C
#include "sym.h"
|
|
#include "header.h"
|
|
#include "link.h"
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
void sym_destroy(Sym* sym)
|
|
{
|
|
free(sym->ident);
|
|
}
|
|
|
|
void sym_table_construct(SymTable* table)
|
|
{
|
|
const size_t syms_capacity = 16;
|
|
*table = (SymTable) {
|
|
.syms = malloc(sizeof(SymTable) * syms_capacity),
|
|
.syms_capacity = syms_capacity,
|
|
.syms_size = 0,
|
|
};
|
|
}
|
|
|
|
void sym_table_destroy(SymTable* table)
|
|
{
|
|
for (size_t i = 0; i < table->syms_size; ++i) {
|
|
sym_destroy(&table->syms[i]);
|
|
}
|
|
free(table->syms);
|
|
}
|
|
|
|
Sym* sym_table_find(SymTable* table, const char* ident)
|
|
{
|
|
for (size_t i = 0; i < table->syms_size; ++i) {
|
|
Sym* sym = &table->syms[i];
|
|
if (strcmp(sym->ident, ident) == 0) {
|
|
return sym;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static inline void sym_table_add(SymTable* table,
|
|
char* ident,
|
|
const char* filename,
|
|
uint16_t offset,
|
|
bool resolved)
|
|
{
|
|
if (table->syms_size + 1 > table->syms_capacity) {
|
|
table->syms_capacity *= 2;
|
|
table->syms
|
|
= realloc(table->syms, sizeof(SymTable) * table->syms_capacity);
|
|
}
|
|
table->syms[table->syms_size++]
|
|
= (Sym) { ident, filename, offset, resolved };
|
|
}
|
|
|
|
void sym_table_add_unresolved(
|
|
SymTable* table, char* ident, const char* filename)
|
|
{
|
|
sym_table_add(table, ident, filename, 0, false);
|
|
}
|
|
|
|
void sym_table_add_resolved(
|
|
SymTable* table, char* ident, const char* filename, uint16_t offset)
|
|
{
|
|
sym_table_add(table, ident, filename, offset, true);
|
|
}
|
|
|
|
int sym_table_walk_header(
|
|
SymTable* syms, Header* header, uint16_t offset, const char* input_filename)
|
|
{
|
|
for (size_t i = 0; i < header->global_syms_size; ++i) {
|
|
const HeaderGlobalSym* global_sym = &header->global_syms[i];
|
|
Sym* sym = sym_table_find(syms, global_sym->ident);
|
|
|
|
if (!sym) {
|
|
sym_table_add_resolved(syms,
|
|
link_strdup(global_sym->ident),
|
|
input_filename,
|
|
offset + global_sym->offset);
|
|
} else if (!sym->resolved) {
|
|
sym->offset = offset + global_sym->offset;
|
|
sym->resolved = true;
|
|
} else {
|
|
|
|
fprintf(stderr,
|
|
"error: duplicate symbol '%s' defined in %s\n",
|
|
global_sym->ident,
|
|
input_filename);
|
|
fprintf(stderr,
|
|
"info: symbol '%s' originally defined in %s\n",
|
|
sym->ident,
|
|
sym->filename);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
for (size_t i = 0; i < header->extern_syms_size; ++i) {
|
|
const HeaderExternSym* extern_sym = &header->extern_syms[i];
|
|
Sym* sym = sym_table_find(syms, extern_sym->ident);
|
|
|
|
if (!sym) {
|
|
sym_table_add_unresolved(
|
|
syms, link_strdup(extern_sym->ident), input_filename);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|