/*
* FDPP - freedos port to modern C++
* Copyright (C) 2021 Stas Sergeev (stsp)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "elf_priv.h"
struct elfstate {
size_t mapsize;
Elf *elf;
Elf_Scn *symtab_scn;
GElf_Shdr symtab_shdr;
char *addr;
};
static int do_getsym(struct elfstate *state, const char *name, GElf_Sym *r_sym)
{
Elf_Data *data;
int count, i;
data = elf_getdata(state->symtab_scn, NULL);
count = state->symtab_shdr.sh_size / state->symtab_shdr.sh_entsize;
for (i = 0; i < count; i++) {
GElf_Sym sym;
gelf_getsym(data, i, &sym);
if (strcmp(elf_strptr(state->elf, state->symtab_shdr.sh_link,
sym.st_name), name) == 0) {
*r_sym = sym;
return 0;
}
}
return -1;
}
static int do_elf_open(char *addr, uint32_t size, struct elfstate *ret)
{
Elf *elf;
Elf_Scn *scn = NULL;
GElf_Shdr shdr;
elf_version(EV_CURRENT);
elf = elf_memory(addr, size);
if (!elf) {
fprintf(stderr, "elf_memory() failed\n");
return -1;
}
while ((scn = elf_nextscn(elf, scn)) != NULL) {
gelf_getshdr(scn, &shdr);
if (shdr.sh_type == SHT_SYMTAB) {
/* found a symbol table, go print it. */
break;
}
}
if (!scn) {
fprintf(stderr, "elf: not found SHT_SYMTAB\n");
goto err;
}
ret->mapsize = size;
ret->elf = elf;
ret->symtab_scn = scn;
ret->symtab_shdr = shdr;
return 0;
err:
elf_end(elf);
return -1;
}
void *djelf_open(char *addr, uint32_t size)
{
struct elfstate es = {}, *ret;
int err = do_elf_open(addr, size, &es);
if (err)
return NULL;
ret = (struct elfstate *)malloc(sizeof(*ret));
*ret = es;
return ret;
}
void *djelf_open_dyn(void)
{
struct elfstate es = {}, *ret;
int err;
int fd;
char *addr;
struct stat st;
fd = open(CRT0, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
perror("open()");
return NULL;
}
fstat(fd, &st);
addr = (char *)mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
fd, 0);
close(fd);
if (addr == MAP_FAILED) {
perror("mmap()");
return NULL;
}
err = do_elf_open(addr, st.st_size, &es);
if (err)
return NULL;
ret = (struct elfstate *)malloc(sizeof(*ret));
*ret = es;
ret->addr = addr;
return ret;
}
void djelf_close(void *arg)
{
struct elfstate *state = (struct elfstate *)arg;
elf_end(state->elf);
if (state->addr)
munmap(state->addr, state->mapsize);
free(state);
}
static uint32_t do_getsymoff(struct elfstate *state, const char *name)
{
GElf_Sym sym;
int err = do_getsym(state, name, &sym);
assert(err || sym.st_value); // make sure st_value!=0
return (err ? 0 : sym.st_value);
}
uint32_t djelf_getsymoff(void *arg, const char *name)
{
struct elfstate *state = (struct elfstate *)arg;
return do_getsymoff(state, name);
}