1
0
Files
irix-657m-src/eoe/cmd/setsym/elfsubr.c
2022-09-29 17:59:04 +03:00

263 lines
6.8 KiB
C

/*
* "elfsubr.c"
*
*/
#include <libelf.h>
#include <string.h>
#include "elfsubr.h"
int
sym_val64(Elf *elf, char *sym_name, Elf64_Addr *value)
{
/* this static is here so that if the same file is repeatedly checked,
the code isn't repeated */
static Elf *oldelf = NULL;
static Elf_Scn *symtab_scn;
static Elf64_Shdr *symtab_shdr;
Elf64_Sym *symtab;
int symtab_size, i;
/* see if we have correct symtab */
if (elf != oldelf) {
symtab_scn = find_section(elf, ".symtab");
symtab_shdr = elf64_getshdr(symtab_scn);
}
symtab = (Elf64_Sym *)(elf_getdata(symtab_scn, NULL)->d_buf);
symtab_size = (elf_getdata(symtab_scn, NULL)->d_size)
/ sizeof(Elf64_Sym);
/* keep looking at entries until the right one is found */
for(i = 0; i < symtab_size; i++)
if (strcmp(sym_name,
elf_strptr(elf, symtab_shdr->sh_link, symtab[i].st_name))
== 0)
break;
if (i == symtab_size)
return 1;
*value = symtab[i].st_value;
return 0;
}
int
sym_val32(Elf *elf, char *sym_name, Elf32_Addr *value)
{
/* this static is here so that if the same file is repeatedly checked,
the code isn't repeated */
static Elf *oldelf = NULL;
static Elf_Scn *symtab_scn;
static Elf32_Shdr *symtab_shdr;
Elf32_Sym *symtab;
int symtab_size, i;
/* see if we have correct symtab */
if (elf != oldelf) {
symtab_scn = find_section(elf, ".symtab");
symtab_shdr = elf32_getshdr(symtab_scn);
}
symtab = (Elf32_Sym *)(elf_getdata(symtab_scn, NULL)->d_buf);
symtab_size = (elf_getdata(symtab_scn, NULL)->d_size)
/ sizeof(Elf32_Sym);
/* keep looking at entries until the right one is found */
for(i = 0; i < symtab_size; i++)
if (strcmp(sym_name,
elf_strptr(elf, symtab_shdr->sh_link, symtab[i].st_name))
== 0)
break;
if (i == symtab_size)
return 1;
*value = symtab[i].st_value;
return 0;
}
int
elf_type(Elf *elf)
{
/* these statics are here so that if the same file is repeatedly
checked, the code isn't repeated */
static Elf *oldelf = NULL;
static int oldtype;
if (elf == oldelf)
return(oldtype);
/* otherwise do calculations */
else
{
unsigned char MipsElf32Ident[EI_NIDENT] = {
0x7f, 'E', 'L', 'F',
ELFCLASS32, ELFDATA2MSB, EV_CURRENT,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned char MipsElf64Ident[EI_NIDENT] = {
0x7f, 'E', 'L', 'F',
ELFCLASS64, ELFDATA2MSB, EV_CURRENT,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
char *elf_ident;
oldelf = elf;
if ((elf_ident = elf_getident(elf, NULL)) == NULL)
return((oldtype = ELF_NONE));
if (memcmp(MipsElf32Ident, elf_ident, EI_NIDENT) == 0)
return((oldtype = ELF_MIPS32));
else if (memcmp(MipsElf64Ident, elf_ident, EI_NIDENT) == 0)
return((oldtype = ELF_MIPS64));
else
return((oldtype = ELF_UNKNOWN));
}
}
/*
* returns section with the name of scn_name, & puts its header in shdr64 or
* shdr32 based on elf's file type
*
*/
Elf_Scn *
find_section(Elf *elf, char *scn_name)
{
Elf64_Ehdr *ehdr64;
Elf32_Ehdr *ehdr32;
Elf_Scn *scn = NULL;
Elf64_Shdr *shdr64;
Elf32_Shdr *shdr32;
if (elf_type(elf) == ELF_MIPS64) {
if ((ehdr64 = elf64_getehdr(elf)) == NULL)
return(NULL);
do {
if ((scn = elf_nextscn(elf, scn)) == NULL)
break;
if ((shdr64 = elf64_getshdr(scn)) == NULL)
return(NULL);
} while (strcmp(scn_name, elf_strptr(elf, ehdr64->e_shstrndx,
shdr64->sh_name)));
}
else if (elf_type(elf) == ELF_MIPS32) {
if ((ehdr32 = elf32_getehdr(elf)) == NULL)
return(NULL);
do {
if ((scn = elf_nextscn(elf, scn)) == NULL)
break;
if ((shdr32 = elf32_getshdr(scn)) == NULL)
return(NULL);
} while (strcmp(scn_name, elf_strptr(elf, ehdr32->e_shstrndx,
shdr32->sh_name)));
}
else
scn = NULL;
return(scn);
}
char *
find_sym_offset64(Elf *elf,
char *symname,
Elf64_Off *offset,
Elf_Scn *datascn,
Elf_Scn *sdatascn,
Elf_Scn *bssscn)
{
Elf64_Off data_offset;
Elf64_Addr data_addr;
Elf64_Word data_size;
Elf64_Addr addr;
data_offset = elf64_getshdr(datascn)->sh_offset;
data_addr = elf64_getshdr(datascn)->sh_addr;
data_size = elf64_getshdr(datascn)->sh_size;
if (sym_val64(elf, symname, &addr) != 0)
return "symbol not found";
/*
* Original code from kevinm
* There seems to be a little bit of alignment padding
* between the data and sdata sections in elf32. That
* prevents us from directly seeking to an sdata symbol
* using the data section as a base. So if the symbol
* shows up within the sdata section, use sdata as the
* base for seeking in the file.
*/
if (addr < data_addr || addr >= data_addr + data_size) {
if (sdatascn) {
Elf64_Off sdata_offset = elf64_getshdr(sdatascn)->sh_offset;
Elf64_Addr sdata_addr = elf64_getshdr(sdatascn)->sh_addr;
Elf64_Word sdata_size = elf64_getshdr(sdatascn)->sh_size;
if (addr < sdata_addr || addr >= sdata_addr + sdata_size) {
Elf64_Addr bss_addr = bssscn ? elf64_getshdr(bssscn)->sh_addr : 0;
Elf64_Word bss_size = bssscn ? elf64_getshdr(bssscn)->sh_size : 0;
/*
Check if the value is in the bss ... if it is and
your setsym'ing the kernel - you need to turn
on the the special flag to make sure that the
variable(s) initialized to zero are placed in the
data section. Without the flag variables that
are initialized to zero will be placed in the bss.
*/
if (addr >= bss_addr && addr <= bss_addr + bss_size)
return "Initialized variable in bss ";
else
return "symbol not in sdata";
}
*offset = (addr - sdata_addr) + sdata_offset;
} else
return "symbol not in data";
} else
*offset = (addr - data_addr) + data_offset;
return NULL;
}
char *
find_sym_offset32(Elf *elf,
char *symname,
Elf32_Off *offset,
Elf_Scn *datascn,
Elf_Scn *sdatascn,
Elf_Scn *bssscn)
{
Elf32_Off data_offset;
Elf32_Addr data_addr;
Elf32_Word data_size;
Elf32_Addr addr;
data_offset = elf32_getshdr(datascn)->sh_offset;
data_addr = elf32_getshdr(datascn)->sh_addr;
data_size = elf32_getshdr(datascn)->sh_size;
if (sym_val32(elf, symname, &addr) != 0)
return "symbol not found";
if (addr < data_addr || addr >= data_addr + data_size) {
/* There seems to be a little bit of alignment padding
* between the data and sdata sections in elf32. That
* prevents us from directly seeking to an sdata symbol
* using the data section as a base. So if the symbol
* shows up within the sdata section, use sdata as the
* base for seeking in the file.
*/
if (sdatascn) {
Elf32_Off sdata_offset = elf32_getshdr(sdatascn)->sh_offset;
Elf32_Addr sdata_addr = elf32_getshdr(sdatascn)->sh_addr;
Elf32_Word sdata_size = elf32_getshdr(sdatascn)->sh_size;
if (addr < sdata_addr || addr >= sdata_addr + sdata_size)
return "symbol not in sdata";
*offset = (addr - sdata_addr) + sdata_offset;
} else
return "symbol not in data";
} else
*offset = (addr - data_addr) + data_offset;
return NULL;
}