Alien-LibJIT
view release on metacpan or search on metacpan
libjit/jit/jit-elf-read.c view on Meta::CPAN
We use our own routines to read and write ELF binaries. We chose ELF
because it has all of the features that we require, and reusing an
existing format was better than inventing a completely new one.
@section Reading ELF binaries
@*/
/*
* Determine whether we should be using the 32-bit or 64-bit ELF structures.
*/
#ifdef JIT_NATIVE_INT32
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Phdr Elf_Phdr;
typedef Elf32_Addr Elf_Addr;
typedef Elf32_Word Elf_Word;
typedef Elf32_Xword Elf_Xword;
typedef Elf32_Off Elf_Off;
typedef Elf32_Dyn Elf_Dyn;
typedef Elf32_Sym Elf_Sym;
typedef Elf32_Rel Elf_Rel;
typedef Elf32_Rela Elf_Rela;
#define ELF_R_SYM(val) ELF32_R_SYM((val))
#define ELF_R_TYPE(val) ELF32_R_TYPE((val))
#else
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Phdr Elf_Phdr;
typedef Elf64_Addr Elf_Addr;
typedef Elf64_Word Elf_Word;
typedef Elf64_Xword Elf_Xword;
typedef Elf64_Off Elf_Off;
typedef Elf64_Dyn Elf_Dyn;
typedef Elf64_Sym Elf_Sym;
typedef Elf64_Rel Elf_Rel;
typedef Elf64_Rela Elf_Rela;
#define ELF_R_SYM(val) ELF64_R_SYM((val))
#define ELF_R_TYPE(val) ELF64_R_TYPE((val))
#endif
/*
* Deal with platform differences in the file descriptor routines.
*/
#ifdef JIT_WIN32_NATIVE
#define sys_open _open
#define sys_close _close
#define sys_read _read
#define sys_lseek _lseek
#else
#define sys_open open
#define sys_close close
#define sys_read read
#define sys_lseek lseek
#endif
#ifndef O_BINARY
#define O_BINARY 0
#endif
/*
* Define the relocation function type.
*/
typedef int (*jit_reloc_func)(jit_readelf_t readelf, void *address,
int type, jit_nuint value, int has_addend,
jit_nuint addend);
/*
* Get the relocation function for a particular machine type.
*/
static jit_reloc_func get_reloc(unsigned int machine);
/*
* Structure of an ELF binary once it has been loaded into memory.
*/
struct jit_readelf
{
jit_readelf_t next;
int resolved;
Elf_Ehdr ehdr;
unsigned char *phdrs;
unsigned char *shdrs;
char *regular_strings;
jit_nuint regular_strings_size;
char *dynamic_strings;
jit_nuint dynamic_strings_size;
Elf_Sym *symbol_table;
jit_nuint symbol_table_size;
Elf_Word *symbol_hash;
jit_nuint symbol_hash_size;
Elf_Word symbol_hash_buckets;
jit_reloc_func reloc_func;
void *map_address;
jit_nuint map_size;
int free_with_munmap;
};
/*
* Flag that indicates that an auxillary section was malloc'ed,
* and isn't part of the main memory range at "map_address".
*/
#define JIT_ELF_IS_MALLOCED 0x01000000
/*
* Get the address of a particular phdr.
*/
static Elf_Phdr *get_phdr(jit_readelf_t readelf, unsigned int index)
{
if(index < readelf->ehdr.e_phnum &&
readelf->ehdr.e_phentsize >= sizeof(Elf_Phdr))
{
return (Elf_Phdr *)
(readelf->phdrs +
index * ((unsigned int)(readelf->ehdr.e_phentsize)));
}
else
{
return 0;
}
}
/*
* Get the address of a particular shdr.
*/
static Elf_Shdr *get_shdr(jit_readelf_t readelf, unsigned int index)
{
if(index < readelf->ehdr.e_shnum &&
readelf->ehdr.e_shentsize >= sizeof(Elf_Shdr))
{
libjit/jit/jit-elf-read.c view on Meta::CPAN
/* Close the file descriptor because we don't need it any more */
sys_close(fd);
/* Find the regular string table */
shdr = get_shdr(readelf, ehdr.e_shstrndx);
if(shdr)
{
if((shdr->sh_flags & JIT_ELF_IS_MALLOCED) != 0)
{
readelf->regular_strings = (char *)(jit_nuint)(shdr->sh_offset);
}
else
{
readelf->regular_strings =
(char *)jit_readelf_map_vaddr(readelf, shdr->sh_addr);
}
if(readelf->regular_strings)
{
readelf->regular_strings_size = (jit_nuint)(shdr->sh_size);
}
}
/* Dump debug information about the program segments and sections */
if((flags & JIT_READELF_FLAG_DEBUG) != 0)
{
printf("header: machine=%d, abi=%d, abi_version=%d\n",
(int)(ehdr.e_machine), (int)(ehdr.e_ident[EI_OSABI]),
(int)(ehdr.e_ident[EI_ABIVERSION]));
for(index = 0; index < ehdr.e_phnum; ++index)
{
phdr = get_phdr(readelf, index);
if(phdr)
{
printf("program segment: type=%d, flags=0x%x, "
"vaddr=0x%lx, file_size=%ld, memory_size=%ld\n",
(int)(phdr->p_type),
(int)(phdr->p_flags & ~JIT_ELF_IS_MALLOCED),
(long)(phdr->p_vaddr),
(long)(phdr->p_filesz),
(long)(phdr->p_memsz));
}
}
for(index = 0; index < ehdr.e_shnum; ++index)
{
shdr = get_shdr(readelf, index);
if(shdr)
{
printf("section %2d: name=\"%s\", type=%d, flags=0x%x, "
"vaddr=0x%lx, size=%ld\n",
index,
get_string(readelf, shdr->sh_name),
(int)(shdr->sh_type),
(int)(shdr->sh_flags & ~JIT_ELF_IS_MALLOCED),
(long)(shdr->sh_addr),
(long)(shdr->sh_size));
}
}
}
/* Get the relocation function for this machine type */
readelf->reloc_func = get_reloc((unsigned int)(ehdr.e_machine));
/* Load useful values from the dynamic section that we want to cache */
load_dynamic_section(readelf, flags);
/* The ELF binary is loaded and ready to go */
*_readelf = readelf;
return JIT_READELF_OK;
}
/*@
* @deftypefun void jit_readelf_close (jit_readelf_t @var{readelf})
* Close an ELF reader, reclaiming all of the memory that was used.
* @end deftypefun
@*/
void jit_readelf_close(jit_readelf_t readelf)
{
unsigned int index;
Elf_Shdr *shdr;
if(!readelf)
{
return;
}
#ifdef JIT_USE_MMAP_TO_LOAD
if(readelf->free_with_munmap)
{
munmap(readelf->map_address, (size_t)(readelf->map_size));
}
else
#endif
{
_jit_free_exec(readelf->map_address, readelf->map_size);
}
for(index = 0; index < readelf->ehdr.e_shnum; ++index)
{
shdr = get_shdr(readelf, index);
if(shdr && (shdr->sh_flags & JIT_ELF_IS_MALLOCED) != 0)
{
unmap_section
((void *)(jit_nuint)(shdr->sh_offset),
shdr->sh_size, shdr->sh_size, shdr->sh_flags);
}
}
jit_free(readelf->phdrs);
jit_free(readelf->shdrs);
jit_free(readelf);
}
/*@
* @deftypefun {const char *} jit_readelf_get_name (jit_readelf_t @var{readelf})
* Get the library name that is embedded inside an ELF binary.
* ELF binaries can refer to each other using this name.
* @end deftypefun
@*/
const char *jit_readelf_get_name(jit_readelf_t readelf)
{
Elf_Addr value;
if(dynamic_for_type(readelf, DT_SONAME, &value))
{
return get_dyn_string(readelf, value);
libjit/jit/jit-elf-read.c view on Meta::CPAN
/* Look for "before" symbols that are registered with the context */
for(index = 0; index < context->num_registered_symbols; ++index)
{
if(!jit_strcmp(symbol_name, context->registered_symbols[index]->name) &&
!(context->registered_symbols[index]->after))
{
return context->registered_symbols[index]->value;
}
}
/* Search all loaded ELF libraries for the name */
library = context->elf_binaries;
while(library != 0)
{
value = jit_readelf_get_symbol(library, symbol_name);
if(value)
{
return value;
}
library = library->next;
}
/* Look for libjit internal symbols (i.e. intrinsics) */
left = 0;
right = _jit_num_internal_symbols - 1;
while(left <= right)
{
index = (left + right) / 2;
cmp = jit_strcmp(symbol_name, _jit_internal_symbols[index].name);
if(cmp == 0)
{
return _jit_internal_symbols[index].value;
}
else if(cmp < 0)
{
right = index - 1;
}
else
{
left = index + 1;
}
}
/* Look for "after" symbols that are registered with the context */
for(index = 0; index < context->num_registered_symbols; ++index)
{
if(!jit_strcmp(symbol_name, context->registered_symbols[index]->name) &&
context->registered_symbols[index]->after)
{
return context->registered_symbols[index]->value;
}
}
/* If we get here, then we could not resolve the symbol */
printf("%s: could not resolve `%s'\n", name, symbol_name);
return 0;
}
/*
* Perform a DT_REL style relocation on an ELF binary.
*/
static int perform_rel
(jit_context_t context, jit_readelf_t readelf,
int print_failures, const char *name, Elf_Rel *reloc)
{
void *address;
void *value;
/* Get the address to apply the relocation at */
address = jit_readelf_map_vaddr(readelf, (jit_nuint)(reloc->r_offset));
if(!address)
{
if(print_failures)
{
printf("%s: cannot map virtual address 0x%lx\n",
name, (long)(reloc->r_offset));
}
return 0;
}
/* Resolve the designated symbol to its actual value */
value = resolve_symbol
(context, readelf, print_failures, name,
(jit_nuint)ELF_R_SYM(reloc->r_info));
if(!value)
{
return 0;
}
/* Perform the relocation */
if(!(*(readelf->reloc_func))
(readelf, address, (int)(ELF_R_TYPE(reloc->r_info)),
(jit_nuint)value, 0, 0))
{
if(print_failures)
{
printf("%s: relocation type %d was not recognized\n",
name, (int)(ELF_R_TYPE(reloc->r_info)));
}
return 0;
}
return 1;
}
/*
* Perform a DT_RELA style relocation on an ELF binary.
*/
static int perform_rela
(jit_context_t context, jit_readelf_t readelf,
int print_failures, const char *name, Elf_Rela *reloc)
{
void *address;
void *value;
/* Get the address to apply the relocation at */
address = jit_readelf_map_vaddr(readelf, (jit_nuint)(reloc->r_offset));
if(!address)
{
if(print_failures)
{
printf("%s: cannot map virtual address 0x%lx\n",
name, (long)(reloc->r_offset));
}
return 0;
}
/* Resolve the designated symbol to its actual value */
value = resolve_symbol
(context, readelf, print_failures, name,
(jit_nuint)ELF_R_SYM(reloc->r_info));
if(!value)
{
return 0;
}
/* Perform the relocation */
if(!(*(readelf->reloc_func))
(readelf, address, (int)(ELF_R_TYPE(reloc->r_info)),
(jit_nuint)value, 1, (jit_nuint)(reloc->r_addend)))
{
if(print_failures)
{
printf("%s: relocation type %d was not recognized\n",
name, (int)(ELF_R_TYPE(reloc->r_info)));
}
return 0;
}
return 1;
}
/*
* Perform relocations on an ELF binary. Returns zero on failure.
*/
static int perform_relocations
(jit_context_t context, jit_readelf_t readelf, int print_failures)
{
Elf_Addr address;
Elf_Addr table_size;
Elf_Addr entry_size;
unsigned char *table;
const char *name;
int ok = 1;
/* Get the library name, for printing diagnostic messages */
name = jit_readelf_get_name(readelf);
if(!name)
{
name = "unknown-elf-binary";
}
/* Bail out if we don't know how to perform relocations */
if(!(readelf->reloc_func))
{
if(print_failures)
{
printf("%s: do not know how to perform relocations\n", name);
}
return 0;
}
/* Apply the "Rel" relocations in the dynamic section */
if(dynamic_for_type(readelf, DT_REL, &address) &&
dynamic_for_type(readelf, DT_RELSZ, &table_size) &&
dynamic_for_type(readelf, DT_RELENT, &entry_size) && entry_size)
{
table = (unsigned char *)jit_readelf_map_vaddr
(readelf, (jit_nuint)address);
while(table && table_size >= entry_size)
{
if(!perform_rel(context, readelf, print_failures, name,
(Elf_Rel *)table))
{
ok = 0;
}
table += (jit_nuint)entry_size;
table_size -= entry_size;
}
}
/* Apply the "Rela" relocations in the dynamic section */
if(dynamic_for_type(readelf, DT_RELA, &address) &&
dynamic_for_type(readelf, DT_RELASZ, &table_size) &&
dynamic_for_type(readelf, DT_RELAENT, &entry_size) && entry_size)
{
table = (unsigned char *)jit_readelf_map_vaddr
(readelf, (jit_nuint)address);
while(table && table_size >= entry_size)
{
if(!perform_rela(context, readelf, print_failures, name,
(Elf_Rela *)table))
{
ok = 0;
}
table += (jit_nuint)entry_size;
table_size -= entry_size;
}
}
/* Apply the "PLT" relocations in the dynamic section, which
may be either DT_REL or DT_RELA style relocations */
if(dynamic_for_type(readelf, DT_JMPREL, &address) &&
dynamic_for_type(readelf, DT_PLTRELSZ, &table_size) &&
dynamic_for_type(readelf, DT_PLTREL, &entry_size))
{
if(entry_size == DT_REL)
{
if(dynamic_for_type(readelf, DT_RELENT, &entry_size) && entry_size)
{
table = (unsigned char *)jit_readelf_map_vaddr
(readelf, (jit_nuint)address);
while(table && table_size >= entry_size)
{
if(!perform_rel(context, readelf, print_failures, name,
(Elf_Rel *)table))
{
ok = 0;
}
table += (jit_nuint)entry_size;
table_size -= entry_size;
}
}
}
else if(entry_size == DT_RELA)
{
if(dynamic_for_type(readelf, DT_RELAENT, &entry_size) && entry_size)
{
table = (unsigned char *)jit_readelf_map_vaddr
(readelf, (jit_nuint)address);
while(table && table_size >= entry_size)
{
if(!perform_rela(context, readelf, print_failures, name,
(Elf_Rela *)table))
{
ok = 0;
}
table += (jit_nuint)entry_size;
table_size -= entry_size;
}
}
}
}
/* Return to the caller */
return ok;
}
/*@
* @deftypefun int jit_readelf_resolve_all (jit_context_t @var{context}, int @var{print_failures})
* Resolve all of the cross-library symbol references in ELF binaries
* that have been added to @var{context} but which were not resolved
* in the previous call to this function. If @var{print_failures}
* is non-zero, then diagnostic messages will be written to stdout
* for any symbol resolutions that fail.
*
* Returns zero on failure, or non-zero if all symbols were successfully
* resolved. If there are no ELF binaries awaiting resolution, then
* this function will return a non-zero result.
* @end deftypefun
@*/
int jit_readelf_resolve_all(jit_context_t context, int print_failures)
{
int ok = 1;
jit_readelf_t readelf;
if(!context)
{
return 0;
}
_jit_memory_lock(context);
readelf = context->elf_binaries;
while(readelf != 0)
{
if(!(readelf->resolved))
{
readelf->resolved = 1;
if(!perform_relocations(context, readelf, print_failures))
{
ok = 0;
}
}
readelf = readelf->next;
}
_jit_memory_unlock(context);
return ok;
}
/*@
* @deftypefun int jit_readelf_register_symbol (jit_context_t @var{context}, const char *@var{name}, void *@var{value}, int @var{after})
* Register @var{value} with @var{name} on the specified @var{context}.
* Whenever symbols are resolved with @code{jit_readelf_resolve_all},
* and the symbol @var{name} is encountered, @var{value} will be
* substituted. Returns zero if out of memory or there is something
* wrong with the parameters.
*
* If @var{after} is non-zero, then @var{name} will be resolved after all
* other ELF libraries; otherwise it will be resolved before the ELF
* libraries.
*
* This function is used to register intrinsic symbols that are specific to
* the front end virtual machine. References to intrinsics within
* @code{libjit} itself are resolved automatically.
* @end deftypefun
@*/
int jit_readelf_register_symbol
(jit_context_t context, const char *name, void *value, int after)
{
jit_regsym_t sym;
jit_regsym_t *new_list;
/* Bail out if there is something wrong with the parameters */
if(!context || !name || !value)
{
return 0;
}
/* Allocate and populate the symbol information block */
sym = (jit_regsym_t)jit_malloc
(sizeof(struct jit_regsym) + jit_strlen(name));
if(!sym)
{
return 0;
}
sym->value = value;
sym->after = after;
jit_strcpy(sym->name, name);
/* Add the symbol details to the registered list */
new_list = (jit_regsym_t *)jit_realloc
(context->registered_symbols,
sizeof(jit_regsym_t) * (context->num_registered_symbols + 1));
if(!new_list)
{
jit_free(sym);
return 0;
}
new_list[(context->num_registered_symbols)++] = sym;
context->registered_symbols = new_list;
return 1;
}
/************************************************************************
Warning! Warning! Warning!
The following code is very system-dependent, as every ELF target has its
own peculiar mechanism for performing relocations. Consult your target's
documentation for the precise details.
To make things a little easier, you only need to support the relocation
types that you intend to use in the JIT's ELF writer. And many types
only pertain to ELF executable or object files, which we don't use.
************************************************************************/
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
/*
* Apply relocations for i386 platforms.
*/
static int i386_reloc(jit_readelf_t readelf, void *address, int type,
jit_nuint value, int has_addend, jit_nuint addend)
{
if(type == R_386_32)
{
if(has_addend)
{
*((jit_nuint *)address) = value + addend;
}
else
{
*((jit_nuint *)address) += value;
}
return 1;
}
else if(type == R_386_PC32)
{
value -= (jit_nuint)address;
if(has_addend)
{
*((jit_nuint *)address) = value + addend;
}
else
{
*((jit_nuint *)address) += value;
}
return 1;
}
return 0;
}
#endif /* i386 */
#if defined(__arm) || defined(__arm__)
/*
* Apply relocations for ARM platforms.
*/
static int arm_reloc(jit_readelf_t readelf, void *address, int type,
jit_nuint value, int has_addend, jit_nuint addend)
{
if(type == R_ARM_PC24)
{
value -= (jit_nuint)address;
if(has_addend)
{
*((jit_nuint *)address) =
(*((jit_nuint *)address) & 0xFF000000) + value + addend;
}
else
{
*((jit_nuint *)address) += value;
}
return 1;
}
else if(type == R_ARM_ABS32)
{
if(has_addend)
{
*((jit_nuint *)address) = value + addend;
}
else
{
*((jit_nuint *)address) += value;
}
return 1;
}
else if(type == R_ARM_REL32)
{
value -= (jit_nuint)address;
if(has_addend)
{
*((jit_nuint *)address) = value + addend;
}
else
{
*((jit_nuint *)address) += value;
}
return 1;
}
return 0;
}
#endif /* arm */
/*
* Apply relocations for the interpreted platform.
*/
static int interp_reloc(jit_readelf_t readelf, void *address, int type,
jit_nuint value, int has_addend, jit_nuint addend)
{
/* We only have one type of relocation for the interpreter: direct */
if(type == 1)
{
*((jit_nuint *)address) = value;
return 1;
}
else
{
return 0;
}
}
/*
* Get the relocation function for a particular machine type.
*/
static jit_reloc_func get_reloc(unsigned int machine)
{
#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
if(machine == EM_386)
{
return i386_reloc;
}
#endif
#if defined(__arm) || defined(__arm__)
if(machine == EM_ARM)
{
return arm_reloc;
}
#endif
if(machine == 0x4C6A) /* "Lj" for the libjit interpreter */
{
return interp_reloc;
}
return 0;
}
( run in 0.873 second using v1.01-cache-2.11-cpan-71847e10f99 )