mirror of
https://github.com/darlinghq/darling.git
synced 2024-11-27 06:10:36 +00:00
Significantly improved trampoline, working dladdr() and modified FileMap, removing macho2elf, capturing C++ exception data sections
This commit is contained in:
parent
d195c7ed35
commit
ae8f596555
@ -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
|
||||
)
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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()
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
86
src/dyld/trampoline_helper.asm
Normal file
86
src/dyld/trampoline_helper.asm
Normal 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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user