From 67cd9d3620666fec2a4f762c8fe74051b9e7f8d2 Mon Sep 17 00:00:00 2001 From: Stan H Date: Sun, 10 Dec 2017 14:53:58 +0100 Subject: [PATCH] support for absolute references to local symbols --- CMakeLists.txt | 3 + core/event_object.cpp | 161 +++++++++++++++++++++++++++--------------- core/event_object.h | 11 +-- core/section_data.cpp | 38 ++-------- core/section_data.h | 2 - core/util.cpp | 23 ++++++ core/util.h | 12 ++++ main.cpp | 70 +++++++++--------- 8 files changed, 187 insertions(+), 133 deletions(-) create mode 100644 core/util.cpp create mode 100644 core/util.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 33af6be..d8d79e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") set(SOURCE_LIST main.cpp + core/util.h + core/util.cpp + core/binary_file.h core/binary_file.cpp diff --git a/core/event_object.cpp b/core/event_object.cpp index 3530af6..b8b3e59 100644 --- a/core/event_object.cpp +++ b/core/event_object.cpp @@ -4,6 +4,7 @@ #include #include "../ea/event_section.h" +#include "util.h" namespace lyn { @@ -11,6 +12,18 @@ void event_object::append_from_elf(const elf_file& elfFile) { std::vector newSections(elfFile.sections().size()); std::vector outMap(elfFile.sections().size(), false); + auto getLocalSymbolName = [this] (int section, int index) -> std::string { + std::string result; + result.reserve(2 + 8 + 4 + 4); + + result.append("_L"); + result.append(stan::to_hex_digits(size(), 8)); + result.append(stan::to_hex_digits(section, 4)); + result.append(stan::to_hex_digits(index, 4)); + + return result; + }; + // Initializing written Sections from relevant elf sections for (int i=0; iis_absolute() && relocatelet->can_make_trampoline()) { - std::string renamed = std::string("LYN_PROXY_").append(relocation.symbolName); + std::string renamed; + renamed.reserve(4 + relocation.symbolName.size()); + + renamed.append("_LP_"); // local proxy + renamed.append(relocation.symbolName); + bool exists = false; for (auto& sym : symbols()) @@ -153,16 +173,13 @@ void event_object::make_trampolines() { combine_with(std::move(trampolineData)); } -void event_object::link_temporaries() { +void event_object::try_relocate_relatives() { relocations().erase( std::remove_if( relocations().begin(), relocations().end(), [this] (const section_data::relocation& relocation) -> bool { for (auto& symbol : symbols()) { - if (!symbol.isLocal) - continue; - if (symbol.name != relocation.symbolName) continue; @@ -183,18 +200,18 @@ void event_object::link_temporaries() { ); } -void event_object::link_locals() { +void event_object::try_relocate_absolutes() { relocations().erase( std::remove_if( relocations().begin(), relocations().end(), [this] (const section_data::relocation& relocation) -> bool { - for (auto& symbol : symbols()) { + for (auto& symbol : mAbsoluteSymbols) { if (symbol.name != relocation.symbolName) continue; if (auto relocatelet = mRelocator.get_relocatelet(relocation.type)) { - if (!relocatelet->is_absolute()) { + if (relocatelet->is_absolute()) { relocatelet->apply_relocation(*this, relocation.offset, symbol.offset, relocation.addend); return true; } @@ -210,30 +227,33 @@ void event_object::link_locals() { ); } -void event_object::link_absolutes() { - relocations().erase( +void event_object::remove_unnecessary_symbols() { + symbols().erase( std::remove_if( - relocations().begin(), - relocations().end(), - [this] (const section_data::relocation& relocation) -> bool { - for (auto& symbol : mAbsoluteSymbols) { - if (symbol.name != relocation.symbolName) - continue; - - if (auto relocatelet = mRelocator.get_relocatelet(relocation.type)) { - if (relocatelet->is_absolute()) { - relocatelet->apply_relocation(*this, relocation.offset, symbol.offset, relocation.addend); - return true; - } - } + symbols().begin(), + symbols().end(), + [this] (const section_data::symbol& symbol) -> bool { + if (!symbol.isLocal) + return false; // symbol may be used outside of the scope of this object - return false; - } + for (auto& reloc : relocations()) + if (reloc.symbolName == symbol.name) + return false; // a relocation is dependant on this symbol - return false; + return true; // symbol is local and unused, we can remove it safely (hopefully) } ), - relocations().end() + symbols().end() + ); +} + +void event_object::cleanup() { + std::sort( + symbols().begin(), + symbols().end(), + [] (const section_data::symbol& a, const section_data::symbol& b) -> bool { + return a.offset < b.offset; + } ); } @@ -262,26 +282,51 @@ void event_object::write_events(std::ostream& output) const { if (auto relocatelet = mRelocator.get_relocatelet(relocation.type)) events.set_code(relocation.offset, relocatelet->make_event_code(relocation.symbolName, relocation.addend)); else - throw std::runtime_error(std::string("RELOC ERROR: Unhandled relocation type ").append(std::to_string(relocation.type))); + throw std::runtime_error(std::string("unhandled relocation type #").append(std::to_string(relocation.type))); } events.compress_codes(); events.optimize(); - if (!symbols().empty()) { + if (std::any_of(symbols().begin(), symbols().end(), [] (const section_data::symbol& sym) { return !sym.isLocal; })) { output << "PUSH" << std::endl; int currentOffset = 0; for (auto& symbol : symbols()) { + if (symbol.isLocal) + continue; + output << "ORG (CURRENTOFFSET+$" << std::hex << (symbol.offset - currentOffset) << "); " << symbol.name << ":" << std::endl; currentOffset = symbol.offset; } - output << "POP" << std::endl << std::endl; + output << "POP" << std::endl; } - events.write_to_stream(output); + if (std::any_of(symbols().begin(), symbols().end(), [] (const section_data::symbol& sym) { return sym.isLocal; })) { + output << "{" << std::endl; + output << "PUSH" << std::endl; + + int currentOffset = 0; + + for (auto& symbol : symbols()) { + if (!symbol.isLocal) + continue; + + output << "ORG (CURRENTOFFSET+$" << std::hex << (symbol.offset - currentOffset) << "); " + << symbol.name << ":" << std::endl; + currentOffset = symbol.offset; + } + + output << "POP" << std::endl; + + events.write_to_stream(output); + + output << "}" << std::endl; + } else { + events.write_to_stream(output); + } } } // namespace lyn diff --git a/core/event_object.h b/core/event_object.h index 6925bc3..da321f0 100644 --- a/core/event_object.h +++ b/core/event_object.h @@ -18,11 +18,14 @@ class event_object : public section_data { public: void append_from_elf(const lyn::elf_file& elfFile); - void make_trampolines(); + void try_transform_relatives(); - void link_locals(); - void link_temporaries(); - void link_absolutes(); + void try_relocate_relatives(); + void try_relocate_absolutes(); + + void remove_unnecessary_symbols(); + + void cleanup(); std::vector get_hooks() const; diff --git a/core/section_data.cpp b/core/section_data.cpp index 3e00e69..85ce448 100644 --- a/core/section_data.cpp +++ b/core/section_data.cpp @@ -1,29 +1,12 @@ #include "section_data.h" #include "../ea/event_section.h" +#include "util.h" #include namespace lyn { -std::string::value_type toHexDigit(std::uint32_t value) { - value = (value & 0xF); - - if (value < 10) - return '0' + value; - return 'A' + (value - 10); -} - -std::string toHexDigits(std::uint32_t value, int digits) { - std::string result; - result.resize(digits); - - for (int i=0; i> (4*i)); - - return result; -} - event_section section_data::make_events() const { event_section result; result.resize(size()); @@ -41,7 +24,7 @@ event_section section_data::make_events() const { case mapping::Data: result.set_code(pos, lyn::event_code( lyn::event_code::CODE_BYTE, - std::string("$").append(toHexDigits(byte_at(pos), 2)) + std::string("$").append(stan::to_hex_digits(byte_at(pos), 2)) )); pos++; break; @@ -49,7 +32,7 @@ event_section section_data::make_events() const { case mapping::Thumb: result.set_code(pos, lyn::event_code( lyn::event_code::CODE_SHORT, - std::string("$").append(toHexDigits(at(pos), 4)) + std::string("$").append(stan::to_hex_digits(at(pos), 4)) )); pos += 2; break; @@ -57,7 +40,7 @@ event_section section_data::make_events() const { case mapping::ARM: result.set_code(pos, lyn::event_code( lyn::event_code::CODE_WORD, - std::string("$").append(toHexDigits(at(pos), 8)) + std::string("$").append(stan::to_hex_digits(at(pos), 8)) )); pos += 4; break; @@ -134,17 +117,4 @@ void section_data::combine_with(section_data&& other) { binary_file::combine_with(other); } -void section_data::remove_temp_symbols() { - symbols().erase( - std::remove_if( - symbols().begin(), - symbols().end(), - [] (const section_data::symbol& symbol) -> bool { - return symbol.isLocal; - } - ), - symbols().end() - ); -} - } // namespace lyn diff --git a/core/section_data.h b/core/section_data.h index e42dc4d..0ba254a 100644 --- a/core/section_data.h +++ b/core/section_data.h @@ -58,8 +58,6 @@ class section_data : public binary_file { void combine_with(const section_data& other); void combine_with(section_data&& other); - void remove_temp_symbols(); - private: std::string mName; diff --git a/core/util.cpp b/core/util.cpp new file mode 100644 index 0000000..026d924 --- /dev/null +++ b/core/util.cpp @@ -0,0 +1,23 @@ +#include "util.h" + +namespace stan { + +static std::string::value_type to_hex_digit(std::uint32_t value) { + value = (value & 0xF); + + if (value < 10) + return '0' + value; + return 'A' + (value - 10); +} + +std::string to_hex_digits(std::uint32_t value, int digits) { + std::string result; + result.resize(digits); + + for (int i=0; i> (4*i)); + + return result; +} + +} // namespace stan diff --git a/core/util.h b/core/util.h new file mode 100644 index 0000000..296b1f2 --- /dev/null +++ b/core/util.h @@ -0,0 +1,12 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + +namespace stan { + +std::string to_hex_digits(std::uint32_t value, int digits); + +} // namespace stan + +#endif // UTIL_H diff --git a/main.cpp b/main.cpp index f76ad38..f21a6d1 100644 --- a/main.cpp +++ b/main.cpp @@ -24,11 +24,10 @@ int main(int argc, char** argv) { return 1; struct { - bool linkLocals = true; - bool linkAbsolutes = true; - bool makeTrampolines = false; - bool printTemporary = false; + bool doLink = true; + bool longCall = false; bool applyHooks = true; + bool printTemporary = false; } options; std::vector elves; @@ -40,28 +39,26 @@ int main(int argc, char** argv) { continue; if (argument[0] == '-') { // option - if (argument == "-nolink") { - options.linkLocals = false; - options.linkAbsolutes = false; - } else if (argument == "-linkabs") { - options.linkLocals = false; - options.linkAbsolutes = true; - } else if (argument == "-linkall") { - options.linkLocals = true; - options.linkAbsolutes = true; + if (argument == "-nolink") { + options.doLink = false; + } else if (argument == "-link") { + options.doLink = true; } else if (argument == "-longcalls") { - options.makeTrampolines = true; + options.longCall = true; + } else if (argument == "-nolongcalls") { + options.longCall = false; } else if (argument == "-raw") { - options.linkLocals = false; - options.linkAbsolutes = false; - options.makeTrampolines = false; - options.applyHooks = false; - } else if (argument == "-printtemp") { - options.printTemporary = true; - } else if (argument == "-autohook") { - options.applyHooks = true; + options.doLink = false; + options.longCall = false; + options.applyHooks = false; + } else if (argument == "-temp") { + options.printTemporary = true; + } else if (argument == "-notemp") { + options.printTemporary = false; + } else if (argument == "-hook") { + options.applyHooks = true; } else if (argument == "-nohook") { - options.applyHooks = false; + options.applyHooks = false; } } else { // elf elves.push_back(std::move(argument)); @@ -74,34 +71,37 @@ int main(int argc, char** argv) { for (auto& elf : elves) object.append_from_elf(make_elf(elf)); - if (options.linkLocals) - object.link_locals(); + if (options.doLink) + object.try_relocate_relatives(); - if (options.makeTrampolines) - object.make_trampolines(); + if (options.longCall) + object.try_transform_relatives(); - if (!options.printTemporary) { - object.link_temporaries(); - object.remove_temp_symbols(); - } + if (options.doLink) + object.try_relocate_absolutes(); - if (options.linkAbsolutes) - object.link_absolutes(); + if (!options.printTemporary) + object.remove_unnecessary_symbols(); + + object.cleanup(); if (options.applyHooks) { for (auto& hook : object.get_hooks()) { + lyn::event_object temp; + std::cout << "PUSH" << std::endl; std::cout << "ORG $" << std::hex << (hook.originalOffset & (~1)) << std::endl; - lyn::event_object temp; + temp.combine_with(lyn::arm_relocator::make_thumb_veneer(hook.name, 0)); temp.write_events(std::cout); + std::cout << "POP" << std::endl; } } object.write_events(std::cout); } catch (const std::exception& e) { - std::cout << "ERROR: [lyn] " << e.what() << std::endl; + std::cerr << "[lyn] ERROR: " << e.what() << std::endl; return 1; }