Significantly improved trampoline, working dladdr() and modified FileMap, removing macho2elf, capturing C++ exception data sections

This commit is contained in:
Lubos Dolezel 2012-08-30 23:40:00 +02:00
parent d195c7ed35
commit ae8f596555
13 changed files with 441 additions and 871 deletions

View File

@ -5,6 +5,7 @@ if(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)
enable_language(ASM_NASM)
ADD_DEFINITIONS(-ggdb -DDEBUG)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
@ -47,6 +48,7 @@ set(dyld_SRCS
src/dyld/MachOLoader.cpp
src/dyld/UndefinedFunction.cpp
src/dyld/Trampoline.cpp
src/dyld/trampoline_helper.asm
src/dyld/ld.cpp
src/dyld/dyld.cpp
)

View File

@ -1,36 +1,19 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#include "FileMap.h"
#include <cassert>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <err.h>
#include <stdexcept>
#include <sstream>
FileMap::~FileMap()
{
for (auto m : m_maps)
{
delete m.second;
}
}
void FileMap::add(const MachO& mach, uintptr_t slide, uintptr_t base)
{
@ -39,13 +22,13 @@ void FileMap::add(const MachO& mach, uintptr_t slide, uintptr_t base)
symbol_map->base = base;
if (!m_maps.insert(std::make_pair(base, symbol_map)).second)
{
err(1, "dupicated base addr: %p in %s",
(void*)base, mach.filename().c_str());
std::stringstream ss;
ss << "dupicated base addr: " << (void*) base << " in " << mach.filename();
throw std::runtime_error(ss.str());
}
for (size_t i = 0; i < mach.symbols().size(); i++)
for (MachO::Symbol sym : mach.symbols())
{
MachO::Symbol sym = mach.symbols()[i];
if (sym.name.empty() || sym.name[0] != '_')
continue;
sym.addr += slide;
@ -61,48 +44,60 @@ void FileMap::addWatchDog(uintptr_t addr)
assert(r);
}
const char* FileMap::dumpSymbol(void* p)
const char* FileMap::gdbInfoForAddr(void* p)
{
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
std::map<uintptr_t, SymbolMap*>::const_iterator found = m_maps.upper_bound(addr);
if (found == m_maps.begin() || found == m_maps.end())
{
Dl_info i;
if (!findSymbolInfo(p, &i))
return 0;
if (i.dli_fbase)
{
#ifdef __i386__
const char* fmt_string = "0x%08lx in %s+%x () from %s";
#else
const char* fmt_string = "0x%016lx in %s%x () from %s";
#endif
ptrdiff_t func_offset = uintptr_t(p) - uintptr_t(i.dli_saddr);
snprintf(m_dumped_stack_frame_buf, sizeof(m_dumped_stack_frame_buf)-1, fmt_string, p, i.dli_sname, func_offset, i.dli_fname);
}
--found;
return dumpSymbolFromMap(*found->second, addr);
}
const char* FileMap::dumpSymbolFromMap(const SymbolMap& symbol_map, uintptr_t addr)
{
uintptr_t file_offset = addr - symbol_map.base;
// Use lower_bound as PC may be in just after call.
std::map<uintptr_t, std::string>::const_iterator found = symbol_map.symbols.lower_bound(addr);
if (found == symbol_map.symbols.begin())
else
{
#ifdef __i386__
const char* fmt_string = "0x%08lx in ?? () from %s";
#else
const char* fmt_string = "0x%016lx in ?? () from %s";
#endif
snprintf(m_dumped_stack_frame_buf, 4095, fmt_string,
(void*)addr, symbol_map.filename.c_str());
return m_dumped_stack_frame_buf;
snprintf(m_dumped_stack_frame_buf, sizeof(m_dumped_stack_frame_buf)-1, fmt_string, p, i.dli_fname);
}
--found;
#ifdef __i386__
const char* fmt_string = "0x%08lx in %s () from %s";
#else
const char* fmt_string = "0x%016lx in %s () from %s";
#endif
const char* name = found->second.c_str();
uintptr_t func_offset = addr - found->first;
snprintf(m_dumped_stack_frame_buf, 4095, fmt_string,
(void*)addr, name, symbol_map.filename.c_str());
return m_dumped_stack_frame_buf;
}
bool FileMap::findSymbolInfo(void* p, Dl_info* info)
{
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
const SymbolMap* symbol_map;
std::map<uintptr_t, SymbolMap*>::const_iterator found = m_maps.upper_bound(addr);
if (found == m_maps.begin() || found == m_maps.end())
return false;
--found;
symbol_map = found->second;
std::map<uintptr_t, std::string>::const_iterator sfound = symbol_map->symbols.lower_bound(addr);
if (sfound != symbol_map->symbols.begin())
{
// found in lib and in symbols
info->dli_sname = sfound->second.c_str();
info->dli_saddr = reinterpret_cast<void*>(sfound->first);
}
info->dli_fname = symbol_map->filename.c_str();
info->dli_fbase = reinterpret_cast<void*>(symbol_map->base);
return true;
}

View File

@ -1,29 +1,3 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#ifndef FILEMAP_H
#define FILEMAP_H
@ -31,15 +5,19 @@
#include <string>
#include <map>
#include "MachO.h"
#include <dlfcn.h>
class FileMap
{
public:
~FileMap();
void add(const MachO& mach, uintptr_t slide, uintptr_t base);
void addWatchDog(uintptr_t addr);
const char* dumpSymbol(void* p);
const char* gdbInfoForAddr(void* p);
bool findSymbolInfo(void* addr, Dl_info* p); // used by __darwin_dladdr
private:
struct SymbolMap
@ -49,8 +27,6 @@ private:
uintptr_t base;
};
const char* dumpSymbolFromMap(const SymbolMap& symbol_map, uintptr_t addr);
std::map<uintptr_t, SymbolMap*> m_maps;
char m_dumped_stack_frame_buf[4096];
};

View File

@ -229,10 +229,6 @@ void MachOLoader::doBind(const MachO& mach, intptr slide)
size_t seen_weak_bind_index = 0;
size_t seen_weak_binds_orig_size = m_seen_weak_binds.size();
unsigned int common_code_size = (unsigned int)m_trampoline.size();
// Ensure that we won't change the address.
m_trampoline.reserve(common_code_size +
(1 + 6 + 5 + 10 + 3 + 2 + 1) * mach.binds().size());
g_bound_names.resize(mach.binds().size());
for (size_t i = 0; i < mach.binds().size(); i++)
@ -527,7 +523,7 @@ void MachOLoader::boot( uint64_t entry, int argc, char** argv, char** envp)
// GDB helper
extern "C" const char* dumpSymbol(void* p)
{
return g_file_map.dumpSymbol(p);
return g_file_map.gdbInfoForAddr(p);
}
#endif

View File

@ -6,8 +6,14 @@
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
TrampolineMgr* TrampolineMgr::m_pInstance = 0;
int TrampolineMgr::m_nDepth = 0;
std::map<std::string, TrampolineMgr::FunctionInfo> TrampolineMgr::m_functionInfo;
extern "C" void reg_saveall();
extern "C" void reg_restoreall();
TrampolineMgr::TrampolineMgr(int entries)
: m_nNext(0)
@ -27,13 +33,12 @@ TrampolineMgr::TrampolineMgr(int entries)
m_pMem = static_cast<Trampoline*>(mem);
m_nMax = bytes / sizeof(Trampoline);
m_nBytes = bytes;
}
TrampolineMgr::~TrampolineMgr()
{
::munmap(m_pMem, m_nBytes);
::munmap(m_pMem, m_nMax * sizeof(Trampoline));
}
void* TrampolineMgr::generate(void* targetAddr, const char* name)
@ -46,7 +51,7 @@ void* TrampolineMgr::generate(void* targetAddr, const char* name)
throw std::runtime_error("TrampolineMgr buffer full");
m_entries.push_back(e);
m_pMem[m_nNext].init(m_nNext, TrampolineMgr::printInfo);
m_pMem[m_nNext].init(m_nNext, TrampolineMgr::printInfo, TrampolineMgr::printInfoR);
void* addr = &m_pMem[m_nNext++];
// std::cout << "Trampoline for " << name << " is at " << addr << std::endl;
@ -93,32 +98,209 @@ void TrampolineMgr::loadMemoryMap()
}
}
void* TrampolineMgr::printInfo(uint32_t index)
void TrampolineMgr::loadFunctionInfo(const char* path)
{
std::cerr << m_pInstance->m_entries[index].name << "() called\n" << std::flush;
std::ifstream file(path);
std::string line;
while (std::getline(file, line))
{
size_t p = line.find(':');
if (p == std::string::npos)
continue;
FunctionInfo info;
info.retType = line.at(p+1);
info.arguments = line.substr(p+2);
m_functionInfo[line.substr(0, p)] = info;
}
}
void* TrampolineMgr::printInfo(uint32_t index, CallStack* stack)
{
FunctionInfo* info = 0;
const std::string& name = m_pInstance->m_entries[index].name;
auto it = m_functionInfo.find(name);
std::cerr << std::string(m_nDepth, ' ');
if (it != m_functionInfo.end())
{
ArgumentWalker w(stack);
bool first = true;
std::cerr << name << '(';
for (char c : it->second.arguments)
{
if (!first)
std::cerr << ", ";
else
first = false;
std::cerr << w.next(c);
}
std::cerr << ")\n" << std::flush;
}
else
std::cerr << m_pInstance->m_entries[index].name << "(?)\n" << std::flush;
m_pInstance->m_entries[index].retAddr = stack->retAddr;
m_nDepth++;
return m_pInstance->m_entries[index].addr;
}
void Trampoline::init(uint32_t i, void* (*pDebug)(uint32_t))
void* TrampolineMgr::printInfoR(uint32_t index, CallStack* stack)
{
// See /tools/trampoline.asm for source
void* rv = m_pInstance->m_entries[index].retAddr;
memcpy(code1, "\x50\x53\x57\x56\x52\x51\x41\x50\x41\x51\x48\x81\xec\x80\x00\x00\x00\xf3\x0f\x7f"
"\x04\x24\xf3\x0f\x7f\x4c\x24\x10\xf3\x0f\x7f\x54\x24\x20\xf3\x0f"
"\x7f\x5c\x24\x30\xf3\x0f\x7f\x64\x24\x40\xf3\x0f\x7f\x6c\x24\x50"
"\xf3\x0f\x7f\x74\x24\x60\xf3\x0f\x7f\x7c\x24\x70\xbf", sizeof(code1));
index = i;
code2[0] = 0x48;
code2[1] = 0xba;
debugFcn = uint64_t(pDebug);
m_pInstance->m_entries[index].retAddr = 0;
m_nDepth--;
memcpy(code3, "\xff\xd2\x49\x89\xc3"
"\xf3\x0f\x6f\x7c\x24\x70\xf3\x0f\x6f\x74\x24\x60\xf3\x0f\x6f\x6c"
"\x24\x50\xf3\x0f\x6f\x64\x24\x40\xf3\x0f\x6f\x5c\x24\x30\xf3\x0f"
"\x6f\x54\x24\x20\xf3\x0f\x6f\x4c\x24\x10\xf3\x0f\x6f\x04\x24\x48"
"\x81\xc4\x80\x00\x00\x00\x41\x59\x41\x58\x59\x5a\x5e\x5f\x5b\x58\x41\xff\xe3", sizeof(code3));
const std::string& name = m_pInstance->m_entries[index].name;
auto it = m_functionInfo.find(name);
std::cerr << std::string(m_nDepth, ' ');
if (it != m_functionInfo.end())
{
ArgumentWalker w(stack);
std::cerr << "-> " << w.ret(it->second.retType) << '\n' << std::flush;
}
else
std::cerr << "-> ?\n" << std::flush;
// standard retval in rax, double in xmm0
return rv;
}
void Trampoline::init(uint32_t i, void* (*pDebug)(uint32_t,TrampolineMgr::CallStack*), void* (*pDebugR)(uint32_t,TrampolineMgr::CallStack*))
{
// See trampoline in trampoline_helper.asm for source
memcpy(this, "\x49\xba\xb6\xb5\xb4\xb3\xb2\xb1\xb0\x00\x41\xff\xd2\xbf"
"\x56\x34\x12\x00\x48\x89\xe6\x48\xb9\xff\xee\xdd\xcc\xbb\xaa\x00\x00"
"\xff\xd1\x49\x89\xc3\x49\xba\xc6\xc5\xc4\xc3\xc2\xc1\xc0\x00\x41\xff"
"\xd2\x4c\x8d\x15\x08\x00\x00\x00\x4c\x89\x14\x24\x41\xff\xe3\x90\x49"
"\xba\xb6\xb5\xb4\xb3\xb2\xb1\xb0\x00\x41\xff\xd2\xbf\x56\x34\x12\x00"
"\x48\x89\xe6\x48\xb9\xa6\xa5\xa4\xa3\xa2\xa1\xa0\x00\xff\xd1\x49\x89"
"\xc3\x49\xba\xc6\xc5\xc4\xc3\xc2\xc1\xc0\x00\x41\xff\xd2\x41\xff\xe3",
sizeof(*this)
);
this->reg_saveall = reinterpret_cast<uint64_t>(::reg_saveall);
this->reg_saveall2 = reinterpret_cast<uint64_t>(::reg_saveall);
this->reg_restoreall = reinterpret_cast<uint64_t>(::reg_restoreall);
this->reg_restoreall2 = reinterpret_cast<uint64_t>(::reg_restoreall);
this->index = i;
this->index2 = i;
this->debugFcn = reinterpret_cast<uint64_t>(pDebug);
this->debugFcnR = reinterpret_cast<uint64_t>(pDebugR);
}
TrampolineMgr::ArgumentWalker::ArgumentWalker(CallStack* stack)
: m_stack(stack), m_indexInt(0), m_indexXmm(0)
{
}
uint64_t TrampolineMgr::ArgumentWalker::next64bit()
{
uint64_t rv;
if (m_indexInt == 0)
rv = m_stack->rdi;
else if (m_indexInt == 1)
rv = m_stack->rsi;
else if (m_indexInt == 2)
rv = m_stack->rdx;
else if (m_indexInt == 3)
rv = m_stack->rcx;
else if (m_indexInt == 4)
rv = m_stack->r8;
else if (m_indexInt == 5)
rv = m_stack->r9;
else
throw std::out_of_range("7th int argument not supported");
m_indexInt++;
return rv;
}
long double TrampolineMgr::ArgumentWalker::nextDouble()
{
long double rv;
if (m_indexXmm >= 0 && m_indexXmm <= 7)
return m_stack->xmm[m_indexXmm];
else
throw std::out_of_range("8th double argument not supported");
m_indexXmm++;
return rv;
}
std::string TrampolineMgr::ArgumentWalker::next(char type)
{
std::stringstream ss;
if (type == 'u')
ss << next64bit();
else if (type == 'i')
{
uint64_t u = next64bit();
ss << *((int64_t*) &u);
}
else if (type == 'f')
{
long double d = nextDouble();
ss << *((float*)&d);
}
else if (type == 'd')
{
long double d = nextDouble();
ss << *((double*)&d);
}
else if (type == 'p')
ss << "0x" << std::hex << (void*)next64bit() << std::dec;
else if (type == 's')
ss << (const char*)next64bit();
else if (type == 'v')
ss << "(void)";
else
ss << '?';
return ss.str();
}
std::string TrampolineMgr::ArgumentWalker::ret(char type)
{
std::stringstream ss;
if (type == 'u')
ss << m_stack->rax;
else if (type == 'i')
{
uint64_t u = m_stack->rax;
ss << *((int64_t*) &u);
}
else if (type == 'f')
{
long double d = m_stack->xmm[0];
ss << *((float*)&d);
}
else if (type == 'd')
{
long double d = m_stack->xmm[0];
ss << *((double*)&d);
}
else if (type == 'p')
ss << "0x" << std::hex << (void*)m_stack->rax << std::dec;
else if (type == 's')
ss << (const char*)m_stack->rax;
else
ss << '?';
return ss.str();
}
#ifdef TEST
@ -130,6 +312,7 @@ double mytestfunc(int a, int b, double c)
int main()
{
TrampolineMgr* mgr = new TrampolineMgr;
TrampolineMgr::loadFunctionInfo("/tmp/fi");
double (*pFunc)(int,int,double) = (double (*)(int,int,double)) mgr->generate((void*) &mytestfunc, "mytestfunc");
std::cout << pFunc(2,3,0.5) << std::endl;

View File

@ -4,6 +4,7 @@
#include <vector>
#include <string>
#include <list>
#include <map>
struct Trampoline;
@ -16,19 +17,28 @@ public:
void* generate(void* targetAddr, const char* name);
bool isExecutable(void* targetAddr);
void invalidateMemoryMap();
static void loadFunctionInfo(const char* path);
#pragma pack(1)
struct CallStack
{
long double xmm[8]; // xmm7-xmm0
uint64_t r9, r8, rcx, rdx, rsi, rdi, rbx, rax;
void* retAddr;
};
#pragma pack()
private:
void loadMemoryMap();
static void* printInfo(uint32_t index);
static void* printInfo(uint32_t index, CallStack* stack);
static void* printInfoR(uint32_t index, CallStack* stack);
private:
static TrampolineMgr* m_pInstance;
Trampoline* m_pMem;
int m_nMax, m_nNext, m_nBytes;
struct AddrEntry
{
std::string name;
void* addr;
void* retAddr; // not reentrant
};
struct MemoryPages
{
@ -39,21 +49,57 @@ private:
bool operator<(const MemoryPages& o) { return start < o.start; }
bool operator<(void* p) { return start < p; }
};
struct FunctionInfo
{
char retType;
std::string arguments;
};
class ArgumentWalker
{
public:
ArgumentWalker(CallStack* stack);
uint64_t next64bit();
long double nextDouble();
std::string next(char type);
std::string ret(char type);
private:
CallStack* m_stack;
int m_indexInt, m_indexXmm;
};
static TrampolineMgr* m_pInstance;
Trampoline* m_pMem;
int m_nMax, m_nNext;
std::vector<AddrEntry> m_entries;
std::list<MemoryPages> m_memoryMap;
static int m_nDepth;
static std::map<std::string, FunctionInfo> m_functionInfo;
};
#pragma pack(1)
struct Trampoline
struct Trampoline // 119 bytes // 63 code // 56 pointers
{
void init(uint32_t index, void* (*pDebug)(uint32_t));
void init(uint32_t index, void* (*pDebug)(uint32_t,TrampolineMgr::CallStack*), void* (*pDebugR)(uint32_t,TrampolineMgr::CallStack*));
char code1[65];
char code1[2];
uint64_t reg_saveall;
char code2[4];
uint32_t index;
char code2[2];
char code3[5];
uint64_t debugFcn;
char code3[72];
char code4[7];
uint64_t reg_restoreall;
char code5[20];
uint64_t reg_saveall2;
char code6[4];
uint32_t index2;
char code7[5];
uint64_t debugFcnR;
char code8[7];
uint64_t reg_restoreall2;
char code9[9];
char padding[1];
};
#pragma pack()

View File

@ -548,10 +548,18 @@ int __darwin_dladdr(void *addr, Dl_info *info)
Darling::MutexLock l(g_ldMutex);
g_ldError[0] = 0;
if (!g_file_map.findSymbolInfo(addr, info))
{
strcpy(g_ldError, "Specified address not mapped to a Mach-O file");
return -1;
}
if (!info->dli_fbase)
{
strcpy(g_ldError, "Specified address not resolvable to a symbol");
return -1;
}
// TODO: implement - examine g_file_map
strcpy(g_ldError, "Not implemented yet");
return -1;
return 0;
}
extern "C" void* dyld_stub_binder()

View File

@ -1,691 +0,0 @@
// Copyright 2011 Shinichiro Hamaji. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY Shinichiro Hamaji ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Shinichiro Hamaji OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// An attempt to translate from Mach-O to ELF.
//
// Note that programs generated by this program won't run because this
// doesn't initialize glibc properly.
#include <assert.h>
#include <elf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "mach-o.h"
using namespace std;
static map<string, string> g_rename;
static vector<string> g_sos;
static void initRename() {
#define RENAME(src, dst) g_rename.insert(make_pair(#src, #dst));
#define WRAP(src) RENAME(src, __darwin_ ## src)
#include "rename.tab"
#undef RENAME
#undef WRAP
}
static uint64_t alignMem(uint64_t p, uint64_t a) {
a--;
return (p + a) & ~a;
}
static void fwrite_checked(const void* ptr,
size_t size,
size_t nmemb,
FILE* stream) {
size_t r = fwrite(ptr, size, nmemb, stream);
if (r != nmemb) {
fprintf(stderr, "fwrite failed\n");
abort();
}
}
template <bool is64>
struct BitsHelpers {
typedef Elf64_Ehdr Elf_Ehdr;
typedef Elf64_Phdr Elf_Phdr;
typedef Elf64_Shdr Elf_Shdr;
typedef Elf64_Dyn Elf_Dyn;
typedef Elf64_Sym Elf_Sym;
typedef Elf64_Rela Elf_Rel;
typedef uint64_t intptr;
typedef segment_command_64 mach_segment;
static const vector<mach_segment*>& segments(const MachO& mach) {
return mach.segments64();
}
static int elf_st_bind(int val) {
return ELF64_ST_BIND(val);
}
};
template <>
struct BitsHelpers<false> {
typedef Elf32_Ehdr Elf_Ehdr;
typedef Elf32_Phdr Elf_Phdr;
typedef Elf32_Shdr Elf_Shdr;
typedef Elf32_Dyn Elf_Dyn;
typedef Elf32_Sym Elf_Sym;
typedef Elf32_Rela Elf_Rel;
typedef uint32_t intptr;
typedef segment_command mach_segment;
static const vector<mach_segment*>& segments(const MachO& mach) {
return mach.segments();
}
static int elf_st_bind(int val) {
return ELF32_ST_BIND(val);
}
};
template <bool is64>
class ELFBuilder {
typedef BitsHelpers<is64> Helpers;
typedef typename Helpers::Elf_Ehdr Ehdr;
typedef typename Helpers::Elf_Phdr Phdr;
typedef typename Helpers::Elf_Shdr Shdr;
typedef typename Helpers::Elf_Dyn Dyn;
typedef typename Helpers::Elf_Sym Sym;
typedef typename Helpers::Elf_Rel Rel;
typedef typename Helpers::intptr intptr;
typedef typename Helpers::mach_segment Segment;
public:
~ELFBuilder() {
for (size_t i = 0; i < sections_.size(); i++) {
delete sections_[i];
}
fclose(fp_);
}
void emit(const MachO& mach, const char* filename) {
Section* null_section = newSection("", SHT_NULL);
null_section->flags = 0;
fp_ = fopen(filename, "wb");
if (!fp_) {
fprintf(stderr, "Cannot write %s\n", filename);
exit(1);
}
int num_phdr = 3; // PT_INTERP + PT_DYNAMIC + PT_LOAD for dynamic
intptr base_vaddr = 0;
intptr max_vaddr = 0;
const vector<Segment*>& segments = Helpers::segments(mach);
for (size_t i = 0; i < segments.size(); i++) {
Segment* seg = segments[i];
const char* name = seg->segname;
if (!strcmp(name, SEG_PAGEZERO)) {
continue;
}
if (!strcmp(name, SEG_TEXT)) {
base_vaddr = seg->vmaddr;
}
max_vaddr = max(max_vaddr, seg->vmaddr + seg->vmsize);
num_phdr++;
}
Ehdr ehdr;
memset(&ehdr, 0, sizeof(ehdr));
ehdr.e_ident[EI_MAG0] = ELFMAG0;
ehdr.e_ident[EI_MAG1] = ELFMAG1;
ehdr.e_ident[EI_MAG2] = ELFMAG2;
ehdr.e_ident[EI_MAG3] = ELFMAG3;
ehdr.e_ident[EI_CLASS] = is64 ? ELFCLASS64 : ELFCLASS32;
ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
ehdr.e_ident[EI_VERSION] = EV_CURRENT;
ehdr.e_ident[EI_OSABI] = ELFOSABI_SYSV;
ehdr.e_type = ET_EXEC;
ehdr.e_machine = is64 ? EM_X86_64 : EM_386;
ehdr.e_version = EV_CURRENT;
ehdr.e_entry = mach.entry();
ehdr.e_phoff = sizeof(ehdr);
ehdr.e_shoff = 0;
ehdr.e_flags = 0;
ehdr.e_ehsize = sizeof(ehdr);
ehdr.e_phentsize = sizeof(Phdr);
ehdr.e_phnum = num_phdr;
ehdr.e_shentsize = sizeof(Shdr);
ehdr.e_shnum = 0;
ehdr.e_shstrndx = 0;
fwrite_checked(&ehdr, sizeof(ehdr), 1, fp_);
intptr offset = sizeof(Ehdr) + sizeof(Phdr) * num_phdr;
Phdr phdr;
const char* loader =
is64 ? "/lib64/ld-linux-x86-64.so.2" : "/lib/ld-linux.so.2";
phdr.p_type = PT_INTERP;
phdr.p_offset = offset;
phdr.p_vaddr = base_vaddr + phdr.p_offset;
phdr.p_paddr = phdr.p_vaddr;
phdr.p_filesz = strlen(loader) + 1;
phdr.p_memsz = phdr.p_filesz;
phdr.p_flags = PF_R;
phdr.p_align = 1;
fwrite_checked(&phdr, sizeof(phdr), 1, fp_);
offset += phdr.p_filesz;
for (size_t i = 0; i < segments.size(); i++) {
Segment* seg = segments[i];
const char* name = seg->segname;
if (!strcmp(name, SEG_PAGEZERO)) {
continue;
}
phdr.p_type = PT_LOAD;
phdr.p_offset = seg->fileoff;
phdr.p_vaddr = seg->vmaddr;
phdr.p_paddr = phdr.p_vaddr;
// TODO!
//phdr.p_filesz = max<uint64_t>(0x1000, seg->filesize);
phdr.p_filesz = alignMem(seg->filesize, 0x1000);
phdr.p_memsz = seg->vmsize;
phdr.p_flags = 0;
if (seg->initprot & VM_PROT_READ) {
phdr.p_flags |= PF_R;
}
if (seg->initprot & VM_PROT_WRITE) {
phdr.p_flags |= PF_W;
}
if (seg->initprot & VM_PROT_EXECUTE) {
phdr.p_flags |= PF_X;
}
phdr.p_align = 0x1000;
fwrite_checked(&phdr, sizeof(phdr), 1, fp_);
const char* sec_name = seg->segname;
int flags = SHF_ALLOC;
int align = 8;
//size = phdr.p_filesz;
uint64_t size = seg->filesize;
if (!strcmp(sec_name, SEG_TEXT)) {
sec_name = ".text";
flags |= SHF_EXECINSTR;
align = 16;
// TODO: maybe OK?
size = alignMem(size, 0x1000) - offset;
seg->fileoff = offset;
seg->filesize = size;
} else if (!strcmp(sec_name, SEG_DATA)) {
sec_name = ".data";
flags |= SHF_WRITE;
}
Section* sec = newSection(sec_name, SHT_PROGBITS);
sec->override_data_size = phdr.p_filesz;
sec->vmaddr = seg->vmaddr;
sec->offset = phdr.p_offset;
sec->flags |= flags;
sec->align = align;
offset += size;
}
size_t num_dyns = 9 + g_sos.size();
intptr dynamic_offset = max_vaddr + (offset & 0xfff);
phdr.p_type = PT_LOAD;
phdr.p_offset = offset;
phdr.p_vaddr = dynamic_offset;
phdr.p_paddr = phdr.p_vaddr;
// TODO: need to rewrite the size
phdr.p_filesz = 0x4000;
phdr.p_memsz = phdr.p_filesz;
phdr.p_flags = PF_R | PF_W;
phdr.p_align = 8;
fwrite_checked(&phdr, sizeof(phdr), 1, fp_);
phdr.p_type = PT_DYNAMIC;
phdr.p_filesz = sizeof(Dyn) * num_dyns;
fwrite_checked(&phdr, sizeof(phdr), 1, fp_);
Section* dynamic = newSection(".dynamic", SHT_DYNAMIC);
dynamic->entsize = sizeof(Dyn);
dynamic->offset = phdr.p_offset;
dynamic->override_data_size = phdr.p_filesz;
dynamic->flags |= SHF_WRITE;
offset += phdr.p_filesz;
dynamic_offset += phdr.p_filesz;
fwrite_checked(loader, strlen(loader) + 1, 1, fp_);
for (size_t i = 0; i < segments.size(); i++) {
Segment* seg = segments[i];
const char* name = seg->segname;
if (!strcmp(name, SEG_PAGEZERO)) {
continue;
}
fwrite_checked(mach.base() + seg->fileoff, 1, seg->filesize, fp_);
}
Symtab* symtab = newSymtab(".dynsym", SHT_DYNSYM, ".dynstr", ".hash");
dynamic->link = symtab->str;
vector<Rel> rels;
for (size_t i = 0; i < mach.binds().size(); i++) {
MachO::Bind* bind = mach.binds()[i];
if (bind->name[0] != '_') {
continue;
}
if (bind->type == BIND_TYPE_POINTER) {
const char* name = bind->name + 1;
printf("Putting ELF symbol: %s\n", name);
map<string, string>::const_iterator found =
g_rename.find(name);
if (found != g_rename.end()) {
printf("Applying renaming: %s => %s\n",
name, found->second.c_str());
name = found->second.c_str();
}
int sym_index = putELFSym(symtab, bind->vmaddr, 0,
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
0, 0, name);
Rel rel;
rel.r_offset = bind->vmaddr;
rel.r_info = ELF64_R_INFO(sym_index, R_X86_64_JUMP_SLOT);
rel.r_addend = bind->addend;
rels.push_back(rel);
} else {
printf("Unknown bind type: %d\n", bind->type);
abort();
}
}
vector<Dyn> dyns;
for (size_t i = 0; i < g_sos.size(); i++) {
addDynVal(DT_NEEDED, putELFStr(symtab->str, g_sos[i].c_str()),
&dyns);
}
addDynVal(DT_HASH, dynamic_offset, &dyns);
symtab->hash->offset = offset;
offset += symtab->hash->data.size();
dynamic_offset += symtab->hash->data.size();
addDynVal(DT_SYMTAB, dynamic_offset, &dyns);
symtab->sym->offset = offset;
offset += symtab->sym->data.size();
dynamic_offset += symtab->sym->data.size();
addDynVal(DT_STRTAB, dynamic_offset, &dyns);
symtab->str->offset = offset;
offset += symtab->str->data.size();
dynamic_offset += symtab->str->data.size();
addDynVal(DT_STRSZ, symtab->str->data.size(), &dyns);
addDynVal(DT_SYMENT, sizeof(Sym), &dyns);
addDynVal(DT_RELA, dynamic_offset, &dyns);
addDynVal(DT_RELASZ, sizeof(Rel) * rels.size(), &dyns);
Section* rel_sec = newSection(".rela.got", SHT_RELA);
rel_sec->offset = offset;
rel_sec->override_data_size = sizeof(Rel) * rels.size();
rel_sec->entsize = sizeof(Rel);
rel_sec->link = symtab->sym;
offset += sizeof(Rel) * rels.size();
addDynVal(DT_RELAENT, sizeof(Rel), &dyns);
addDynVal(DT_NULL, 0, &dyns);
assert(num_dyns == dyns.size());
for (size_t i = 0; i < dyns.size(); i++) {
fwrite_checked(&dyns[i], 1, sizeof(Dyn), fp_);
}
fwrite_checked(symtab->hash->data.data(),
symtab->hash->data.size(), 1, fp_);
fwrite_checked(symtab->sym->data.data(),
symtab->sym->data.size(), 1, fp_);
fwrite_checked(symtab->str->data.data(),
symtab->str->data.size(), 1, fp_);
for (size_t i = 0; i < rels.size(); i++) {
fwrite_checked(&rels[i], 1, sizeof(Rel), fp_);
}
delete symtab;
Section* shstrtab = newSection(".shstrtab", SHT_STRTAB);
shstrtab->offset = offset;
for (size_t i = 0; i < sections_.size(); i++) {
Section* sec = sections_[i];
sec->name_offset = putELFStr(shstrtab, sec->name.c_str());
}
fwrite_checked(shstrtab->data.data(), shstrtab->data.size(), 1, fp_);
offset += shstrtab->data.size();
ehdr.e_shoff = offset;
ehdr.e_shstrndx = sections_.size() - 1;
for (size_t i = 0; i < sections_.size(); i++) {
Section* sec = sections_[i];
Shdr shdr;
shdr.sh_name = sec->name_offset;
shdr.sh_type = sec->type;
shdr.sh_flags = sec->flags;
shdr.sh_addr = sec->offset + base_vaddr;
if (sec->vmaddr) {
shdr.sh_addr = sec->vmaddr;
}
shdr.sh_offset = sec->offset;
shdr.sh_size = sec->data.size();
if (sec->override_data_size) {
shdr.sh_size = sec->override_data_size;
}
shdr.sh_link = 0;
if (sec->link) {
shdr.sh_link = sec->link->index;
}
shdr.sh_info = 0;
//shdr.sh_addralign = sec->align;
shdr.sh_addralign = 0;
shdr.sh_entsize = sec->entsize;
fwrite_checked(&shdr, 1, sizeof(shdr), fp_);
}
ehdr.e_shnum = sections_.size();
char padding[4096];
fwrite_checked(padding, 1, sizeof(padding), fp_);
fseek(fp_, 0, SEEK_SET);
fwrite_checked(&ehdr, sizeof(ehdr), 1, fp_);
}
private:
struct Section {
string name;
int name_offset;
string data;
uint64_t offset;
uint64_t vmaddr;
uint64_t override_data_size;
uint32_t type;
int nb_hashed_syms;
int entsize;
int index;
int flags;
int align;
Section* link;
};
struct Symtab {
Section* sym;
Section* str;
Section* hash;
~Symtab() {
}
};
static char* addSectionPtr(Section* sec, uint64_t size) {
size_t offset = sec->data.size();
sec->data.resize(offset + size);
return &sec->data[offset];
}
Section* newSection(const char *name, uint32_t type) {
Section* sec;
sec = new Section();
sec->name = name;
sec->type = type;
sec->flags = SHF_ALLOC;
sec->index = static_cast<int>(sections_.size());
sec->name_offset = 0;
sec->offset = 0;
sec->vmaddr = 0;
sec->override_data_size = 0;
sec->nb_hashed_syms = 0;
sec->entsize = 0;
sec->align = 0;
sec->link = NULL;
sections_.push_back(sec);
return sec;
}
Symtab* newSymtab(const char* symtab_name, uint32_t symtab_type,
const char* strtab_name,
const char* hash_name) {
Symtab* symtab = new Symtab();
symtab->sym = newSection(symtab_name, symtab_type);
symtab->sym->entsize = sizeof(Sym);
symtab->str = newSection(strtab_name, SHT_STRTAB);
putELFStr(symtab->str, "");
symtab->sym->link = symtab->str;
putELFSym(symtab, 0, 0, 0, 0, 0, NULL);
int nb_buckets = 1;
symtab->hash = newSection(hash_name, SHT_HASH);
symtab->hash->entsize = sizeof(int);
symtab->hash->link = symtab->sym;
int* ptr = (int*)addSectionPtr(symtab->hash,
(2 + nb_buckets + 1) * sizeof(int));
ptr[0] = nb_buckets;
ptr[1] = 1;
memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
return symtab;
}
/* return the symbol number */
static int putELFSym(Symtab* symtab,
unsigned long value, unsigned long size,
int info, int other, int shndx, const char *name) {
int name_offset, sym_index;
int nbuckets, h;
Sym* sym;
Section* hs;
Section* s = symtab->sym;
sym = reinterpret_cast<Sym*>(addSectionPtr(s, sizeof(Sym)));
if (name) {
name_offset = putELFStr(symtab->str, name);
} else {
name_offset = 0;
}
/* XXX: endianness */
sym->st_name = name_offset;
sym->st_value = value;
sym->st_size = size;
sym->st_info = info;
sym->st_other = other;
sym->st_shndx = shndx;
sym_index = sym - (Sym*)s->data.data();
printf("sym: %x %p index=%d\n",
sym->st_name, (void*)(intptr_t)sym->st_value, sym_index);
hs = symtab->hash;
if (hs) {
int *ptr, *base;
ptr = reinterpret_cast<int*>(addSectionPtr(hs, sizeof(int)));
base = (int*)hs->data.data();
/* only add global or weak symbols */
if (Helpers::elf_st_bind(info) != STB_LOCAL) {
/* add another hashing entry */
nbuckets = base[0];
h = calcHash(name) % nbuckets;
*ptr = base[2 + h];
base[2 + h] = sym_index;
base[1]++;
/* we resize the hash table */
hs->nb_hashed_syms++;
if (hs->nb_hashed_syms > 2 * nbuckets) {
rebuildHash(symtab, 2 * nbuckets);
}
} else {
*ptr = 0;
base[1]++;
}
}
return sym_index;
}
/* rebuild hash table of section s */
/* NOTE: we do factorize the hash table code to go faster */
static void rebuildHash(Symtab* symtab, unsigned int nb_buckets) {
Sym* sym;
int* ptr;
int* hash;
int nb_syms, sym_index, h;
char* strtab;
Section* s = symtab->sym;
strtab = (char*)symtab->str->data.data();
nb_syms = s->data.size() / sizeof(Sym);
symtab->hash->data.clear();
ptr = (int*)addSectionPtr(symtab->hash,
(2 + nb_buckets + nb_syms) * sizeof(int));
ptr[0] = nb_buckets;
ptr[1] = nb_syms;
ptr += 2;
hash = ptr;
memset(hash, 0, (nb_buckets + 1) * sizeof(int));
ptr += nb_buckets + 1;
sym = (Sym*)s->data.data() + 1;
for(sym_index = 1; sym_index < nb_syms; sym_index++) {
if (Helpers::elf_st_bind(sym->st_info) != STB_LOCAL) {
h = calcHash(strtab + sym->st_name) % nb_buckets;
*ptr = hash[h];
hash[h] = sym_index;
} else {
*ptr = 0;
}
ptr++;
sym++;
}
}
static uint64_t putELFStr(Section* sec, const char* sym) {
uint64_t offset = sec->data.size();
sec->data += sym;
sec->data += '\0';
return offset;
}
static void addDynVal(int64_t tag, uint64_t val, vector<Dyn>* dyns) {
Dyn dyn;
dyn.d_tag = tag;
dyn.d_un.d_val = val;
dyns->push_back(dyn);
}
static void addDynPtr(int64_t tag, uint64_t ptr, vector<Dyn>* dyns) {
Dyn dyn;
dyn.d_tag = tag;
dyn.d_un.d_ptr = ptr;
dyns->push_back(dyn);
}
static uint64_t addStr(const string& s, string* o) {
uint64_t r = s.size();
*o += s;
*o += '\0';
return r;
}
static uint32_t calcHash(const char* name) {
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name);
uint32_t h = 0;
while (*ptr) {
h <<= 4;
h += *ptr++;
uint32_t g = h & 0xf0000000;
h ^= g >> 24;
h &= ~g;
}
return h;
}
FILE* fp_;
vector<Section*> sections_;
};
template <bool is64>
void emitELF(const MachO& mach, const char* filename) {
ELFBuilder<is64> builder;
builder.emit(mach, filename);
}
int main(int argc, char* argv[]) {
initRename();
vector<string> args;
g_sos.push_back("/lib/libc.so.6");
for (int i = 1; i < argc; i++) {
const char* arg = argv[i];
if (arg[0] != '-') {
args.push_back(arg);
continue;
}
if (arg[1] == 'l') {
g_sos.push_back(arg + 2);
} else {
fprintf(stderr, "Unknown switch '%s'\n", arg);
exit(1);
}
}
if (args.size() < 2) {
exit(1);
}
auto_ptr<MachO> mach(MachO::read(argv[0], "x86-64",
false /* need_exports */));
if (mach->is64()) {
emitELF<true>(*mach, args[1].c_str());
} else {
emitELF<false>(*mach, args[1].c_str());
}
}

View File

@ -0,0 +1,86 @@
BITS 64
section text
;global trampoline
global reg_saveall
global reg_restoreall
reg_saveall: ; 192 bytes on stack
pop r10 ; remove retaddr from stack
push rax
push rbx
push rdi
push rsi
push rdx
push rcx
push r8
push r9
sub rsp, 128 ; 8*16
movdqu [rsp], xmm0
movdqu [rsp+16], xmm1
movdqu [rsp+32], xmm2
movdqu [rsp+48], xmm3
movdqu [rsp+64], xmm4
movdqu [rsp+80], xmm5
movdqu [rsp+96], xmm6
movdqu [rsp+112], xmm7
jmp r10
reg_restoreall:
pop r10 ; remove retaddr from stack
movdqu xmm7, [rsp+112]
movdqu xmm6, [rsp+96]
movdqu xmm5, [rsp+80]
movdqu xmm4, [rsp+64]
movdqu xmm3, [rsp+48]
movdqu xmm2, [rsp+32]
movdqu xmm1, [rsp+16]
movdqu xmm0, [rsp]
add rsp, 128
pop r9
pop r8
pop rcx
pop rdx
pop rsi
pop rdi
pop rbx
pop rax
jmp r10
; This is duplicated for every mapped function
trampoline:
mov r10, qword 0xb0b1b2b3b4b5b6
call r10 ; call reg_saveall
mov rdi, 0x123456 ; index in entry table
mov rsi, rsp
mov rcx, qword 0xaabbccddeeff ; print function (saves orig ret address)
call rcx
mov r11, rax ; save the right addr
mov r10, qword 0xc0c1c2c3c4c5c6 ; call reg_restoreall
call r10
; rewrite return address
lea r10, [rel after_jump]
mov [rsp], r10; second print function
jmp r11 ; jump to the real function
ALIGN 2
after_jump:
mov r10, qword 0xb0b1b2b3b4b5b6
call r10 ; call reg_saveall
mov rdi, 0x123456
mov rsi, rsp
mov rcx, qword 0xa0a1a2a3a4a5a6 ; retval print function (returns orig ret address)
call rcx
mov r11, rax
mov r10, qword 0xc0c1c2c3c4c5c6 ; call reg_restoreall
call r10
jmp r11 ; now we "return" to the original function

View File

@ -105,6 +105,9 @@ public:
const std::vector<uint64_t>& init_funcs() const { return m_init_funcs; }
const std::vector<uint64_t>& exit_funcs() const { return m_exit_funcs; }
std::pair<uint64_t,uint64_t> get_eh_frame() const { return m_eh_frame; }
std::pair<uint64_t,uint64_t> get_unwind_info() const { return m_unwind_info; }
uint64_t dyld_data() const { return m_dyld_data; }
@ -127,6 +130,8 @@ public:
std::vector<uint64_t> m_init_funcs;
std::vector<uint64_t> m_exit_funcs;
uint64_t m_dyld_data;
std::pair<uint64_t,uint64_t> m_eh_frame;
std::pair<uint64_t,uint64_t> m_unwind_info;
bool m_is64;
int m_ptrsize;
int m_fd;

View File

@ -107,6 +107,19 @@ void MachOImpl::readSegment(char* cmds_ptr, std::vector<segment_command*>* segme
if (!strcmp(sec.sectname, "__dyld") && !strcmp(sec.segname, "__DATA"))
m_dyld_data = sec.addr;
if (!strcmp(sec.segname, "__TEXT"))
{
if (!strcmp(sec.sectname, "__eh_frame"))
{
m_eh_frame.first = sec.addr;
m_eh_frame.second = sec.addr + sec.size;
}
else if (!strcmp(sec.sectname, "__unwind_info"))
{
m_unwind_info.first = sec.addr;
m_unwind_info.second = sec.addr + sec.size;
}
}
int section_type = sec.flags & SECTION_TYPE;
switch (section_type)

View File

@ -1,49 +0,0 @@
BITS 64
section text
global trampoline
trampoline:
push rax
push rbx
push rdi
push rsi
push rdx
push rcx
push r8
push r9
sub rsp, 128 ; 8*16
movdqu [rsp], xmm0
movdqu [rsp+16], xmm1
movdqu [rsp+32], xmm2
movdqu [rsp+48], xmm3
movdqu [rsp+64], xmm4
movdqu [rsp+80], xmm5
movdqu [rsp+96], xmm6
movdqu [rsp+112], xmm7
mov rdi, 0x123456
mov rdx, qword 0xaabbccddeeff
call rdx
mov r11, rax ; save the right addr
movdqu xmm7, [rsp+112]
movdqu xmm6, [rsp+96]
movdqu xmm5, [rsp+80]
movdqu xmm4, [rsp+64]
movdqu xmm3, [rsp+48]
movdqu xmm2, [rsp+32]
movdqu xmm1, [rsp+16]
movdqu xmm0, [rsp]
add rsp, 128
pop r9
pop r8
pop rcx
pop rdx
pop rsi
pop rdi
pop rbx
pop rax
jmp r11