Replaced post-link finalizer with pre-link patchcompile
This commit is contained in:
parent
84b1bc9b4e
commit
6b96c725ee
@ -6,6 +6,6 @@ set(CMAKE_CXX_COMPILER g++-16 CACHE FILEPATH "C++ compiler" FORCE)
|
|||||||
project(SelfPatchSLR LANGUAGES C CXX)
|
project(SelfPatchSLR LANGUAGES C CXX)
|
||||||
|
|
||||||
add_subdirectory(pinpoint)
|
add_subdirectory(pinpoint)
|
||||||
add_subdirectory(finalize)
|
add_subdirectory(patchcompile)
|
||||||
add_subdirectory(selfpatch)
|
add_subdirectory(selfpatch)
|
||||||
add_subdirectory(subject)
|
add_subdirectory(subject)
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
find_package(LIEF REQUIRED)
|
|
||||||
|
|
||||||
add_executable(spslr_finalize finalize.cpp accumulation.cpp symbol_collection.cpp)
|
|
||||||
target_link_libraries(spslr_finalize PRIVATE LIEF::LIEF)
|
|
||||||
set_target_properties(spslr_finalize PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)
|
|
||||||
@ -1,293 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include <LIEF/LIEF.hpp>
|
|
||||||
#include <LIEF/ELF/Builder.hpp>
|
|
||||||
|
|
||||||
#include "accumulation.h"
|
|
||||||
#include "symbol_collection.h"
|
|
||||||
|
|
||||||
#include <spslr_program.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
Notes:
|
|
||||||
Datapins for same var/symbol are randomized in order of their level, from bottom of nest to top
|
|
||||||
Between CUs, types with the same name HAVE TO HAVE the same layout -> randomized together
|
|
||||||
To begin with, anonymous types are not allowed for randomization (later solved with hash(type) instead of name)!
|
|
||||||
*/
|
|
||||||
|
|
||||||
using namespace LIEF::ELF;
|
|
||||||
|
|
||||||
static bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector<uint8_t>& program);
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
static option long_options[] = {
|
|
||||||
{ "help", no_argument, 0, 0 },
|
|
||||||
{ "bin", required_argument, 0, 0 },
|
|
||||||
{ "out", required_argument, 0, 0 },
|
|
||||||
{ "strip", no_argument, 0, 0 },
|
|
||||||
{ 0, 0, 0, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
int option_index = 0;
|
|
||||||
int c;
|
|
||||||
|
|
||||||
std::vector<std::string> spslr_files;
|
|
||||||
std::string bin_file, out_file;
|
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "hb:o:", long_options, &option_index)) == 0) {
|
|
||||||
const option& opt = long_options[option_index];
|
|
||||||
std::string optname { opt.name };
|
|
||||||
|
|
||||||
if (optname == "help") {
|
|
||||||
std::cout << "To use spslr_finalize, supply these 3 arguments:" << std::endl;
|
|
||||||
std::cout << " --bin=<file> (the binary compiled with spslr_pinpoint to be finalized)" << std::endl;
|
|
||||||
std::cout << " --out=<file> (the finalized binary file to be written)" << std::endl;
|
|
||||||
std::cout << " <file>... (one or more .spslr metadata files)" << std::endl;
|
|
||||||
return 0;
|
|
||||||
} else if (optname == "bin") {
|
|
||||||
bin_file = std::string{ optarg };
|
|
||||||
} else if (optname == "out") {
|
|
||||||
out_file = std::string{ optarg };
|
|
||||||
} else if (optname == "strip") {
|
|
||||||
std::cerr << "Symbol stripping (--strip) is not yet implemented!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
std::cerr << "Invalid option, try \"--help\"!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bin_file.empty()) {
|
|
||||||
std::cerr << "Missing input file path, supply it via --bin=<file>!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_file.empty()) {
|
|
||||||
std::cerr << "Missing output file path, supply it via --out=<file>!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = optind; i < argc; ++i)
|
|
||||||
spslr_files.emplace_back(argv[i]);
|
|
||||||
|
|
||||||
if (spslr_files.empty()) {
|
|
||||||
std::cerr << "Missing spslr files! Pass one or more .spslr files as positional arguments." << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!accumulate(spslr_files)) {
|
|
||||||
std::cerr << "Failed to accumulate data from spslr directory!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Gathered a total of " << targets.size() << " distinct targets from "
|
|
||||||
<< units.size() << " compilation units!" << std::endl;
|
|
||||||
|
|
||||||
std::unique_ptr<Binary> bin = Parser::parse(bin_file);
|
|
||||||
if (!bin) {
|
|
||||||
std::cerr << "Failed to parse binary \"" << bin_file << "\"!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!collect_symbols(bin)) {
|
|
||||||
std::cerr << "Failed to collect symbols from \"" << bin_file << "\"!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!associate_symbols()) {
|
|
||||||
std::cerr << "Failed to associate symbols with accumulated data!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find __spslr_program as anchor of relative addressing in patcher program
|
|
||||||
if (!global_syms.symbols.contains("__spslr_program")) {
|
|
||||||
std::cerr << "Unable to locate \"__spslr_program\"!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t spslr_program_ptr_address = global_syms.symbols.at("__spslr_program");
|
|
||||||
|
|
||||||
// Serialize patcher program
|
|
||||||
std::vector<uint8_t> patcher_program;
|
|
||||||
if (!assemble_patcher_program(spslr_program_ptr_address, patcher_program)) {
|
|
||||||
std::cerr << "Failed to assemble patcher program!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Generated patcher program of 0x" << std::hex << patcher_program.size()
|
|
||||||
<< std::dec << " bytes!" << std::endl;
|
|
||||||
|
|
||||||
// Add new section ".spslr" with patcher program
|
|
||||||
|
|
||||||
uint64_t page_align = 0x1000;
|
|
||||||
for (const auto& seg : bin->segments()) {
|
|
||||||
if (seg.type() == Segment::TYPE::LOAD) {
|
|
||||||
if (seg.alignment() > page_align) page_align = seg.alignment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t max_end_vaddr = 0;
|
|
||||||
for (const auto& seg : bin->segments()) {
|
|
||||||
if (seg.type() == Segment::TYPE::LOAD) {
|
|
||||||
uint64_t endv = seg.virtual_address() + seg.virtual_size();
|
|
||||||
if (endv > max_end_vaddr) max_end_vaddr = endv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t new_vaddr = max_end_vaddr;
|
|
||||||
if (new_vaddr % page_align != 0)
|
|
||||||
new_vaddr += page_align - (new_vaddr % page_align);
|
|
||||||
|
|
||||||
std::cout << "Adding patcher program at 0x" << std::hex << new_vaddr << std::dec << std::endl;
|
|
||||||
|
|
||||||
Segment new_seg;
|
|
||||||
new_seg.type(Segment::TYPE::LOAD);
|
|
||||||
new_seg.flags(Segment::FLAGS::R); //(ELF_SEGMENT_FLAGS::PF_R);
|
|
||||||
new_seg.alignment(page_align);
|
|
||||||
new_seg.file_offset(0); // Writer decides where to put it
|
|
||||||
new_seg.virtual_address(new_vaddr);
|
|
||||||
new_seg.content(patcher_program);
|
|
||||||
new_seg.virtual_size(patcher_program.size());
|
|
||||||
|
|
||||||
bin->add(new_seg);
|
|
||||||
|
|
||||||
// Set __spslr_program to (new_vaddr - &__spslr_program)
|
|
||||||
for (Segment& seg : bin->segments()) {
|
|
||||||
uint64_t start = seg.virtual_address();
|
|
||||||
uint64_t end_mem = start + seg.virtual_size();
|
|
||||||
|
|
||||||
if (spslr_program_ptr_address >= start && spslr_program_ptr_address < end_mem) {
|
|
||||||
uint64_t offset_within_seg = spslr_program_ptr_address - start;
|
|
||||||
uint64_t min_needed = offset_within_seg + sizeof(uint64_t);
|
|
||||||
|
|
||||||
if (min_needed > seg.physical_size())
|
|
||||||
seg.physical_size(min_needed);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t relative_new_vaddr = new_vaddr - spslr_program_ptr_address;
|
|
||||||
std::vector<uint8_t> program_ptr_bytes;
|
|
||||||
program_ptr_bytes.resize(8);
|
|
||||||
std::memcpy(program_ptr_bytes.data(), &relative_new_vaddr, 8);
|
|
||||||
bin->patch_address(spslr_program_ptr_address, program_ptr_bytes);
|
|
||||||
|
|
||||||
// Output final program
|
|
||||||
Builder builder{ *bin };
|
|
||||||
builder.build();
|
|
||||||
builder.write(out_file);
|
|
||||||
|
|
||||||
std::cout << "Wrote final binary to \"" << out_file << "\"" << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector<uint8_t>& program) {
|
|
||||||
uint8_t buf[sizeof(SPSLR_INST)];
|
|
||||||
|
|
||||||
auto append_inst = [&](const SPSLR_INST& inst) -> bool {
|
|
||||||
int n = spslr_inst_dump(&inst, buf);
|
|
||||||
if (n < 0) {
|
|
||||||
std::cerr << "Failed to dump patcher instruction!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t program_ptr = program.size();
|
|
||||||
|
|
||||||
program.resize(program.size() + n);
|
|
||||||
std::memcpy(program.data() + program_ptr, buf, n);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
SPSLR_INST inst;
|
|
||||||
|
|
||||||
// Dump all targets, their fields and command randomization
|
|
||||||
for (const auto& [tuid, target] : targets) {
|
|
||||||
inst.opcode = SPSLR_TARGET;
|
|
||||||
inst.op0.target_uid = tuid;
|
|
||||||
inst.op1.target_size = target.size;
|
|
||||||
inst.op2.target_fieldcnt = target.fields.size();
|
|
||||||
|
|
||||||
if (!append_inst(inst))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (const auto& [foff, field] : target.fields) {
|
|
||||||
inst.opcode = SPSLR_FIELD;
|
|
||||||
inst.op0.field_offset = field.offset;
|
|
||||||
inst.op1.field_size = field.size;
|
|
||||||
inst.op2.field_alignment = field.alignment;
|
|
||||||
inst.op3.field_flags = field.flags; // Note -> This should be done explicitely with SPSLR_FLAG_FIELD_FIXED
|
|
||||||
|
|
||||||
if (!append_inst(inst))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
inst.opcode = SPSLR_RANDOMIZE;
|
|
||||||
inst.op0.randomize_target = tuid;
|
|
||||||
|
|
||||||
if (!append_inst(inst))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump ipins with addresses relative to vaddr_pivot
|
|
||||||
auto append_ipin = [&](const CU& cu, const IPIN& ipin) -> bool {
|
|
||||||
inst.opcode = SPSLR_IPATCH;
|
|
||||||
inst.op0.ipatch_ptr = ipin.hit->vaddr - vaddr_pivot;
|
|
||||||
inst.op1.ipatch_size = ipin.imm_size;
|
|
||||||
inst.op2.ipatch_target = cu.local_targets.at(ipin.local_target);
|
|
||||||
|
|
||||||
std::cout << "IPIN found at 0x" << std::hex << ipin.hit->vaddr << std::dec << std::endl;
|
|
||||||
|
|
||||||
if (!targets.at(inst.op2.ipatch_target).fields.contains(ipin.field_offset))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
inst.op3.ipatch_field = targets.at(inst.op2.ipatch_target).fields.at(ipin.field_offset).idx;
|
|
||||||
return append_inst(inst);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dump dpins with addresses relative to vaddr_pivot and components ordered by level
|
|
||||||
auto append_dpin = [&](const CU& cu, const DPIN& dpin) -> bool {
|
|
||||||
std::list<DPIN::COMPONENT> sorted_components = dpin.components;
|
|
||||||
sorted_components.sort([](const DPIN::COMPONENT& a, const DPIN::COMPONENT& b) {
|
|
||||||
return a.level > b.level; // Descending order
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const DPIN::COMPONENT& comp : sorted_components) {
|
|
||||||
inst.opcode = SPSLR_DPATCH;
|
|
||||||
inst.op0.dpatch_ptr = dpin.hit->vaddr + comp.offset - vaddr_pivot;
|
|
||||||
inst.op1.dpatch_target = cu.local_targets.at(comp.target);
|
|
||||||
|
|
||||||
std::cout << "DPIN found at 0x" << std::hex << dpin.hit->vaddr << std::dec << std::endl;
|
|
||||||
|
|
||||||
if (!append_inst(inst))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Dump all pins
|
|
||||||
for (const auto& [cu_uid, cu] : units) {
|
|
||||||
for (const auto& [ipin_sym, ipin] : cu.ipins) {
|
|
||||||
if (!append_ipin(cu, ipin))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& [dpin_sym, dpin] : cu.dpins) {
|
|
||||||
if (!append_dpin(cu, dpin))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exit patcher program
|
|
||||||
inst.opcode = SPSLR_EXIT;
|
|
||||||
if (!append_inst(inst))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
#include "symbol_collection.h"
|
|
||||||
#include "accumulation.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace LIEF::ELF;
|
|
||||||
|
|
||||||
GlobalSymtab global_syms;
|
|
||||||
|
|
||||||
bool collect_symbols(const std::unique_ptr<LIEF::ELF::Binary>& bin) {
|
|
||||||
if (!bin)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
global_syms.symbols.clear();
|
|
||||||
|
|
||||||
for (const Symbol& sym : bin->symbols()) {
|
|
||||||
if (sym.name().empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sym.type() != Symbol::TYPE::OBJECT &&
|
|
||||||
sym.type() != Symbol::TYPE::NOTYPE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sym.binding() != Symbol::BINDING::GLOBAL)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
VADDR vaddr = sym.value();
|
|
||||||
|
|
||||||
if (global_syms.symbols.contains(sym.name())) {
|
|
||||||
std::cerr << "Duplicate global symbol \"" << sym.name() << "\"!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
global_syms.symbols.emplace(sym.name(), vaddr);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool associate_symbols() {
|
|
||||||
for (auto& [cu_uid, cu] : units) {
|
|
||||||
for (auto& [ipin_sym, ipin] : cu.ipins) {
|
|
||||||
if (!global_syms.symbols.contains(ipin_sym)) {
|
|
||||||
std::cerr << "Unable to locate global ipin symbol \"" << ipin_sym << "\"" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipin.hit.emplace();
|
|
||||||
ipin.hit->vaddr = global_syms.symbols.at(ipin_sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& [dpin_sym, dpin] : cu.dpins) {
|
|
||||||
if (!global_syms.symbols.contains(dpin_sym)) {
|
|
||||||
std::cerr << "Unable to locate global dpin symbol \"" << dpin_sym << "\"" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dpin.hit.emplace();
|
|
||||||
dpin.hit->vaddr = global_syms.symbols.at(dpin_sym);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <LIEF/LIEF.hpp>
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
using VADDR = uint64_t;
|
|
||||||
|
|
||||||
struct GlobalSymtab {
|
|
||||||
std::unordered_map<std::string, VADDR> symbols;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern GlobalSymtab global_syms;
|
|
||||||
|
|
||||||
bool collect_symbols(const std::unique_ptr<LIEF::ELF::Binary>& bin);
|
|
||||||
bool associate_symbols();
|
|
||||||
|
|
||||||
2
patchcompile/CMakeLists.txt
Normal file
2
patchcompile/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
add_executable(spslr_patchcompile patchcompile.cpp accumulation.cpp emit.cpp)
|
||||||
|
set_target_properties(spslr_patchcompile PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED YES CXX_EXTENSIONS NO)
|
||||||
@ -37,8 +37,6 @@ static bool global_target_field_cmp(const TARGET& a, const TARGET& b) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool global_target_cmp(const TARGET& a, const TARGET& b) {
|
static bool global_target_cmp(const TARGET& a, const TARGET& b) {
|
||||||
// Note -> Later, use hash of type (generated by pinpoint plugin)
|
|
||||||
|
|
||||||
if (a.name != b.name)
|
if (a.name != b.name)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -9,23 +9,13 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct IPIN {
|
struct IPIN {
|
||||||
struct HIT {
|
|
||||||
uint64_t vaddr;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string symbol;
|
std::string symbol;
|
||||||
std::size_t local_target;
|
std::size_t local_target;
|
||||||
std::size_t field_offset;
|
std::size_t field_offset;
|
||||||
std::size_t imm_size;
|
std::size_t imm_size;
|
||||||
|
|
||||||
std::optional<HIT> hit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DPIN {
|
struct DPIN {
|
||||||
struct HIT {
|
|
||||||
uint64_t vaddr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct COMPONENT {
|
struct COMPONENT {
|
||||||
std::size_t offset;
|
std::size_t offset;
|
||||||
std::size_t level;
|
std::size_t level;
|
||||||
@ -34,8 +24,6 @@ struct DPIN {
|
|||||||
|
|
||||||
std::string symbol;
|
std::string symbol;
|
||||||
std::list<COMPONENT> components;
|
std::list<COMPONENT> components;
|
||||||
|
|
||||||
std::optional<HIT> hit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FIELD {
|
struct FIELD {
|
||||||
144
patchcompile/emit.cpp
Normal file
144
patchcompile/emit.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
#include "emit.h"
|
||||||
|
#include "accumulation.h"
|
||||||
|
|
||||||
|
#include <spslr_program.h>
|
||||||
|
|
||||||
|
static bool emit_header(std::ostream& out);
|
||||||
|
static bool emit_target_header(std::ostream& out, std::size_t uid, std::size_t size, std::size_t fieldcnt);
|
||||||
|
static bool emit_target_field(std::ostream& out, std::size_t offset, std::size_t size, std::size_t alignment, std::size_t flags);
|
||||||
|
static bool emit_target_randomize(std::ostream& out, std::size_t uid);
|
||||||
|
static bool emit_target(std::ostream& out, std::size_t uid, const TARGET& target);
|
||||||
|
static bool emit_ipin(std::ostream& out, const CU& cu, const IPIN& ipin);
|
||||||
|
static bool emit_dpin_component(std::ostream& out, std::size_t target, const std::string& sym, std::size_t offset);
|
||||||
|
static bool emit_dpin(std::ostream& out, const CU& cu, const DPIN& dpin);
|
||||||
|
static bool emit_exit(std::ostream& out);
|
||||||
|
|
||||||
|
bool emit_patcher_program_asm(std::ostream& out) {
|
||||||
|
if (!emit_header(out))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Dump all targets
|
||||||
|
for (const auto& [uid, target] : targets) {
|
||||||
|
if (!emit_target(out, uid, target))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dump all pins
|
||||||
|
for (const auto& [uid, cu] : units) {
|
||||||
|
for (const auto& [sym, pin] : cu.ipins) {
|
||||||
|
if (!emit_ipin(out, cu, pin))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& [sym, pin] : cu.dpins) {
|
||||||
|
if (!emit_dpin(out, cu, pin))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit patcher program
|
||||||
|
if (!emit_exit(out))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_header(std::ostream& out) {
|
||||||
|
out << ".section .spslr,\"a\",@progbits\n";
|
||||||
|
out << ".balign 1\n";
|
||||||
|
out << ".globl __spslr_program\n";
|
||||||
|
out << ".type __spslr_program, @object\n";
|
||||||
|
out << "__spslr_program:\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_target_header(std::ostream& out, std::size_t uid, std::size_t size, std::size_t fieldcnt) {
|
||||||
|
out << "\t.byte " << OPCODE_SPSLR_TARGET << "\n";
|
||||||
|
out << "\t.long " << uid << "\n";
|
||||||
|
out << "\t.long " << size << "\n";
|
||||||
|
out << "\t.long " << fieldcnt << "\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_target_field(std::ostream& out, std::size_t offset, std::size_t size, std::size_t alignment, std::size_t flags) {
|
||||||
|
out << "\t.byte " << OPCODE_SPSLR_FIELD << "\n";
|
||||||
|
out << "\t.long " << offset << "\n";
|
||||||
|
out << "\t.long " << size << "\n";
|
||||||
|
out << "\t.long " << alignment << "\n";
|
||||||
|
out << "\t.long " << flags << "\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_target_randomize(std::ostream& out, std::size_t uid) {
|
||||||
|
out << "\t.byte " << OPCODE_SPSLR_RANDOMIZE << "\n";
|
||||||
|
out << "\t.long " << uid << "\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_target(std::ostream& out, std::size_t uid, const TARGET& target) {
|
||||||
|
if (!emit_target_header(out, uid, target.size, target.fields.size()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto& [off, field] : target.fields) {
|
||||||
|
// Note -> Might want to do explicit flag mapping from pinpoint to selfpatch
|
||||||
|
if (!emit_target_field(out, field.offset, field.size, field.alignment, field.flags))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emit_target_randomize(out, uid))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_ipin(std::ostream& out, const CU& cu, const IPIN& ipin) {
|
||||||
|
std::size_t global_target = cu.local_targets.at(ipin.local_target);
|
||||||
|
|
||||||
|
if (!targets.contains(global_target))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const TARGET& target = targets.at(global_target);
|
||||||
|
|
||||||
|
if (!target.fields.contains(ipin.field_offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const FIELD& field = target.fields.at(ipin.field_offset);
|
||||||
|
|
||||||
|
out << "\t.byte " << OPCODE_SPSLR_IPATCH << "\n";
|
||||||
|
out << "\t.quad " << ipin.symbol << "\n";
|
||||||
|
out << "\t.long " << ipin.imm_size << "\n";
|
||||||
|
out << "\t.long " << global_target << "\n";
|
||||||
|
out << "\t.long " << field.idx << "\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_dpin_component(std::ostream& out, std::size_t target, const std::string& sym, std::size_t offset) {
|
||||||
|
out << "\t.byte " << OPCODE_SPSLR_DPATCH << "\n";
|
||||||
|
out << "\t.quad " << sym;
|
||||||
|
if (offset != 0)
|
||||||
|
out << " + " << offset;
|
||||||
|
out << "\n";
|
||||||
|
out << "\t.long " << target << "\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_dpin(std::ostream& out, const CU& cu, const DPIN& dpin) {
|
||||||
|
std::list<DPIN::COMPONENT> sorted_components = dpin.components;
|
||||||
|
sorted_components.sort([](const DPIN::COMPONENT& a, const DPIN::COMPONENT& b) {
|
||||||
|
return a.level > b.level; // Descending order to handle deeper nested first
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const DPIN::COMPONENT& component : sorted_components) {
|
||||||
|
std::size_t global_target = cu.local_targets.at(component.target);
|
||||||
|
if (!emit_dpin_component(out, global_target, dpin.symbol, component.offset))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool emit_exit(std::ostream& out) {
|
||||||
|
out << "\t.byte " << OPCODE_SPSLR_EXIT << "\n";
|
||||||
|
return !!out;
|
||||||
|
}
|
||||||
|
|
||||||
4
patchcompile/emit.h
Normal file
4
patchcompile/emit.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
bool emit_patcher_program_asm(std::ostream& out);
|
||||||
93
patchcompile/patchcompile.cpp
Normal file
93
patchcompile/patchcompile.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "accumulation.h"
|
||||||
|
#include "emit.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Notes:
|
||||||
|
Datapins for same var/symbol are randomized in order of their level, from bottom of nest to top
|
||||||
|
Between CUs, types with the same name HAVE TO HAVE the same layout -> randomized together
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
static option long_options[] = {
|
||||||
|
{ "help", no_argument, 0, 0 },
|
||||||
|
{ "out", required_argument, 0, 0 },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
int option_index = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
|
std::vector<std::string> spslr_files;
|
||||||
|
std::string out_file;
|
||||||
|
|
||||||
|
while ((c = getopt_long(argc, argv, "h:o:", long_options, &option_index)) == 0) {
|
||||||
|
const option& opt = long_options[option_index];
|
||||||
|
std::string optname { opt.name };
|
||||||
|
|
||||||
|
if (optname == "help") {
|
||||||
|
std::cout << "To use spslr_patchcompile, supply these arguments:" << std::endl;
|
||||||
|
std::cout << " --out=<file> (the compiled asm file to be written)" << std::endl;
|
||||||
|
std::cout << " <file>... (one or more .spslr metadata files)" << std::endl;
|
||||||
|
return 0;
|
||||||
|
} else if (optname == "out") {
|
||||||
|
out_file = std::string{ optarg };
|
||||||
|
} else {
|
||||||
|
std::cerr << "Invalid option, try \"--help\"!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_file.empty()) {
|
||||||
|
std::cerr << "Missing output file path, supply it via --out=<file>!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = optind; i < argc; ++i)
|
||||||
|
spslr_files.emplace_back(argv[i]);
|
||||||
|
|
||||||
|
if (spslr_files.empty()) {
|
||||||
|
std::cerr << "Missing spslr files! Pass one or more .spslr files as positional arguments." << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accumulate(spslr_files)) {
|
||||||
|
std::cerr << "Failed to accumulate data from spslr directory!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Gathered a total of " << targets.size() << " distinct targets from "
|
||||||
|
<< units.size() << " compilation units!" << std::endl;
|
||||||
|
|
||||||
|
std::filesystem::path out_path { out_file };
|
||||||
|
if (out_path.has_parent_path()) {
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(out_path.parent_path(), ec);
|
||||||
|
if (ec) {
|
||||||
|
std::cerr << "failed to create output directory '"
|
||||||
|
<< out_path.parent_path().string()
|
||||||
|
<< "': " << ec.message() << "\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream out(out_path);
|
||||||
|
if (!out) {
|
||||||
|
std::cerr << "Failed to open output file!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emit_patcher_program_asm(out)) {
|
||||||
|
std::cerr << "Failed to write emit patcher program!" << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@ -271,6 +271,7 @@ static bool field_map_add(std::map<std::size_t, TargetType::Field>& map, const T
|
|||||||
TargetType::Field tmp_field;
|
TargetType::Field tmp_field;
|
||||||
tmp_field.offset = field.offset;
|
tmp_field.offset = field.offset;
|
||||||
tmp_field.size = (field.size == 0 ? 1 : field.size);
|
tmp_field.size = (field.size == 0 ? 1 : field.size);
|
||||||
|
tmp_field.alignment = (field.alignment == 0 ? 1 : field.alignment);
|
||||||
tmp_field.flags = (field.size == 0 ? TargetType::Field::FLAG_DANGEROUS : 0) | field.flags;
|
tmp_field.flags = (field.size == 0 ? TargetType::Field::FLAG_DANGEROUS : 0) | field.flags;
|
||||||
|
|
||||||
// Overlaps are dangerous -> remove and integrate into member
|
// Overlaps are dangerous -> remove and integrate into member
|
||||||
@ -289,6 +290,7 @@ static bool field_map_add(std::map<std::size_t, TargetType::Field>& map, const T
|
|||||||
|
|
||||||
tmp_field.flags |= (existing_field.flags | TargetType::Field::FLAG_DANGEROUS);
|
tmp_field.flags |= (existing_field.flags | TargetType::Field::FLAG_DANGEROUS);
|
||||||
tmp_field.offset = combined_offset;
|
tmp_field.offset = combined_offset;
|
||||||
|
tmp_field.alignment = std::min(tmp_field.alignment, existing_field.alignment);
|
||||||
tmp_field.size = combined_size;
|
tmp_field.size = combined_size;
|
||||||
|
|
||||||
// Erase overlapping member
|
// Erase overlapping member
|
||||||
|
|||||||
3
plan.txt
3
plan.txt
@ -1,3 +0,0 @@
|
|||||||
Move patcher generation to pre-link stage
|
|
||||||
- Aggregate meta data files
|
|
||||||
- Generate patcher object file than links against symbols
|
|
||||||
@ -5,4 +5,4 @@ target_include_directories(spslr_selfpatch PUBLIC
|
|||||||
$<INSTALL_INTERFACE:include>
|
$<INSTALL_INTERFACE:include>
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(spslr_finalize PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # For spslr_program.h
|
target_include_directories(spslr_patchcompile PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src) # For spslr_program.h
|
||||||
|
|||||||
@ -6,18 +6,7 @@
|
|||||||
#include "targets.h"
|
#include "targets.h"
|
||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
|
|
||||||
const uint8_t* __spslr_program = NULL;
|
extern const uint8_t __spslr_program[];
|
||||||
|
|
||||||
static void* spslr_ptr_absolute(uint64_t relative) {
|
|
||||||
// To allow ASLR, all patcher addresses are relative to &__spslr_program
|
|
||||||
return ((uint8_t*)&__spslr_program) + relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void spslr_init_program_ptr() {
|
|
||||||
// Finalizer patches __spslr_program to be the relative offset from &__spslr_program to the program
|
|
||||||
uint64_t relative = (uint64_t)__spslr_program;
|
|
||||||
__spslr_program = (const uint8_t*)spslr_ptr_absolute(relative);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int spslr_do(const struct SPSLR_INST* inst) {
|
static int spslr_do(const struct SPSLR_INST* inst) {
|
||||||
if (!inst)
|
if (!inst)
|
||||||
@ -27,18 +16,18 @@ static int spslr_do(const struct SPSLR_INST* inst) {
|
|||||||
static uint32_t pending_fields_target = 0;
|
static uint32_t pending_fields_target = 0;
|
||||||
|
|
||||||
if (pending_fields) {
|
if (pending_fields) {
|
||||||
if (inst->opcode != SPSLR_FIELD) {
|
if (inst->op != SPSLR_FIELD) {
|
||||||
fprintf(stderr, "spslr_do encountered non field instruction where a field instruction was expected\n");
|
fprintf(stderr, "spslr_do encountered non field instruction where a field instruction was expected\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pending_fields--;
|
pending_fields--;
|
||||||
} else if (inst->opcode == SPSLR_FIELD) {
|
} else if (inst->op == SPSLR_FIELD) {
|
||||||
fprintf(stderr, "spslr_do encountered field instruction where none was expected\n");
|
fprintf(stderr, "spslr_do encountered field instruction where none was expected\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
pending_fields = inst->op2.target_fieldcnt;
|
pending_fields = inst->op2.target_fieldcnt;
|
||||||
pending_fields_target = inst->op0.target_uid;
|
pending_fields_target = inst->op0.target_uid;
|
||||||
@ -49,27 +38,22 @@ static int spslr_do(const struct SPSLR_INST* inst) {
|
|||||||
case SPSLR_RANDOMIZE:
|
case SPSLR_RANDOMIZE:
|
||||||
return spslr_randomize(inst->op0.randomize_target);
|
return spslr_randomize(inst->op0.randomize_target);
|
||||||
case SPSLR_IPATCH:
|
case SPSLR_IPATCH:
|
||||||
return spslr_ipatch(spslr_ptr_absolute(inst->op0.ipatch_ptr), inst->op1.ipatch_size,
|
return spslr_ipatch((void*)(uintptr_t)inst->op0.ipatch_ptr, inst->op1.ipatch_size,
|
||||||
inst->op2.ipatch_target, inst->op3.ipatch_field);
|
inst->op2.ipatch_target, inst->op3.ipatch_field);
|
||||||
case SPSLR_DPATCH:
|
case SPSLR_DPATCH:
|
||||||
return spslr_dpatch(spslr_ptr_absolute(inst->op0.dpatch_ptr), inst->op1.dpatch_target);
|
return spslr_dpatch((void*)(uintptr_t)inst->op0.dpatch_ptr, inst->op1.dpatch_target);
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void spslr_selfpatch() {
|
void spslr_selfpatch() {
|
||||||
if (!__spslr_program) {
|
const uint8_t* pc = __spslr_program;
|
||||||
fprintf(stderr, "spslr_selfpatch has no patcher program (finalize this binary to use SPSLR)\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
spslr_init_program_ptr();
|
|
||||||
|
|
||||||
int sz;
|
int sz;
|
||||||
struct SPSLR_INST inst;
|
struct SPSLR_INST inst;
|
||||||
while ((sz = spslr_inst_load(&inst, __spslr_program)) > 0) {
|
while ((sz = spslr_inst_load(&inst, pc)) > 0) {
|
||||||
if (inst.opcode == SPSLR_EXIT) {
|
if (inst.op == SPSLR_EXIT) {
|
||||||
spslr_targets_clear();
|
spslr_targets_clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -79,7 +63,7 @@ void spslr_selfpatch() {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
__spslr_program += sz;
|
pc += sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "spslr_selfpatch encountered invalid instruction\n");
|
fprintf(stderr, "spslr_selfpatch encountered invalid instruction\n");
|
||||||
|
|||||||
@ -6,7 +6,14 @@
|
|||||||
|
|
||||||
#define SPSLR_FLAG_FIELD_FIXED 1
|
#define SPSLR_FLAG_FIELD_FIXED 1
|
||||||
|
|
||||||
enum SPSLR_OPCODE {
|
#define OPCODE_SPSLR_TARGET 1
|
||||||
|
#define OPCODE_SPSLR_FIELD 2
|
||||||
|
#define OPCODE_SPSLR_RANDOMIZE 3
|
||||||
|
#define OPCODE_SPSLR_IPATCH 4
|
||||||
|
#define OPCODE_SPSLR_DPATCH 5
|
||||||
|
#define OPCODE_SPSLR_EXIT 6
|
||||||
|
|
||||||
|
enum SPSLR_OP {
|
||||||
SPSLR_TARGET, // uid, size, field count
|
SPSLR_TARGET, // uid, size, field count
|
||||||
SPSLR_FIELD, // offset, size, alignment, flags
|
SPSLR_FIELD, // offset, size, alignment, flags
|
||||||
SPSLR_RANDOMIZE, // target uid
|
SPSLR_RANDOMIZE, // target uid
|
||||||
@ -16,7 +23,7 @@ enum SPSLR_OPCODE {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SPSLR_INST {
|
struct SPSLR_INST {
|
||||||
enum SPSLR_OPCODE opcode;
|
enum SPSLR_OP op;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint32_t target_uid;
|
uint32_t target_uid;
|
||||||
@ -49,19 +56,19 @@ static inline int spslr_inst_dump_opcode(const struct SPSLR_INST* inst, uint8_t*
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
*buf = 1; return 1;
|
*buf = OPCODE_SPSLR_TARGET; return 1;
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
*buf = 2; return 1;
|
*buf = OPCODE_SPSLR_FIELD; return 1;
|
||||||
case SPSLR_RANDOMIZE:
|
case SPSLR_RANDOMIZE:
|
||||||
*buf = 3; return 1;
|
*buf = OPCODE_SPSLR_RANDOMIZE; return 1;
|
||||||
case SPSLR_IPATCH:
|
case SPSLR_IPATCH:
|
||||||
*buf = 4; return 1;
|
*buf = OPCODE_SPSLR_IPATCH; return 1;
|
||||||
case SPSLR_DPATCH:
|
case SPSLR_DPATCH:
|
||||||
*buf = 5; return 1;
|
*buf = OPCODE_SPSLR_DPATCH; return 1;
|
||||||
case SPSLR_EXIT:
|
case SPSLR_EXIT:
|
||||||
*buf = 6; return 1;
|
*buf = OPCODE_SPSLR_EXIT; return 1;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -72,18 +79,18 @@ static inline int spslr_inst_load_opcode(struct SPSLR_INST* inst, const uint8_t*
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (*buf) {
|
switch (*buf) {
|
||||||
case 1:
|
case OPCODE_SPSLR_TARGET:
|
||||||
inst->opcode = SPSLR_TARGET; return 1;
|
inst->op = SPSLR_TARGET; return 1;
|
||||||
case 2:
|
case OPCODE_SPSLR_FIELD:
|
||||||
inst->opcode = SPSLR_FIELD; return 1;
|
inst->op = SPSLR_FIELD; return 1;
|
||||||
case 3:
|
case OPCODE_SPSLR_RANDOMIZE:
|
||||||
inst->opcode = SPSLR_RANDOMIZE; return 1;
|
inst->op = SPSLR_RANDOMIZE; return 1;
|
||||||
case 4:
|
case OPCODE_SPSLR_IPATCH:
|
||||||
inst->opcode = SPSLR_IPATCH; return 1;
|
inst->op = SPSLR_IPATCH; return 1;
|
||||||
case 5:
|
case OPCODE_SPSLR_DPATCH:
|
||||||
inst->opcode = SPSLR_DPATCH; return 1;
|
inst->op = SPSLR_DPATCH; return 1;
|
||||||
case 6:
|
case OPCODE_SPSLR_EXIT:
|
||||||
inst->opcode = SPSLR_EXIT; return 1;
|
inst->op = SPSLR_EXIT; return 1;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -96,7 +103,7 @@ static inline int spslr_inst_dump_op0(const struct SPSLR_INST* inst, uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
DUMP_OP_RET(inst->op0.target_uid);
|
DUMP_OP_RET(inst->op0.target_uid);
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
@ -118,7 +125,7 @@ static inline int spslr_inst_load_op0(struct SPSLR_INST* inst, const uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
LOAD_OP_RET(inst->op0.target_uid);
|
LOAD_OP_RET(inst->op0.target_uid);
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
@ -140,7 +147,7 @@ static inline int spslr_inst_dump_op1(const struct SPSLR_INST* inst, uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
DUMP_OP_RET(inst->op1.target_size);
|
DUMP_OP_RET(inst->op1.target_size);
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
@ -161,7 +168,7 @@ static inline int spslr_inst_load_op1(struct SPSLR_INST* inst, const uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
LOAD_OP_RET(inst->op1.target_size);
|
LOAD_OP_RET(inst->op1.target_size);
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
@ -182,7 +189,7 @@ static inline int spslr_inst_dump_op2(const struct SPSLR_INST* inst, uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
DUMP_OP_RET(inst->op2.target_fieldcnt);
|
DUMP_OP_RET(inst->op2.target_fieldcnt);
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
@ -202,7 +209,7 @@ static inline int spslr_inst_load_op2(struct SPSLR_INST* inst, const uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_TARGET:
|
case SPSLR_TARGET:
|
||||||
LOAD_OP_RET(inst->op2.target_fieldcnt);
|
LOAD_OP_RET(inst->op2.target_fieldcnt);
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
@ -222,7 +229,7 @@ static inline int spslr_inst_dump_op3(const struct SPSLR_INST* inst, uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
DUMP_OP_RET(inst->op3.field_flags);
|
DUMP_OP_RET(inst->op3.field_flags);
|
||||||
case SPSLR_IPATCH:
|
case SPSLR_IPATCH:
|
||||||
@ -241,7 +248,7 @@ static inline int spslr_inst_load_op3(struct SPSLR_INST* inst, const uint8_t* bu
|
|||||||
if (!inst || !buf)
|
if (!inst || !buf)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
switch (inst->opcode) {
|
switch (inst->op) {
|
||||||
case SPSLR_FIELD:
|
case SPSLR_FIELD:
|
||||||
LOAD_OP_RET(inst->op3.field_flags);
|
LOAD_OP_RET(inst->op3.field_flags);
|
||||||
case SPSLR_IPATCH:
|
case SPSLR_IPATCH:
|
||||||
|
|||||||
@ -1,37 +1,68 @@
|
|||||||
add_executable(subject main.c second.c sub/second.c)
|
set(SUBJECT_SRC
|
||||||
target_include_directories(subject PRIVATE .)
|
main.c
|
||||||
add_dependencies(subject spslr_pinpoint spslr_finalize spslr_selfpatch)
|
second.c
|
||||||
target_link_libraries(subject PRIVATE spslr_selfpatch)
|
sub/second.c
|
||||||
|
)
|
||||||
|
|
||||||
set(SUBJECT_SPSLR_METADIR "${CMAKE_CURRENT_BINARY_DIR}/spslr")
|
set(SUBJECT_SPSLR_METADIR "${CMAKE_CURRENT_BINARY_DIR}/spslr")
|
||||||
set(SUBJECT_SPSLR_SRCROOT "${CMAKE_CURRENT_SOURCE_DIR}")
|
set(SUBJECT_SPSLR_SRCROOT "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
target_compile_options(subject PRIVATE -O1 -fplugin=$<TARGET_FILE:spslr_pinpoint> -fdump-tree-separate_offset -fdump-tree-asm_offset
|
|
||||||
-fplugin-arg-spslr_pinpoint-srcroot=${SUBJECT_SPSLR_SRCROOT}
|
|
||||||
-fplugin-arg-spslr_pinpoint-metadir=${SUBJECT_SPSLR_METADIR})
|
|
||||||
|
|
||||||
file(MAKE_DIRECTORY "${SUBJECT_SPSLR_METADIR}")
|
file(MAKE_DIRECTORY "${SUBJECT_SPSLR_METADIR}")
|
||||||
|
|
||||||
# Apply spslr_finalizer to subject
|
add_library(subject_objs OBJECT ${SUBJECT_SRC})
|
||||||
|
target_include_directories(subject_objs PRIVATE .)
|
||||||
|
target_link_libraries(subject_objs PRIVATE spslr_selfpatch)
|
||||||
|
add_dependencies(subject_objs spslr_pinpoint)
|
||||||
|
|
||||||
get_target_property(SUBJECT_SOURCES subject SOURCES)
|
target_compile_options(subject_objs PRIVATE
|
||||||
|
-O1
|
||||||
|
-fplugin=$<TARGET_FILE:spslr_pinpoint>
|
||||||
|
-fplugin-arg-spslr_pinpoint-srcroot=${SUBJECT_SPSLR_SRCROOT}
|
||||||
|
-fplugin-arg-spslr_pinpoint-metadir=${SUBJECT_SPSLR_METADIR}
|
||||||
|
)
|
||||||
|
|
||||||
set(SUBJECT_SPSLR_FILES "")
|
set(SUBJECT_SPSLR_FILES "")
|
||||||
foreach(src IN LISTS SUBJECT_SOURCES)
|
foreach(src IN LISTS SUBJECT_SRC)
|
||||||
get_filename_component(abs_src "${src}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
get_filename_component(abs_src "${src}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
file(RELATIVE_PATH rel_src "${SUBJECT_SPSLR_SRCROOT}" "${abs_src}")
|
file(RELATIVE_PATH rel_src "${SUBJECT_SPSLR_SRCROOT}" "${abs_src}")
|
||||||
file(TO_CMAKE_PATH "${rel_src}" rel_src)
|
file(TO_CMAKE_PATH "${rel_src}" rel_src)
|
||||||
list(APPEND SUBJECT_SPSLR_FILES "${SUBJECT_SPSLR_METADIR}/${rel_src}.spslr")
|
list(APPEND SUBJECT_SPSLR_FILES "${SUBJECT_SPSLR_METADIR}/${rel_src}.spslr")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
set(SUBJECT_SPSLR_ASM "${CMAKE_CURRENT_BINARY_DIR}/subject_spslr_program.S")
|
||||||
|
set(SUBJECT_SPSLR_OBJ "${CMAKE_CURRENT_BINARY_DIR}/subject_spslr_program.o")
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET subject
|
OUTPUT "${SUBJECT_SPSLR_ASM}"
|
||||||
POST_BUILD
|
COMMAND $<TARGET_FILE:spslr_patchcompile>
|
||||||
COMMAND $<TARGET_FILE:spslr_finalize>
|
--out=${SUBJECT_SPSLR_ASM}
|
||||||
--bin=$<TARGET_FILE:subject>
|
|
||||||
--out=${CMAKE_BINARY_DIR}/subject_final
|
|
||||||
${SUBJECT_SPSLR_FILES}
|
${SUBJECT_SPSLR_FILES}
|
||||||
COMMAND chmod +x ${CMAKE_BINARY_DIR}/subject_final
|
DEPENDS
|
||||||
|
spslr_patchcompile
|
||||||
|
$<TARGET_OBJECTS:subject_objs>
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${SUBJECT_SPSLR_OBJ}"
|
||||||
|
COMMAND ${CMAKE_C_COMPILER}
|
||||||
|
-c "${SUBJECT_SPSLR_ASM}"
|
||||||
|
-o "${SUBJECT_SPSLR_OBJ}"
|
||||||
|
DEPENDS "${SUBJECT_SPSLR_ASM}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
set_source_files_properties("${SUBJECT_SPSLR_OBJ}" PROPERTIES
|
||||||
|
GENERATED TRUE
|
||||||
|
EXTERNAL_OBJECT TRUE
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(subject
|
||||||
|
$<TARGET_OBJECTS:subject_objs>
|
||||||
|
"${SUBJECT_SPSLR_OBJ}"
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(subject PRIVATE .)
|
||||||
|
target_link_libraries(subject PRIVATE spslr_selfpatch)
|
||||||
|
add_dependencies(subject spslr_selfpatch)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user