121 lines
2.6 KiB
C
121 lines
2.6 KiB
C
#include <elf.h>
|
|
#include <merror.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <melf.h>
|
|
|
|
#include "link.h"
|
|
|
|
#define SYMTAB_INIT_LEN 8
|
|
|
|
int symtab_init(struct symbol_table *symtab)
|
|
{
|
|
symtab->len = 1;
|
|
symtab->size = SYMTAB_INIT_LEN;
|
|
symtab->syms = malloc(sizeof(Elf32_Sym) * SYMTAB_INIT_LEN);
|
|
|
|
if (symtab->syms == NULL) {
|
|
PERROR("cannot alloc");
|
|
return M_ERROR;
|
|
}
|
|
|
|
symtab->syms[0] = (Elf32_Sym){0};
|
|
symtab->map = NULL;
|
|
|
|
return M_SUCCESS;
|
|
}
|
|
|
|
void symtab_free(struct symbol_table *symtab)
|
|
{
|
|
free(symtab->syms);
|
|
}
|
|
|
|
int symtab_push(struct symbol_table *symtab, const Elf32_Sym *sym)
|
|
{
|
|
if (symtab->len >= symtab->size) {
|
|
size_t size = symtab->size *= 2;
|
|
void *new = realloc(symtab->syms, sizeof(Elf32_Sym) * size);
|
|
if (new == NULL) {
|
|
PERROR("cannot realloc");
|
|
return M_ERROR;
|
|
}
|
|
symtab->size = size;
|
|
symtab->syms = new;
|
|
}
|
|
|
|
symtab->syms[symtab->len++] = *sym;
|
|
return M_SUCCESS;
|
|
}
|
|
|
|
int symtab_get(struct symbol_table *symtab, Elf32_Sym **res, const char *name,
|
|
int32_t obj_idx)
|
|
{
|
|
for (size_t i = 1; i < symtab->len; i++) {
|
|
Elf32_Sym *sym = &symtab->syms[i];
|
|
const char *symname = symtab->strtab->data + B32(sym->st_name);
|
|
if (strcmp(name, symname) != 0)
|
|
continue;
|
|
|
|
// ignore absolute symbols
|
|
if (B16(sym->st_shndx) == SHN_ABS)
|
|
continue;
|
|
|
|
// only allow retrevial of local variables from the
|
|
// same object
|
|
if (sym->st_info >> 4 != STB_GLOBAL && symtab->map != NULL &&
|
|
obj_idx >= 0) {
|
|
// we need to change the index by one since
|
|
// symbol tables always start will a NULl symbol
|
|
struct object *obj = symtab->map->meta[i - 1];
|
|
if (obj->index != (uint32_t)obj_idx)
|
|
continue;
|
|
} else if (obj_idx < 0 && sym->st_info >> 4 != STB_GLOBAL) {
|
|
// when obj_idx is -1, we only want to reutrn
|
|
// global symbols
|
|
continue;
|
|
}
|
|
|
|
if (res != NULL)
|
|
*res = sym;
|
|
return M_SUCCESS;
|
|
}
|
|
return M_ERROR;
|
|
}
|
|
|
|
int symtab_map_push(struct symbol_table_mapping *symtabm, struct object *meta)
|
|
{
|
|
if (symtabm->len >= symtabm->size) {
|
|
uint32_t size = symtabm->size * 2;
|
|
void *new = realloc(symtabm->meta,
|
|
sizeof(struct object *) * size);
|
|
if (new == NULL) {
|
|
PERROR("cannot realloc");
|
|
return M_ERROR;
|
|
}
|
|
symtabm->size = size;
|
|
symtabm->meta = new;
|
|
}
|
|
|
|
symtabm->meta[symtabm->len++] = meta;
|
|
return M_SUCCESS;
|
|
}
|
|
|
|
int symtab_map_init(struct symbol_table_mapping *symtabm)
|
|
{
|
|
symtabm->len = 0;
|
|
symtabm->size = SYMTAB_INIT_LEN;
|
|
symtabm->meta = malloc(sizeof(struct object *) * symtabm->size);
|
|
|
|
if (symtabm->meta == NULL) {
|
|
PERROR("cannot alloc");
|
|
return M_ERROR;
|
|
}
|
|
|
|
return M_SUCCESS;
|
|
}
|
|
|
|
|
|
void symtab_map_free(struct symbol_table_mapping *symtabm)
|
|
{
|
|
free(symtabm->meta);
|
|
}
|