vc3/link/sym.c
2025-04-17 13:27:20 +02:00

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;
}