#ifdef LTO_SUPPORT
#include <stdio.h>
#include <stdlib.h>
#include <libc.h>
#include <sys/file.h>
#include <dlfcn.h>
#include <llvm-c/lto.h>
#include "stuff/ofile.h"
#include "stuff/lto.h"
#include "stuff/allocate.h"
#include <mach-o/nlist.h>
#include <mach-o/dyld.h>
static int get_lto_cputype(
struct arch_flag *arch_flag,
char *target_triple);
static int tried_to_load_lto = 0;
static void *lto_handle = NULL;
static int (*lto_is_object)(const void* mem, size_t length) = NULL;
static lto_module_t (*lto_create)(const void* mem, size_t length) = NULL;
static void (*lto_dispose)(void *mod) = NULL;
static char * (*lto_get_target)(void *mod) = NULL;
static uint32_t (*lto_get_num_symbols)(void *mod) = NULL;
static lto_symbol_attributes (*lto_get_sym_attr)(void *mod, uint32_t n) = NULL;
static char * (*lto_get_sym_name)(void *mod, uint32_t n) = NULL;
__private_extern__
int
is_llvm_bitcode(
struct ofile *ofile,
char *addr,
size_t size)
{
struct arch_flag arch_flag;
ofile->lto = NULL;
ofile->lto_cputype = 0;
ofile->lto_cpusubtype = 0;
if(is_llvm_bitcode_from_memory(addr, size, &arch_flag,
&ofile->lto) != 0){
ofile->lto_cputype = arch_flag.cputype;
ofile->lto_cpusubtype = arch_flag.cpusubtype;
return(1);
}
return(0);
}
__private_extern__ int is_llvm_bitcode_from_memory(
char *addr,
uint32_t size,
struct arch_flag *arch_flag,
void **pmod)
{
uint32_t bufsize;
char *p, *prefix, *lto_path, buf[MAXPATHLEN], resolved_name[PATH_MAX];
int i;
void *mod;
if(size == 0)
return(0);
if(tried_to_load_lto == 0){
tried_to_load_lto = 1;
bufsize = MAXPATHLEN;
p = buf;
i = _NSGetExecutablePath(p, &bufsize);
if(i == -1){
p = allocate(bufsize);
_NSGetExecutablePath(p, &bufsize);
}
prefix = realpath(p, resolved_name);
p = rindex(prefix, '/');
if(p != NULL)
p[1] = '\0';
lto_path = makestr(prefix, "../lib/libLTO.dylib", NULL);
lto_handle = dlopen(lto_path, RTLD_NOW);
if(lto_handle == NULL){
free(lto_path);
lto_path = NULL;
lto_handle = dlopen("/Applications/Xcode.app/Contents/"
"Developer/Toolchains/XcodeDefault."
"xctoolchain/usr/lib/libLTO.dylib",
RTLD_NOW);
}
if(lto_handle == NULL)
return(0);
lto_is_object = dlsym(lto_handle,
"lto_module_is_object_file_in_memory");
lto_create = dlsym(lto_handle, "lto_module_create_from_memory");
lto_dispose = dlsym(lto_handle, "lto_module_dispose");
lto_get_target = dlsym(lto_handle, "lto_module_get_target_triple");
lto_get_num_symbols = dlsym(lto_handle,
"lto_module_get_num_symbols");
lto_get_sym_attr = dlsym(lto_handle,
"lto_module_get_symbol_attribute");
lto_get_sym_name = dlsym(lto_handle, "lto_module_get_symbol_name");
if(lto_is_object == NULL ||
lto_create == NULL ||
lto_dispose == NULL ||
lto_get_target == NULL ||
lto_get_num_symbols == NULL ||
lto_get_sym_attr == NULL ||
lto_get_sym_name == NULL){
dlclose(lto_handle);
if(lto_path != NULL)
free(lto_path);
return(0);
}
}
if(lto_handle == NULL)
return(0);
if(!lto_is_object(addr, size))
return(0);
mod = lto_create(addr, size);
if(mod == NULL)
return(0);
arch_flag->cputype = 0;
arch_flag->cpusubtype = 0;
arch_flag->name = NULL;
(void)get_lto_cputype(arch_flag, lto_get_target(mod));
if(pmod != NULL)
*pmod = mod;
else
lto_free(mod);
return(1);
}
static
int
get_lto_cputype(
struct arch_flag *arch_flag,
char *target_triple)
{
char *p;
size_t n;
if(target_triple == NULL)
return(0);
p = index(target_triple, '-');
if(p == NULL)
return(0);
n = p - target_triple;
if(strncmp(target_triple, "i686", n) == 0 ||
strncmp(target_triple, "i386", n) == 0){
arch_flag->cputype = CPU_TYPE_I386;
arch_flag->cpusubtype = CPU_SUBTYPE_I386_ALL;
}
else if(strncmp(target_triple, "x86_64", n) == 0){
arch_flag->cputype = CPU_TYPE_X86_64;
arch_flag->cpusubtype = CPU_SUBTYPE_X86_64_ALL;
}
else if(strncmp(target_triple, "powerpc", n) == 0){
arch_flag->cputype = CPU_TYPE_POWERPC;
arch_flag->cpusubtype = CPU_SUBTYPE_POWERPC_ALL;
}
else if(strncmp(target_triple, "powerpc64", n) == 0){
arch_flag->cputype = CPU_TYPE_POWERPC64;
arch_flag->cpusubtype = CPU_SUBTYPE_POWERPC_ALL;
}
else if(strncmp(target_triple, "arm", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V4T;
}
else if(strncmp(target_triple, "armv5", n) == 0 ||
strncmp(target_triple, "armv5e", n) == 0 ||
strncmp(target_triple, "thumbv5", n) == 0 ||
strncmp(target_triple, "thumbv5e", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V5TEJ;
}
else if(strncmp(target_triple, "armv6", n) == 0 ||
strncmp(target_triple, "thumbv6", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V6;
}
else if(strncmp(target_triple, "armv7", n) == 0 ||
strncmp(target_triple, "thumbv7", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7;
}
else if(strncmp(target_triple, "armv7f", n) == 0 ||
strncmp(target_triple, "thumbv7f", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7F;
}
else if(strncmp(target_triple, "armv7s", n) == 0 ||
strncmp(target_triple, "thumbv7s", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7S;
}
else if(strncmp(target_triple, "armv7k", n) == 0 ||
strncmp(target_triple, "thumbv7k", n) == 0){
arch_flag->cputype = CPU_TYPE_ARM;
arch_flag->cpusubtype = CPU_SUBTYPE_ARM_V7K;
}
else{
return(0);
}
arch_flag->name = (char *)get_arch_name_from_types(arch_flag->cputype,
arch_flag->cpusubtype);
return(1);
}
__private_extern__
uint32_t
lto_get_nsyms(
void *mod)
{
return(lto_get_num_symbols(mod));
}
__private_extern__
int
lto_toc_symbol(
void *mod,
uint32_t symbol_index,
int commons_in_toc)
{
lto_symbol_attributes attr;
attr = lto_get_sym_attr(mod, symbol_index);
if((attr & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
return(0);
if((attr & LTO_SYMBOL_DEFINITION_MASK) ==
LTO_SYMBOL_DEFINITION_REGULAR ||
(attr & LTO_SYMBOL_DEFINITION_MASK) ==
LTO_SYMBOL_DEFINITION_WEAK)
return(1);
if((attr & LTO_SYMBOL_DEFINITION_MASK) ==
LTO_SYMBOL_DEFINITION_TENTATIVE &&
commons_in_toc)
return(1);
return(0);
}
__private_extern__
void
lto_get_nlist_64(
struct nlist_64 *nl,
void *mod,
uint32_t symbol_index)
{
lto_symbol_attributes attr;
memset(nl, '\0', sizeof(struct nlist_64));
attr = lto_get_sym_attr(mod, symbol_index);
switch(attr & LTO_SYMBOL_SCOPE_MASK){
case LTO_SYMBOL_SCOPE_INTERNAL:
break;
case LTO_SYMBOL_SCOPE_HIDDEN:
nl->n_type |= N_EXT;
nl->n_type |= N_PEXT;
break;
case LTO_SYMBOL_SCOPE_DEFAULT:
nl->n_type |= N_EXT;
}
if((attr & LTO_SYMBOL_DEFINITION_MASK) == LTO_SYMBOL_DEFINITION_WEAK)
nl->n_desc |= N_WEAK_DEF;
if((attr & LTO_SYMBOL_DEFINITION_MASK) ==
LTO_SYMBOL_DEFINITION_TENTATIVE){
nl->n_type |= N_EXT;
nl->n_type |= N_UNDF;
nl->n_value = 1;
}
if((attr & LTO_SYMBOL_DEFINITION_MASK) ==
LTO_SYMBOL_DEFINITION_UNDEFINED){
nl->n_type |= N_EXT;
nl->n_type |= N_UNDF;
}
else
switch(attr & LTO_SYMBOL_PERMISSIONS_MASK){
case LTO_SYMBOL_PERMISSIONS_CODE:
nl->n_sect = 1;
nl->n_type |= N_SECT;
break;
case LTO_SYMBOL_PERMISSIONS_DATA:
nl->n_sect = 2;
nl->n_type |= N_SECT;
break;
case LTO_SYMBOL_PERMISSIONS_RODATA:
nl->n_sect = 3;
nl->n_type |= N_SECT;
break;
}
}
__private_extern__
char *
lto_symbol_name(
void *mod,
uint32_t symbol_index)
{
return(lto_get_sym_name(mod, symbol_index));
}
__private_extern__
void
lto_free(
void *mod)
{
lto_dispose(mod);
}
#endif