1558 linhas
39 KiB
C++
1558 linhas
39 KiB
C++
/*
|
|
************************************************************************************************************************
|
|
*
|
|
* Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
|
|
*
|
|
***********************************************************************************************************************/
|
|
|
|
//
|
|
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
#include "elf.hpp"
|
|
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <string>
|
|
|
|
#if defined(__linux__)
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include "os/os.hpp"
|
|
#include "_libelf.h"
|
|
namespace amd {
|
|
|
|
using namespace oclelfutils;
|
|
|
|
#if !defined(ELFMAG)
|
|
#define ELFMAG "\177ELF"
|
|
#define SELFMAG 4
|
|
#endif
|
|
|
|
/*
|
|
Opague data type definition.
|
|
*/
|
|
struct symbol_handle {
|
|
union {
|
|
Elf64_Sym sym64;
|
|
Elf32_Sym sym32;
|
|
} u;
|
|
};
|
|
|
|
typedef struct {
|
|
OclElf::oclElfSections id;
|
|
const char *name;
|
|
Elf_Type d_type;
|
|
uint64_t d_align; // section alignment in bytes
|
|
Elf32_Word sh_type; // section type
|
|
Elf32_Word sh_flags; // section flags
|
|
const char *desc;
|
|
} OclElfSectionsDesc;
|
|
|
|
namespace {
|
|
// Objects that are visible only within this module
|
|
|
|
const OclElfSectionsDesc oclElfSecDesc[] =
|
|
{
|
|
{ OclElf::LLVMIR, ".llvmir", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"ASIC-independent LLVM IR" },
|
|
{ OclElf::SOURCE, ".source", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"OpenCL source" },
|
|
{ OclElf::ILTEXT, ".amdil", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"AMD IL text" },
|
|
{ OclElf::ASTEXT, ".astext", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"X86 assembly text" },
|
|
{ OclElf::CAL, ".text", ELF_T_BYTE, 1, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
|
|
"AMD CalImage" },
|
|
{ OclElf::DLL, ".text", ELF_T_BYTE, 1, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
|
|
"x86 dll" },
|
|
{ OclElf::STRTAB, ".strtab", ELF_T_BYTE, 1, SHT_STRTAB, SHF_STRINGS,
|
|
"String table" },
|
|
{ OclElf::SYMTAB, ".symtab", ELF_T_SYM, sizeof(Elf64_Xword), SHT_SYMTAB, 0,
|
|
"Symbol table" },
|
|
{ OclElf::RODATA, ".rodata", ELF_T_BYTE, 1, SHT_PROGBITS, SHF_ALLOC,
|
|
"Read-only data" },
|
|
{ OclElf::SHSTRTAB, ".shstrtab", ELF_T_BYTE, 1, SHT_STRTAB, SHF_STRINGS,
|
|
"Section names" },
|
|
{ OclElf::NOTES, ".note", ELF_T_NOTE, 1, SHT_NOTE, 0,
|
|
"used by loader for notes" },
|
|
{ OclElf::COMMENT, ".comment", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Version string" },
|
|
{ OclElf::ILDEBUG, ".debugil", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"AMD Debug IL" },
|
|
{ OclElf::DEBUG_INFO, ".debug_info", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug info" },
|
|
{ OclElf::DEBUG_ABBREV, ".debug_abbrev", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug abbrev" },
|
|
{ OclElf::DEBUG_LINE, ".debug_line", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug line" },
|
|
{ OclElf::DEBUG_PUBNAMES, ".debug_pubnames", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug pubnames" },
|
|
{ OclElf::DEBUG_PUBTYPES, ".debug_pubtypes", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug pubtypes" },
|
|
{ OclElf::DEBUG_LOC, ".debug_loc", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug loc" },
|
|
{ OclElf::DEBUG_ARANGES, ".debug_aranges", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug aranges" },
|
|
{ OclElf::DEBUG_RANGES, ".debug_ranges", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug ranges" },
|
|
{ OclElf::DEBUG_MACINFO, ".debug_macinfo", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug macinfo" },
|
|
{ OclElf::DEBUG_STR, ".debug_str", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug str" },
|
|
{ OclElf::DEBUG_FRAME, ".debug_frame", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Dwarf debug frame" },
|
|
{ OclElf::JITBINARY, ".text", ELF_T_BYTE, 1, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
|
|
"x86 JIT Binary" },
|
|
{ OclElf::CODEGEN, ".cg", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Target dependent IL" },
|
|
{ OclElf::TEXT, ".text", ELF_T_BYTE, 1, SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR,
|
|
"Device specific ISA" },
|
|
{ OclElf::INTERNAL, ".internal", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Internal usage" },
|
|
{ OclElf::SPIR, ".spir", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"Vendor/Device-independent LLVM IR" },
|
|
{ OclElf::SPIRV, ".spirv", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"SPIR-V Binary" },
|
|
{ OclElf::RUNTIME_METADATA,".AMDGPU.runtime_metadata", ELF_T_BYTE, 1, SHT_PROGBITS, 0,
|
|
"AMDGPU runtime metadata" },
|
|
};
|
|
|
|
// index 0 is reserved and must be there (NULL section)
|
|
const char shstrtab[] = {
|
|
/* index 0 */ '\0',
|
|
/* index 1 */ '.', 's', 'h', 's', 't', 'r', 't', 'a', 'b', '\0',
|
|
/* index 11 */ '.', 's', 't', 'r', 't', 'a', 'b', '\0'
|
|
};
|
|
|
|
#define SHSTRTAB_NAME_NDX 1
|
|
#define STRTAB_NAME_NDX 11
|
|
|
|
// index 0 is reserved and must be there (NULL name)
|
|
const char strtab[] = {
|
|
/* index 0 */ '\0'
|
|
};
|
|
|
|
}
|
|
|
|
bool
|
|
isElfMagic(const char* p)
|
|
{
|
|
if (p==NULL || strncmp(p, ELFMAG, SELFMAG) != 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//
|
|
bool
|
|
isElfHeader(const char* p, signed char ec)
|
|
{
|
|
if (!isElfMagic(p)) {
|
|
return false;
|
|
}
|
|
signed char libVersion = elf_version(EV_CURRENT);
|
|
signed char fileVersion = p[EI_VERSION];
|
|
signed char elfClass = p[EI_CLASS];
|
|
if( fileVersion > libVersion) {
|
|
return false;
|
|
}
|
|
|
|
// class check:
|
|
if ( elfClass != ec) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
isCALTarget(const char* p, signed char ec)
|
|
{
|
|
if (!isElfMagic(p)) {
|
|
return false;
|
|
}
|
|
|
|
Elf64_Half machine;
|
|
if (ec == ELFCLASS32) {
|
|
machine = ((Elf32_Ehdr*)p)->e_machine;
|
|
|
|
}
|
|
else {
|
|
machine = ((Elf64_Ehdr*)p)->e_machine;
|
|
}
|
|
|
|
#if !defined(WITH_LIGHTNING_COMPILER)
|
|
if ( (machine >= OclElf::CAL_FIRST) && (machine <= OclElf::CAL_LAST) ) {
|
|
return true;
|
|
}
|
|
#endif // !defined(WITH_LIGHTNING_COMPILER)
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
////////////////////// elf initializers ///////////////////////
|
|
///////////////////////////////////////////////////////////////
|
|
|
|
OclElf::OclElf (
|
|
unsigned char eclass,
|
|
const char* rawElfBytes,
|
|
uint64_t rawElfSize,
|
|
const char* elfFileName,
|
|
Elf_Cmd elfcmd
|
|
)
|
|
: _fd (-1),
|
|
_fname (elfFileName),
|
|
_e (0),
|
|
_err (),
|
|
_eclass (eclass),
|
|
_rawElfBytes (rawElfBytes),
|
|
_rawElfSize (rawElfSize),
|
|
_elfCmd (elfcmd),
|
|
_elfMemory(),
|
|
_shstrtab_ndx (0),
|
|
_strtab_ndx (0)
|
|
{
|
|
if (rawElfBytes != NULL) {
|
|
/*
|
|
In general, 'eclass' should be the same as rawElfBytes's. 'eclass' is what the runtime
|
|
will use for generating an ELF, and therefore it expects the input ELF to have this 'eclass'.
|
|
However, GPU needs to accept both 32-bit and 64-bit ELF for compatibility (we used to
|
|
generate 64-bit ELF, which is the bad design in the first place). Here we just uses eclass
|
|
from rawElfBytes, and overrides the input 'eclass'.
|
|
*/
|
|
_eclass = (unsigned char)rawElfBytes[EI_CLASS];
|
|
}
|
|
(void)Init();
|
|
}
|
|
|
|
OclElf::~OclElf()
|
|
{
|
|
#if 0
|
|
Elf_Cmd c = (_errCmd == ELF_C_READ) ? ELF_C_NULL : _errCmd;
|
|
if (elf_update(_e, c < 0) {
|
|
_err.xfail("OclElf::Fini() : elf_update() failed: %s", elf_errmsg(-1);
|
|
return;
|
|
}
|
|
#endif
|
|
_err.Fini();
|
|
|
|
elf_end(_e);
|
|
_e = 0;
|
|
|
|
if (_fd != -1) {
|
|
xclose(_err, _fname, _fd);
|
|
char* tname= const_cast<char*>(_fname);
|
|
if (tname) {
|
|
unlink(tname);
|
|
free(tname);
|
|
}
|
|
_fd = -1;
|
|
_fname = NULL;
|
|
|
|
}
|
|
|
|
elfMemoryRelease();
|
|
}
|
|
|
|
bool
|
|
OclElf::Clear()
|
|
{
|
|
if (_e) {
|
|
elf_end(_e);
|
|
_e = NULL;
|
|
}
|
|
|
|
if (_fd != -1) {
|
|
if (xclose(_err, _fname, _fd) < 0) {
|
|
return false;
|
|
}
|
|
_fd = -1;
|
|
}
|
|
|
|
elfMemoryRelease();
|
|
|
|
_err.Fini();
|
|
|
|
// Re-initialize the object
|
|
Init();
|
|
|
|
return !hasError();
|
|
}
|
|
|
|
/*
|
|
Initialize OclElf object
|
|
*/
|
|
bool
|
|
OclElf::Init()
|
|
{
|
|
_err.Init();
|
|
|
|
// Create a temporary file if it is needed
|
|
if (_elfCmd != ELF_C_READ) {
|
|
if (_fname != NULL) {
|
|
size_t sz = strlen(_fname) + 1;
|
|
|
|
char* tname = (char*)xmalloc(_err, sz);
|
|
if (tname == 0) {
|
|
_err.xfail("OclElf::Init() failed to malloc()");
|
|
return false;
|
|
}
|
|
strcpy(tname, _fname);
|
|
_fname = static_cast<const char*>(tname);
|
|
}
|
|
}
|
|
|
|
if (elf_version(EV_CURRENT) == EV_NONE) {
|
|
_err.xfail("OclElf::Init(): Application expects CURRENT elf version");
|
|
return false;
|
|
}
|
|
int oflag, pmode;
|
|
#if defined(_MSC_VER)
|
|
if (_elfCmd == ELF_C_READ) {
|
|
oflag = _O_RDONLY | _O_BINARY;
|
|
}
|
|
else {
|
|
oflag = _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY;
|
|
}
|
|
pmode = _S_IREAD | _S_IWRITE;
|
|
#else
|
|
if (_elfCmd == ELF_C_READ) {
|
|
oflag = O_RDONLY;
|
|
}
|
|
else {
|
|
oflag = O_CREAT | O_RDWR | O_TRUNC;
|
|
}
|
|
pmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 0644
|
|
#endif
|
|
if ((_fd == -1) && (_rawElfBytes == NULL)) {
|
|
// case 1: elf object is in file '_fname'
|
|
|
|
_fd = xopen(_err, _fname, oflag, pmode);
|
|
if (_fd == -1) {
|
|
_err.xfail("OclElf::Init(): Cannot Open File %s!", _fname);
|
|
return false;
|
|
}
|
|
|
|
_e = elf_begin(_fd, _elfCmd, NULL, NULL);
|
|
if (_e == NULL) {
|
|
_err.xfail ("OclElf::Init(): elf_begin failed");
|
|
return false;
|
|
}
|
|
}
|
|
else if (_fd == -1) {
|
|
// case 2: elf object is in memory
|
|
if (_elfCmd == ELF_C_READ) {
|
|
assert ((_fname == NULL) && "ELF file name should not be provided for a read only elf.");
|
|
} else {
|
|
_fd = xopen(_err, _fname, oflag, pmode);
|
|
if (_fd == -1) {
|
|
_err.xfail("OclElf::Init(): Cannot Open File %s!", _fname);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// const_cast is safe
|
|
_e = elf_memory(const_cast<char*>(_rawElfBytes), _rawElfSize, NULL);
|
|
if ( _e == NULL) {
|
|
_err.xfail("OclElf::Init(): elf_memory failed: %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
// If _fd != -1, then we are a read/write and not just a read, so change accordingly.
|
|
if (_fd != -1) {
|
|
_e->e_fd = _fd;
|
|
_e->e_cmd = _elfCmd;
|
|
}
|
|
}
|
|
else { // _fd != -1
|
|
// case 3: elf object is in a file with file descriptor '_fd'
|
|
|
|
_e = elf_begin(_fd, _elfCmd, NULL, NULL);
|
|
if (_e == NULL) {
|
|
_err.xfail ("OclElf::Init(): elf_begin failed: %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!InitElf()) {
|
|
return false;
|
|
}
|
|
|
|
// Success
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Return true: if InitElf() is successful
|
|
Return false: if InitElf() failed.
|
|
*/
|
|
bool
|
|
OclElf::InitElf ()
|
|
{
|
|
assert (_e && "libelf object should have been created already");
|
|
|
|
if (_elfCmd != ELF_C_WRITE) {
|
|
// Set up _shstrtab_ndx and _strtab_ndx
|
|
GElf_Ehdr gehdr;
|
|
if (gelf_getehdr(_e, &gehdr) == NULL) {
|
|
_err.xfail("OclElf::InitElf() failed in gelf_getehdr()- %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
_shstrtab_ndx = gehdr.e_shstrndx;
|
|
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, STRTAB)) {
|
|
_err.xfail("OclElf::InitElf() failed in getSectionDesc(STRTAB)");
|
|
return false;
|
|
}
|
|
|
|
// Sanity check. Each ELF binary should have STRTAB !
|
|
if (scn != NULL) {
|
|
_strtab_ndx = elf_ndxscn(scn);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*********************************/
|
|
/******** ELF_C_WRITE ************/
|
|
/*********************************/
|
|
|
|
//
|
|
// 1. Create ELF header
|
|
//
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Ehdr* ehdr32 = elf32_newehdr(_e);
|
|
if (ehdr32 == NULL) {
|
|
_err.xfail("OclElf::InitElf() failed in elf32_newehdr: %s.",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
Elf64_Ehdr* ehdr64 = elf64_newehdr(_e);
|
|
if (ehdr64 == NULL) {
|
|
_err.xfail("OclElf::InitElf() failed in elf32_newehdr : %s.",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("elf_update() failed");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// 2. Create ELF shstrtab
|
|
//
|
|
Elf_Scn* scn_shstrtab = elf_newscn(_e);
|
|
if (scn_shstrtab == NULL) {
|
|
_err.xfail("Elf::InitElf() failed in elf_newscn : %s", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
/* addng ELF_Data descriptor associated with section scn */
|
|
Elf_Data* data_shstrtab = createElfData(scn_shstrtab, SHSTRTAB,
|
|
const_cast<char*>(shstrtab), (uint64_t)sizeof(shstrtab), false);
|
|
if (data_shstrtab == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (!createShdr(SHSTRTAB, scn_shstrtab, SHSTRTAB_NAME_NDX)) {
|
|
return false;
|
|
}
|
|
|
|
// Save shstrtab section index
|
|
_shstrtab_ndx = elf_ndxscn(scn_shstrtab);
|
|
#if defined(BSD_LIBELF)
|
|
elf_setshstrndx(_e, _shstrtab_ndx);
|
|
#else
|
|
elfx_update_shstrndx(_e, _shstrtab_ndx);
|
|
#endif
|
|
|
|
#if 0
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("elf_update() failed");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// 3. Create .strtab section
|
|
//
|
|
Elf_Scn* scn_strtab = elf_newscn(_e);
|
|
if (scn_strtab == NULL) {
|
|
_err.xfail("Elf::InitElf() failed in elf_newscn : %s", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
/* addng ELF_Data descriptor associated with section scn */
|
|
Elf_Data* data_strtab = createElfData(scn_strtab, STRTAB,
|
|
const_cast<char*>(strtab), (uint64_t)sizeof(strtab), false);
|
|
if (data_strtab == NULL) {
|
|
return false;
|
|
}
|
|
|
|
if (!createShdr(STRTAB, scn_strtab, STRTAB_NAME_NDX)) {
|
|
return false;
|
|
}
|
|
|
|
// Save strtab section index
|
|
_strtab_ndx = elf_ndxscn(scn_strtab);
|
|
|
|
// Need to update section header
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("elf_update() failed");
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// 4. Create the symbol table
|
|
//
|
|
|
|
// Create the first reserved symbol (undefined symbol)
|
|
size_t sym_sz = (_eclass == ELFCLASS32) ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym);
|
|
void* sym = oclelf_calloc(sym_sz);
|
|
if (sym == NULL) {
|
|
_err.xfail("OclElf::InitElf() failed to alloc memory");
|
|
return false;
|
|
}
|
|
|
|
Elf_Scn* scn_symtab = newSection(SYMTAB, sym, sym_sz, false);
|
|
if (scn_symtab == NULL) {
|
|
// Use newSection()'s error message.
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Elf_Data*
|
|
OclElf::createElfData(
|
|
Elf_Scn*& scn,
|
|
oclElfSections id,
|
|
void* d_buf,
|
|
uint64_t d_size,
|
|
bool do_copy
|
|
)
|
|
{
|
|
/* addng Elf_Data descriptor associated with section scn */
|
|
Elf_Data* data = elf_newdata(scn);
|
|
if (data == NULL) {
|
|
_err.xfail("OclElf::createElfData() failed in elf_newdata() - %s",
|
|
elf_errmsg(-1));
|
|
return NULL;
|
|
}
|
|
|
|
void* newbuf;
|
|
if (do_copy) {
|
|
newbuf = oclelf_allocAndCopy((void*)d_buf, d_size);
|
|
}
|
|
else {
|
|
newbuf = d_buf;
|
|
}
|
|
|
|
data->d_align = oclElfSecDesc[id].d_align;
|
|
data->d_off = 0LL;
|
|
data->d_buf = newbuf;
|
|
data->d_type = oclElfSecDesc[id].d_type;
|
|
data->d_size = d_size;
|
|
data->d_version = EV_CURRENT ;
|
|
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("elf_update() failed");
|
|
return NULL;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
bool
|
|
OclElf::createShdr (
|
|
oclElfSections id,
|
|
Elf_Scn*& scn,
|
|
Elf64_Word shname,
|
|
Elf64_Word shlink
|
|
)
|
|
{
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Shdr* shdr32 = elf32_getshdr(scn);
|
|
if (shdr32 == NULL) {
|
|
_err.xfail("Elf::createShdr() failed in elf32_getshdr(): %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
shdr32->sh_name = (Elf32_Word)shname;
|
|
shdr32->sh_type = (Elf32_Word)oclElfSecDesc[id].sh_type;
|
|
shdr32->sh_flags = (Elf32_Word)oclElfSecDesc[id].sh_flags;
|
|
|
|
shdr32->sh_link = (Elf32_Word)shlink;
|
|
}
|
|
else {
|
|
Elf64_Shdr* shdr64 = elf64_getshdr(scn);
|
|
if (shdr64 == NULL) {
|
|
_err.xfail("Elf::InitElf() failed in elf64_getshdr(): %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
shdr64->sh_name = (Elf64_Word)shname;
|
|
shdr64->sh_type = (Elf64_Word)oclElfSecDesc[id].sh_type;
|
|
shdr64->sh_flags = (Elf64_Xword)oclElfSecDesc[id].sh_flags;
|
|
|
|
shdr64->sh_link = (Elf64_Word)shlink;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::getTarget(uint16_t& machine, oclElfPlatform& platform)
|
|
{
|
|
assert(_e != 0);
|
|
|
|
GElf_Ehdr ehdrO;
|
|
GElf_Ehdr *ehdr = gelf_getehdr(_e, &ehdrO);
|
|
if (ehdr == NULL) {
|
|
return false;
|
|
}
|
|
|
|
Elf64_Half mach = ehdr->e_machine;
|
|
if ((mach >= CPU_FIRST) && (mach <= CPU_LAST)) {
|
|
platform = CPU_PLATFORM;
|
|
machine = mach - CPU_BASE;
|
|
}
|
|
#if !defined(WITH_LIGHTNING_COMPILER)
|
|
else if ( (mach >= CAL_FIRST) && (mach <= CAL_LAST)) {
|
|
platform = CAL_PLATFORM;
|
|
machine = mach - CAL_BASE;
|
|
}
|
|
#endif // !defined(WITH_LIGHTNING_COMPILER)
|
|
else if (mach == EM_386
|
|
|| mach == EM_HSAIL
|
|
|| mach == EM_HSAIL_64
|
|
|| mach == EM_AMDIL
|
|
|| mach == EM_AMDIL_64
|
|
|| mach == EM_X86_64) {
|
|
platform = COMPLIB_PLATFORM;
|
|
machine = mach;
|
|
} else {
|
|
// Invalid machine
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::setTarget(uint16_t machine, oclElfPlatform platform)
|
|
{
|
|
assert(_e != 0);
|
|
|
|
Elf64_Half mach;
|
|
if (platform == CPU_PLATFORM)
|
|
mach = machine + CPU_BASE;
|
|
else if (platform == CAL_PLATFORM)
|
|
mach = machine + CAL_BASE;
|
|
else
|
|
mach = machine;
|
|
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Ehdr* ehdr32 = elf32_getehdr(_e);
|
|
|
|
if (ehdr32 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf32_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
ehdr32->e_ident[EI_DATA] = ELFDATA2LSB;
|
|
ehdr32->e_type = ET_NONE;
|
|
ehdr32->e_machine = (Elf32_Half)mach;
|
|
}
|
|
else {
|
|
Elf64_Ehdr* ehdr64 = elf64_getehdr(_e);
|
|
|
|
if (ehdr64 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf64_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
ehdr64->e_ident[EI_DATA] = ELFDATA2LSB;
|
|
ehdr64->e_type = ET_NONE;
|
|
ehdr64->e_machine = mach;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::getType(uint16_t &type) {
|
|
assert(_e != 0);
|
|
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Ehdr* ehdr32 = elf32_getehdr(_e);
|
|
|
|
if (ehdr32 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf32_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
type = ehdr32->e_type;
|
|
}
|
|
else {
|
|
Elf64_Ehdr* ehdr64 = elf64_getehdr(_e);
|
|
|
|
if (ehdr64 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf64_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
type = ehdr64->e_type;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::setType(uint16_t type) {
|
|
assert(_e != 0);
|
|
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Ehdr* ehdr32 = elf32_getehdr(_e);
|
|
|
|
if (ehdr32 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf32_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
ehdr32->e_type = type;
|
|
}
|
|
else {
|
|
Elf64_Ehdr* ehdr64 = elf64_getehdr(_e);
|
|
|
|
if (ehdr64 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf64_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
ehdr64->e_type = type;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::getFlags(uint32_t &flag) {
|
|
assert(_e != 0);
|
|
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Ehdr* ehdr32 = elf32_getehdr(_e);
|
|
|
|
if (ehdr32 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf32_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
flag = ehdr32->e_flags;
|
|
}
|
|
else {
|
|
Elf64_Ehdr* ehdr64 = elf64_getehdr(_e);
|
|
|
|
if (ehdr64 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf64_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
flag = ehdr64->e_flags;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::setFlags(uint32_t flag) {
|
|
assert(_e != 0);
|
|
|
|
if (_eclass == ELFCLASS32) {
|
|
Elf32_Ehdr* ehdr32 = elf32_getehdr(_e);
|
|
|
|
if (ehdr32 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf32_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
ehdr32->e_flags = flag;
|
|
}
|
|
else {
|
|
Elf64_Ehdr* ehdr64 = elf64_getehdr(_e);
|
|
|
|
if (ehdr64 == NULL) {
|
|
_err.xfail("setTarget() : failed in elf64_getehdr()- %s.", elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
ehdr64->e_flags = flag;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
returns true if success; return false if fail.
|
|
scn will return scn for 'id'.
|
|
*/
|
|
bool
|
|
OclElf::getSectionDesc(Elf_Scn*& scn, OclElf::oclElfSections id) const
|
|
{
|
|
if ( ((id == SHSTRTAB) && (_shstrtab_ndx != 0)) ||
|
|
((id == STRTAB) && (_strtab_ndx != 0)) ) {
|
|
// Special (efficient) processing of SHSTRTAB/STRTAB
|
|
size_t idx = (id == SHSTRTAB) ? _shstrtab_ndx : _strtab_ndx;
|
|
if ((scn = elf_getscn(_e, idx)) == NULL) {
|
|
_err.xfail("OclElf::addSectionDesc(): elf_getscn() failed - %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
/* Search sections */
|
|
const char* sname = oclElfSecDesc[id].name;
|
|
for (scn = elf_nextscn(_e, 0);
|
|
scn != NULL;
|
|
scn = elf_nextscn(_e, scn))
|
|
{
|
|
size_t idx = elf_ndxscn(scn);
|
|
if ( ((idx == _shstrtab_ndx) && (_shstrtab_ndx != 0)) ||
|
|
((idx == _strtab_ndx) && (_strtab_ndx != 0)) ) {
|
|
continue;
|
|
}
|
|
|
|
GElf_Shdr shdr;
|
|
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
|
_err.xfail("OclElf::getSectionDesc() : failed in gelf_getshdr()- %s.",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
/* Convert an index (to the shdr string table) to a char pointer */
|
|
char *nm = elf_strptr(_e, _shstrtab_ndx, shdr.sh_name);
|
|
if (strcmp(sname, nm ? nm : "") == 0) {
|
|
// Found !
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Return true if success; return false if fail.
|
|
data will return Elf_Data.
|
|
*/
|
|
bool
|
|
OclElf::getSectionData(Elf_Data*& data, OclElf::oclElfSections id) const
|
|
{
|
|
assert(_e != 0);
|
|
|
|
data = NULL;
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, id)) {
|
|
return false;
|
|
}
|
|
if (scn != NULL) {
|
|
// There is only one data descriptor (we are reading!)
|
|
data = elf_getdata(scn, 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Get the whole section, assuming that there is only one data descriptor
|
|
*/
|
|
bool
|
|
OclElf::getSection(OclElf::oclElfSections id, char** dst, size_t* sz) const
|
|
{
|
|
assert((oclElfSecDesc[id].id == id) &&
|
|
"oclElfSecDesc[] should be in the same order as enum oclElfSections");
|
|
|
|
Elf_Data* data;
|
|
if (!getSectionData(data, id)) {
|
|
_err.xfail("OclElf::getSection() failed in getSectionData()");
|
|
return false;
|
|
}
|
|
if (data == NULL) {
|
|
*dst = NULL;
|
|
*sz = 0;
|
|
}
|
|
else {
|
|
*sz = (size_t)data->d_size;
|
|
*dst = (char*)data->d_buf;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
API routines for manipulating symbols
|
|
*/
|
|
Sym_Handle
|
|
OclElf::nextSymbol(Sym_Handle symHandle) const
|
|
{
|
|
size_t sz;
|
|
char* beg, *end;
|
|
|
|
if (!getSection(SYMTAB, &beg, &sz)) {
|
|
_err.xfail("OclElf::nextSymbol() failed in getSection()");
|
|
return NULL;
|
|
}
|
|
|
|
if ( (beg == 0) || (sz == 0) ) {
|
|
return NULL;
|
|
}
|
|
|
|
end = beg + sz;
|
|
if (_eclass == ELFCLASS64) {
|
|
// Skip the first dummy symbol (STT_NOTYPE)
|
|
beg += sizeof(Elf64_Sym);
|
|
|
|
if (beg == end) { // No valid symbols in the table
|
|
return NULL;
|
|
}
|
|
|
|
if (symHandle == NULL) {
|
|
// Return the first symbol
|
|
return reinterpret_cast<Sym_Handle>(beg);
|
|
}
|
|
|
|
// Return the next symbol
|
|
Elf64_Sym* sym64 = reinterpret_cast<Elf64_Sym*>(symHandle);
|
|
sym64++;
|
|
if (reinterpret_cast<char*>(sym64) == end) {
|
|
return NULL;
|
|
}
|
|
return reinterpret_cast<Sym_Handle>(sym64);
|
|
}
|
|
else {
|
|
// Skip the first dummy symbol (STT_NOTYPE)
|
|
beg += sizeof(Elf32_Sym);
|
|
|
|
if (beg == end) { // No valid symbols in the table
|
|
return NULL;
|
|
}
|
|
|
|
if (symHandle == NULL) {
|
|
// Return the first symbol
|
|
return reinterpret_cast<Sym_Handle>(beg);
|
|
}
|
|
|
|
Elf32_Sym* sym32 = reinterpret_cast<Elf32_Sym*>(symHandle);
|
|
sym32++;
|
|
if (reinterpret_cast<char*>(sym32) == end) {
|
|
return NULL;
|
|
}
|
|
return reinterpret_cast<Sym_Handle>(sym32);
|
|
}
|
|
|
|
// UNREACHABLE
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
Given a symbol handle, return info for this symbol
|
|
|
|
Fails with symbols which have special section indexes (like absolute symbols).
|
|
It is impossible to return valid SymbolInfo for such symbols because
|
|
correct section names are unknown (unspecified in ELF).
|
|
*/
|
|
bool
|
|
OclElf::getSymbolInfo(Sym_Handle symHandle, SymbolInfo* symInfo) const
|
|
{
|
|
assert(_e != 0);
|
|
|
|
Elf_Scn *scn;
|
|
char* sym_name;
|
|
Elf64_Addr st_value; /* visibility */
|
|
Elf64_Xword st_size; /* index of related section */
|
|
|
|
if (_eclass == ELFCLASS64) {
|
|
Elf64_Sym* sym64 = reinterpret_cast<Elf64_Sym*>(symHandle);
|
|
if (sym64->st_shndx >= SHN_LORESERVE && sym64->st_shndx <= SHN_HIRESERVE) {
|
|
return false;
|
|
}
|
|
|
|
sym_name = elf_strptr(_e, _strtab_ndx, sym64->st_name);
|
|
st_value = (Elf64_Addr)(sym64->st_value);
|
|
st_size = (Elf64_Xword)(sym64->st_size);
|
|
|
|
// get section
|
|
scn = elf_getscn(_e, sym64->st_shndx);
|
|
}
|
|
else {
|
|
Elf32_Sym* sym32 = reinterpret_cast<Elf32_Sym*>(symHandle);
|
|
if (sym32->st_shndx >= SHN_LORESERVE && sym32->st_shndx <= SHN_HIRESERVE) {
|
|
return false;
|
|
}
|
|
|
|
sym_name = elf_strptr(_e, _strtab_ndx, sym32->st_name);
|
|
st_value = (Elf64_Addr)(sym32->st_value);
|
|
st_size = (Elf64_Xword)(sym32->st_size);
|
|
|
|
// get section
|
|
scn = elf_getscn(_e, sym32->st_shndx);
|
|
}
|
|
|
|
GElf_Shdr gshdr;
|
|
if (gelf_getshdr(scn, &gshdr) == NULL) {
|
|
_err.xfail("OclElf::getSymbolInfo() failed in gelf_getshdr() - %s.",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
char* sec_name = elf_strptr(_e, _shstrtab_ndx, gshdr.sh_name);
|
|
|
|
// Assume there is only one Elf_Data. For reading, it's always true
|
|
Elf_Data* data = elf_getdata(scn, 0);
|
|
if (data == NULL) {
|
|
symInfo->sec_addr = (char*)NULL;
|
|
symInfo->sec_size = 0;
|
|
symInfo->address = (char*)NULL;
|
|
symInfo->size = (uint64_t)0;
|
|
}
|
|
else {
|
|
symInfo->sec_addr = (char*)data->d_buf;
|
|
symInfo->sec_size = data->d_size;
|
|
symInfo->address = symInfo->sec_addr + (size_t)st_value;
|
|
symInfo->size = (uint64_t)st_size;
|
|
}
|
|
symInfo->sec_name = sec_name;
|
|
symInfo->sym_name = sym_name;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
AddSectionData() will add data into a section. Return the offset
|
|
of the data in this section if success; return -1 if fail.
|
|
*/
|
|
bool
|
|
OclElf::addSectionData (
|
|
Elf64_Xword& outOffset,
|
|
oclElfSections id,
|
|
const void* buffer,
|
|
size_t size,
|
|
bool do_copy // true if buffer needs to be copied
|
|
)
|
|
{
|
|
outOffset = 0;
|
|
const char* secName = oclElfSecDesc[id].name;
|
|
GElf_Shdr shdr;
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, id)) {
|
|
return false;
|
|
}
|
|
assert (scn && "Elf_Scn should have been created already");
|
|
|
|
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
|
_err.xfail("OclElf::addSectionData(): gelf_getshdr() failed - %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
outOffset = (Elf64_Xword)shdr.sh_size;
|
|
|
|
/* addng Elf_Data descriptor associated with section scn */
|
|
Elf_Data* data = createElfData(scn, id, const_cast<void*>(buffer),
|
|
(uint64_t)size, do_copy);
|
|
if (data == NULL) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
getShdrNdx() returns an index to the .shstrtab in 'outNdx' for "name" if it
|
|
is in .shstrtab (outNdx == 0 means it is not in .shstrtab). It return true if
|
|
it is successful; return false if en error occured.
|
|
*/
|
|
bool
|
|
OclElf::getShstrtabNdx(Elf64_Word& outNdx, const char* name)
|
|
{
|
|
outNdx = 0;
|
|
|
|
// .shstrtab must be created already
|
|
Elf_Scn* scn = elf_getscn(_e, _shstrtab_ndx);
|
|
if (scn == NULL) {
|
|
_err.xfail("OclElf::getShdrNdx() failed in elf_getscn for section .shstrtab - %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
Elf_Data* data = elf_getdata(scn, NULL);
|
|
if (data == NULL) {
|
|
_err.xfail("Elf::getShdrNdx() failed in elf_getdata for section .shstrtab - %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
size_t name_sz = strlen(name);
|
|
uint64_t data_offset = 0;
|
|
do {
|
|
if (data->d_size > name_sz) {
|
|
char* base = (char*)data->d_buf;
|
|
char* end = base + (size_t)data->d_size;
|
|
char* b = base;
|
|
char* e;
|
|
|
|
while ( b != end) {
|
|
e = b;
|
|
|
|
// find the next 0 char
|
|
while ( (e != end) && (*e != 0) ) {
|
|
e++;
|
|
}
|
|
|
|
if ((e != end) && ((size_t)(e - b) == name_sz) &&
|
|
(strcmp(b, name) == 0)) {
|
|
outNdx = (Elf64_Word)((b - base) + data_offset);
|
|
return true;
|
|
}
|
|
b = e+1;
|
|
}
|
|
}
|
|
data_offset += data->d_size;
|
|
} while ((data = elf_getdata(scn, data)) != NULL);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
newSection() assumes that .shstrtab and .strtab have been created already.
|
|
Return the pointer to the new section if success; return 0 if fail.
|
|
*/
|
|
Elf_Scn*
|
|
OclElf::newSection (
|
|
OclElf::oclElfSections id,
|
|
const void* d_buf,
|
|
size_t d_size,
|
|
bool do_copy
|
|
)
|
|
{
|
|
Elf64_Word sh_name;
|
|
if (!getShstrtabNdx(sh_name, oclElfSecDesc[id].name)) {
|
|
_err.xfail("OclElf::newSection() failed in getShstrtabNdx() for section %s",
|
|
oclElfSecDesc[id].name);
|
|
return NULL;
|
|
}
|
|
|
|
if (sh_name == 0) { // Need to create a new entry for this section name
|
|
Elf64_Xword offset;
|
|
if (!addSectionData(offset, SHSTRTAB, oclElfSecDesc[id].name,
|
|
strlen(oclElfSecDesc[id].name) + 1, false)) {
|
|
_err.xfail("OclElf::newSection() failed in getSectionData() for section %s",
|
|
oclElfSecDesc[id].name);
|
|
return NULL;
|
|
}
|
|
sh_name = (Elf64_Word)offset;
|
|
}
|
|
|
|
// Create a new section
|
|
Elf_Scn* scn = elf_newscn(_e);
|
|
if (scn == NULL) {
|
|
_err.xfail("OclElf::newSection() failed in elf_newscn() - %s.",
|
|
elf_errmsg(-1));
|
|
return NULL;
|
|
}
|
|
|
|
// If there is no data, skip creating Elf_Data
|
|
if ((d_buf != NULL) && (d_size != 0)) {
|
|
Elf_Data* data = createElfData(scn, id,
|
|
const_cast<void*>(d_buf), (uint64_t)d_size, do_copy);
|
|
if (data == NULL) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (!createShdr(id, scn, sh_name, (id == SYMTAB) ? _strtab_ndx : 0)) {
|
|
return NULL;
|
|
}
|
|
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("OclElf::newSection(): elf_update() failed");
|
|
return NULL;
|
|
}
|
|
|
|
return scn;
|
|
}
|
|
|
|
/*
|
|
Return true: success
|
|
false: fail
|
|
*/
|
|
bool
|
|
OclElf::addSection (
|
|
oclElfSections id,
|
|
const void* d_buf,
|
|
size_t d_size,
|
|
bool do_copy
|
|
)
|
|
{
|
|
assert(oclElfSecDesc[id].id == id &&
|
|
"struct oclElfSecDesc should be ordered by id same as enum Elf::oclElfSections");
|
|
|
|
/* If section is already in elf object, simply return its address */
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, id)) {
|
|
// Failed
|
|
return false;
|
|
}
|
|
|
|
if (scn != NULL) {
|
|
Elf64_Xword sec_offset;
|
|
if (!addSectionData(sec_offset, id, d_buf, d_size, do_copy)) {
|
|
_err.xfail("OclElf::addSection() failed in addSectionData() for section name %s.",
|
|
oclElfSecDesc[id].name);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
scn = newSection(id, d_buf, d_size, do_copy);
|
|
if (scn == NULL) {
|
|
_err.xfail("OclElf::addSection() failed in newSection() for section name %s.",
|
|
oclElfSecDesc[id].name);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::addSymbol(
|
|
oclElfSections id,
|
|
const char* symbolName,
|
|
const void* buffer,
|
|
size_t size,
|
|
bool do_copy
|
|
)
|
|
{
|
|
assert(oclElfSecDesc[id].id == id &&
|
|
"The order of oclElfSecDesc[] and Elf::oclElfSections mismatches.");
|
|
|
|
const char* sectionName = oclElfSecDesc[id].name;
|
|
|
|
bool isFunction = ((id == OclElf::CAL) || (id == OclElf::DLL) || (id == OclElf::JITBINARY)) ? true : false;
|
|
|
|
// Get section index
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, id)) {
|
|
_err.xfail("OclElf::addSymbol() failed in getSectionDesc");
|
|
return false;
|
|
}
|
|
if (scn == NULL) {
|
|
// Create a new section.
|
|
if ((scn = newSection(id, NULL, 0, false)) == NULL) {
|
|
_err.xfail("OclElf::addSymbol() failed in newSection");
|
|
return false;
|
|
}
|
|
}
|
|
size_t sec_ndx = elf_ndxscn(scn);
|
|
if (sec_ndx == SHN_UNDEF) {
|
|
_err.xfail("OclElf::addSymbol() failed in elf_ndxscn() - %s.",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
// Put symbolName into .strtab section
|
|
Elf64_Xword strtab_offset;
|
|
if (!addSectionData(strtab_offset, STRTAB, (void*)symbolName,
|
|
strlen(symbolName)+1, true)) {
|
|
_err.xfail("OclElf::addSymbol() failed in addSectionData(.strtab)");
|
|
return false;
|
|
}
|
|
|
|
// Put buffer into section
|
|
Elf64_Xword sec_offset = 0;
|
|
if ( (buffer != NULL) && (size != 0) ) {
|
|
if (!addSectionData(sec_offset, id, buffer, size, do_copy)) {
|
|
_err.xfail("OclElf::addSymbol() failed in addSectionData(%s)", sectionName);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool retvalue;
|
|
Elf64_Xword symtab_offset;
|
|
if (_eclass == ELFCLASS64) {
|
|
Elf64_Sym* sym64 = (Elf64_Sym*)oclelf_calloc(sizeof(Elf64_Sym));
|
|
|
|
sym64->st_name = (Elf64_Word)strtab_offset;
|
|
sym64->st_value = (Elf64_Addr)sec_offset;
|
|
sym64->st_size = (Elf64_Xword)size;
|
|
sym64->st_info = (isFunction)? STT_FUNC : STT_OBJECT;
|
|
sym64->st_shndx = (Elf64_Section)sec_ndx;
|
|
|
|
retvalue = addSectionData(symtab_offset, SYMTAB, sym64, sizeof(Elf64_Sym), false);
|
|
}
|
|
else { // _eclass == ELFCLASS32
|
|
Elf32_Sym* sym32 = (Elf32_Sym*)oclelf_calloc(sizeof(Elf32_Sym));
|
|
|
|
sym32->st_name = (Elf32_Word)strtab_offset;
|
|
sym32->st_value = (Elf32_Addr)sec_offset;
|
|
sym32->st_size = (Elf32_Word)size;
|
|
sym32->st_info = (isFunction)? STT_FUNC : STT_OBJECT;
|
|
sym32->st_shndx = (Elf32_Section)sec_ndx;
|
|
|
|
retvalue = addSectionData(symtab_offset, SYMTAB, sym32, sizeof(Elf32_Sym), false);
|
|
}
|
|
|
|
if (!retvalue) {
|
|
_err.xfail("OclElf::addSymbol() failed in addSectionData(.symtab)");
|
|
return false;
|
|
}
|
|
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("OclElf::addSymbol() : elf_update() failed");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::getSymbol(
|
|
oclElfSections id,
|
|
const char* symbolName,
|
|
char** buffer,
|
|
size_t* size
|
|
) const
|
|
{
|
|
assert(oclElfSecDesc[id].id == id &&
|
|
"The order of oclElfSecDesc[] and Elf::oclElfSections mismatches.");
|
|
if (!size || !buffer || !symbolName) {
|
|
return false;
|
|
}
|
|
// Initialize the size and buffer to invalid data points.
|
|
(*size) = 0;
|
|
(*buffer) = NULL;
|
|
for (amd::Sym_Handle s = nextSymbol(NULL); s; s = nextSymbol(s)) {
|
|
amd::OclElf::SymbolInfo si;
|
|
// Continue if symbol information is not retrieved.
|
|
if (!getSymbolInfo(s, &si)) {
|
|
continue;
|
|
}
|
|
// Continue if the symbol is in the wrong section.
|
|
if (strcmp(oclElfSecDesc[id].name, si.sec_name)) {
|
|
continue;
|
|
}
|
|
// Continue if the symbol name doesn't match.
|
|
if (strcmp(symbolName, si.sym_name)) {
|
|
continue;
|
|
}
|
|
// Set the size and the address and return true.
|
|
(*size) = si.size;
|
|
(*buffer) = si.address;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
OclElf::addNote(
|
|
const char* noteName,
|
|
const char* noteDesc,
|
|
size_t nameSize,
|
|
size_t descSize
|
|
)
|
|
{
|
|
if ((nameSize == 0 && descSize == 0)
|
|
|| (nameSize != 0 && noteName == NULL)
|
|
|| (descSize != 0 && noteDesc == NULL)) {
|
|
_err.xfail("OclElf::addNote() empty note");
|
|
return false;
|
|
}
|
|
|
|
const oclElfSections sid = NOTES;
|
|
assert(oclElfSecDesc[sid].id == sid &&
|
|
"The order of oclElfSecDesc[] and Elf::oclElfSections mismatches.");
|
|
|
|
// Get section
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, sid)) {
|
|
_err.xfail("OclElf::addNote() failed in getSectionDesc");
|
|
return false;
|
|
}
|
|
if (scn == NULL) {
|
|
// Create a new section.
|
|
if ((scn = newSection(sid, NULL, 0, false)) == NULL) {
|
|
_err.xfail("OclElf::addNote() failed in newSection");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Put note into section
|
|
Elf64_Xword sec_offset = 0;
|
|
size_t bufsize = sizeof(Elf_Note) + nameSize + descSize;
|
|
char* buffer = (char*)oclelf_calloc(bufsize);
|
|
if (buffer == NULL) return false;
|
|
|
|
Elf_Note* en = reinterpret_cast<Elf_Note*>(buffer);
|
|
en->n_namesz = nameSize;
|
|
en->n_descsz = descSize;
|
|
en->n_type = 0;
|
|
memcpy(buffer+sizeof(Elf_Note), noteName, nameSize);
|
|
memcpy(buffer+sizeof(Elf_Note)+nameSize, noteDesc, descSize);
|
|
if (!addSectionData(sec_offset, sid, buffer, bufsize, false/*not copy*/)) {
|
|
const char* sectionName = oclElfSecDesc[sid].name;
|
|
_err.xfail("OclElf::addNote() failed in addSectionData(%s)", sectionName);
|
|
return false;
|
|
}
|
|
|
|
if (elf_update(_e, ELF_C_NULL) < 0) {
|
|
_err.xfail("OclElf::addNote() : elf_update() failed");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
OclElf::getNote(
|
|
const char* noteName,
|
|
char** noteDesc,
|
|
size_t *descSize
|
|
)
|
|
{
|
|
if (!descSize || !noteDesc || !noteName) {
|
|
return false;
|
|
}
|
|
|
|
const oclElfSections sid = NOTES;
|
|
assert(oclElfSecDesc[sid].id == sid &&
|
|
"The order of oclElfSecDesc[] and Elf::oclElfSections mismatches.");
|
|
|
|
// Get section
|
|
Elf_Scn* scn;
|
|
if (!getSectionDesc(scn, sid)) {
|
|
_err.xfail("OclElf::getNote() failed in getSectionDesc");
|
|
return false;
|
|
}
|
|
if (scn == NULL) {
|
|
_err.xfail("OclElf::getNote() failed: .note section not found");
|
|
return false;
|
|
}
|
|
|
|
// read the whole .note section
|
|
Elf_Data* data = elf_getdata(scn, 0);
|
|
|
|
// Initialize the size and buffer to invalid data points.
|
|
*descSize = 0;
|
|
*noteDesc = NULL;
|
|
|
|
// look for the specified note
|
|
char* ptr = (char*)data->d_buf;
|
|
while (ptr < (char*)data->d_buf + data->d_size) {
|
|
Elf_Note* note = reinterpret_cast<Elf_Note*>(ptr);
|
|
|
|
// Continue if the note name doesn't match.
|
|
if (strlen(noteName) != note->n_namesz
|
|
|| strncmp(noteName, ptr+sizeof(Elf_Note), note->n_namesz) != 0) {
|
|
ptr += sizeof(Elf_Note) + note->n_namesz + note->n_descsz;
|
|
continue;
|
|
}
|
|
// Set the size and the address and return true.
|
|
*descSize = note->n_descsz;
|
|
*noteDesc = ptr + sizeof(Elf_Note) + note->n_namesz;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
OclElf::dumpImage(char** buff, size_t* len)
|
|
{
|
|
if (buff == NULL || len == NULL ) {
|
|
return false;
|
|
}
|
|
|
|
assert ((_fd != -1) && "_fd in Elf::dumpImage should be defined");
|
|
|
|
// Now, write the ELF into the file
|
|
if (elf_update(_e, ELF_C_WRITE) < 0) {
|
|
_err.xfail("OclElf::dumpImage() : elf_update() failed - %s",
|
|
elf_errmsg(-1));
|
|
return false;
|
|
}
|
|
|
|
int buff_sz = xlseek(_err, _fname, _fd, 0, SEEK_END);
|
|
if (buff_sz == -1) {
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
The memory is owned by caller, and caller assumes that the memory is new'ed.
|
|
So, use new instead of malloc
|
|
*/
|
|
*buff = new char[buff_sz];
|
|
if (*buff == NULL) {
|
|
_err.xfail("OclElf::dumpImage() : new char[sz] failed");
|
|
return false;
|
|
}
|
|
|
|
if (xlseek(_err, _fname, _fd, 0, SEEK_SET) == -1) {
|
|
_err.xfail("OclElf::dumpImage() failed in xlseek()");
|
|
delete [] *buff;
|
|
return false;
|
|
}
|
|
|
|
if (xread(_err, _fname, _fd, *buff, buff_sz) != buff_sz) {
|
|
_err.xfail("OclElf::dumpImage() failed in xread()");
|
|
delete [] *buff;
|
|
*buff = 0;
|
|
return false;
|
|
}
|
|
|
|
*len = buff_sz;
|
|
return true;
|
|
}
|
|
|
|
void*
|
|
OclElf::oclelf_allocAndCopy(void* p, size_t sz)
|
|
{
|
|
if (p == 0 || sz == 0) return p;
|
|
|
|
void* buf = xmalloc(_err, sz);
|
|
if (buf == 0) {
|
|
_err.xfail("OclElf::oclelf_allocAndCopy() failed");
|
|
return 0;
|
|
}
|
|
|
|
memcpy(buf, p, sz);
|
|
_elfMemory.insert( std::make_pair(buf, sz));
|
|
return buf;
|
|
}
|
|
|
|
void*
|
|
OclElf::oclelf_calloc(size_t sz)
|
|
{
|
|
void* buf = xmalloc(_err, sz);
|
|
if (buf == 0) {
|
|
_err.xfail("OclElf::oclelf_calloc() failed");
|
|
return 0;
|
|
}
|
|
_elfMemory.insert( std::make_pair(buf, sz));
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
OclElf::elfMemoryRelease()
|
|
{
|
|
for(EMemory::iterator it = _elfMemory.begin(); it != _elfMemory.end(); it++) {
|
|
free(it->first);
|
|
}
|
|
_elfMemory.clear();
|
|
}
|
|
|
|
} // namespace amd
|