#include "jit-internal.h"
#include "jit-elf-defs.h"
#include "jit-rules.h"
#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_Half Elf_Half;
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;
#else
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Phdr Elf_Phdr;
typedef Elf64_Addr Elf_Addr;
typedef Elf64_Half Elf_Half;
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;
#endif
typedef struct jit_section *jit_section_t;
struct jit_section
{
Elf_Shdr shdr;
char *data;
unsigned int data_len;
};
struct jit_writeelf
{
Elf_Ehdr ehdr;
jit_section_t sections;
int num_sections;
int regular_string_section;
int dynamic_string_section;
};
static const char *get_string(jit_writeelf_t writeelf, Elf_Word index)
{
if(writeelf->regular_string_section < 0)
{
return 0;
}
else
{
return writeelf->sections[writeelf->regular_string_section].data +
(jit_nuint)index;
}
}
static Elf_Word add_string(jit_writeelf_t writeelf, const char *name)
{
jit_section_t section;
char *data;
Elf_Word index;
unsigned int name_len = jit_strlen(name) + 1;
section = &(writeelf->sections[writeelf->regular_string_section]);
data = (char *)jit_realloc(section->data, section->data_len + name_len);
if(!data)
{
return 0;
}
section->data = data;
jit_strcpy(data + section->data_len, name);
index = (Elf_Word)(section->data_len);
section->data_len += name_len;
return index;
}
static const char *get_dyn_string(jit_writeelf_t writeelf, Elf_Word index)
{
if(writeelf->dynamic_string_section < 0)
{
return 0;
}
else
{
return writeelf->sections[writeelf->dynamic_string_section].data +
(jit_nuint)index;
}
}
static Elf_Word add_dyn_string(jit_writeelf_t writeelf, const char *name)
{
jit_section_t section;
char *data;
Elf_Word index;
unsigned int name_len = jit_strlen(name) + 1;
section = &(writeelf->sections[writeelf->dynamic_string_section]);
data = (char *)jit_realloc(section->data, section->data_len + name_len);
if(!data)
{
return 0;
}
section->data = data;
jit_strcpy(data + section->data_len, name);
index = (Elf_Word)(section->data_len);
section->data_len += name_len;
return index;
}
static jit_section_t get_section
(jit_writeelf_t writeelf, const char *name, jit_int type,
Elf_Word flags, Elf_Word entry_size, Elf_Word alignment)
{
int index;
jit_section_t section;
for(index = 0; index < writeelf->num_sections; ++index)
{
section = &(writeelf->sections[index]);
if(!jit_strcmp(get_string(writeelf, section->shdr.sh_name), name))
{
return section;
}
}
section = (jit_section_t)jit_realloc
(writeelf->sections,
(writeelf->num_sections + 1) * sizeof(struct jit_section));
if(!section)
{
return 0;
}
writeelf->sections = section;
section += writeelf->num_sections;
jit_memzero(section, sizeof(struct jit_section));
if(writeelf->regular_string_section < 0)
{
section->data = (char *)jit_malloc(jit_strlen(name) + 2);
if(!(section->data))
{
return 0;
}
section->data_len = jit_strlen(name) + 2;
section->data[0] = '\0';
jit_strcpy(section->data + 1, name);
section->shdr.sh_name = 1;
writeelf->regular_string_section = writeelf->num_sections;
}
else
{
section->shdr.sh_name = add_string(writeelf, name);
if(!(section->shdr.sh_name))
{
return 0;
}
}
section->shdr.sh_type = (Elf_Word)type;
section->shdr.sh_flags = flags;
section->shdr.sh_entsize = entry_size;
section->shdr.sh_addralign = alignment;
++(writeelf->num_sections);
return section;
}
static int add_to_section
(jit_section_t section, const void *buf, unsigned int len)
{
char *data = (char *)jit_realloc(section->data, section->data_len + len);
if(!data)
{
return 0;
}
section->data = data;
jit_memcpy(data + section->data_len, buf, len);
section->data_len += len;
return 1;
}
static int add_dyn_info
(jit_writeelf_t writeelf, int type, Elf_Addr value, int modify_existing)
{
jit_section_t section;
Elf_Dyn dyn;
section = get_section(writeelf, ".dynamic", SHT_DYNAMIC,
SHF_WRITE | SHF_ALLOC,
sizeof(Elf_Dyn), sizeof(Elf_Dyn));
if(!section)
{
return 0;
}
if(modify_existing)
{
Elf_Dyn *existing = (Elf_Dyn *)(section->data);
unsigned int num = section->data_len / sizeof(Elf_Dyn);
while(num > 0)
{
if(existing->d_tag == type)
{
existing->d_un.d_ptr = value;
return 1;
}
++existing;
--num;
}
}
jit_memzero(&dyn, sizeof(dyn));
dyn.d_tag = type;
dyn.d_un.d_ptr = value;
return add_to_section(section, &dyn, sizeof(dyn));
}
jit_writeelf_t jit_writeelf_create(const char *library_name)
{
jit_writeelf_t writeelf;
Elf_Word name_index;
union
{
jit_ushort value;
unsigned char bytes[2];
} un;
jit_elf_info_t elf_info;
writeelf = jit_cnew(struct jit_writeelf);
if(!writeelf)
{
return 0;
}
writeelf->regular_string_section = -1;
writeelf->dynamic_string_section = -1;
if(!get_section(writeelf, ".shstrtab", SHT_STRTAB, 0, 0, 0))
{
jit_writeelf_destroy(writeelf);
return 0;
}
if(!get_section(writeelf, ".dynstr", SHT_STRTAB, SHF_ALLOC, 0, 0))
{
jit_writeelf_destroy(writeelf);
return 0;
}
writeelf->dynamic_string_section = writeelf->num_sections - 1;
if(!add_dyn_string(writeelf, ""))
{
jit_writeelf_destroy(writeelf);
return 0;
}
name_index = add_dyn_string(writeelf, library_name);
if(!name_index)
{
jit_writeelf_destroy(writeelf);
return 0;
}
if(!add_dyn_info(writeelf, DT_SONAME, (Elf_Addr)name_index, 0))
{
jit_writeelf_destroy(writeelf);
return 0;
}
writeelf->ehdr.e_ident[EI_MAG0] = ELFMAG0;
writeelf->ehdr.e_ident[EI_MAG1] = ELFMAG1;
writeelf->ehdr.e_ident[EI_MAG2] = ELFMAG2;
writeelf->ehdr.e_ident[EI_MAG3] = ELFMAG3;
#ifdef JIT_NATIVE_INT32
writeelf->ehdr.e_ident[EI_CLASS] = ELFCLASS32;
#else
writeelf->ehdr.e_ident[EI_CLASS] = ELFCLASS64;
#endif
un.value = 0x0102;
if(un.bytes[0] == 0x01)
{
writeelf->ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
}
else
{
writeelf->ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
}
writeelf->ehdr.e_ident[EI_VERSION] = EV_CURRENT;
_jit_gen_get_elf_info(&elf_info);
writeelf->ehdr.e_ident[EI_OSABI] = (unsigned char)(elf_info.abi);
writeelf->ehdr.e_ident[EI_ABIVERSION] =
(unsigned char)(elf_info.abi_version);
writeelf->ehdr.e_machine = (Elf_Half)(elf_info.machine);
writeelf->ehdr.e_version = EV_CURRENT;
writeelf->ehdr.e_ehsize = sizeof(writeelf->ehdr);
if(!jit_writeelf_add_needed(writeelf, "libjit.so"))
{
jit_writeelf_destroy(writeelf);
return 0;
}
return writeelf;
}
void jit_writeelf_destroy(jit_writeelf_t writeelf)
{
int index;
if(!writeelf)
{
return;
}
for(index = 0; index < writeelf->num_sections; ++index)
{
jit_free(writeelf->sections[index].data);
}
jit_free(writeelf->sections);
jit_free(writeelf);
}
int jit_writeelf_write(jit_writeelf_t writeelf, const char *filename)
{
return 1;
}
int jit_writeelf_add_function
(jit_writeelf_t writeelf, jit_function_t func, const char *name)
{
return 1;
}
int jit_writeelf_add_needed(jit_writeelf_t writeelf, const char *library_name)
{
jit_section_t section;
Elf_Dyn *dyn;
unsigned int num_dyn;
Elf_Word name_index;
if(!writeelf || !library_name)
{
return 0;
}
section = get_section(writeelf, ".dynamic", SHT_DYNAMIC,
SHF_WRITE | SHF_ALLOC,
sizeof(Elf_Dyn), sizeof(Elf_Dyn));
if(!section)
{
return 0;
}
dyn = (Elf_Dyn *)(section->data);
num_dyn = section->data_len / sizeof(Elf_Dyn);
while(num_dyn > 0)
{
if(dyn->d_tag == DT_NEEDED &&
!jit_strcmp(get_dyn_string(writeelf, (Elf_Word)(dyn->d_un.d_ptr)),
library_name))
{
return 1;
}
++dyn;
--num_dyn;
}
name_index = add_dyn_string(writeelf, library_name);
if(!name_index)
{
return 0;
}
if(!add_dyn_info(writeelf, DT_NEEDED, (Elf_Addr)name_index, 0))
{
return 0;
}
return 1;
}
int jit_writeelf_write_section
(jit_writeelf_t writeelf, const char *name, jit_int type,
const void *buf, unsigned int len, int discardable)
{
jit_section_t section;
if(!writeelf || !name)
{
return 0;
}
if(!type)
{
type = (jit_int)(SHT_LOUSER + 0x1234);
}
if(discardable)
{
section = get_section(writeelf, name, type, 0, 1, 1);
}
else
{
section = get_section(writeelf, name, type, SHF_ALLOC, 1, 1);
}
if(!section)
{
return 0;
}
if(len > 0)
{
return add_to_section(section, buf, len);;
}
else
{
return 1;
}
}