Insert labels right at immediates
This commit is contained in:
parent
9555c48024
commit
ce7e75ecc9
@ -50,9 +50,9 @@ target <name> <local uid> <size> <field count>
|
|||||||
f <offset> <size> <alignment> <flags>
|
f <offset> <size> <alignment> <flags>
|
||||||
f <offset> <size> <alignment> <flags>
|
f <offset> <size> <alignment> <flags>
|
||||||
...
|
...
|
||||||
ipin <label> <target uid> <field offset>
|
ipin <label> <target uid> <field offset> <immediate size>
|
||||||
ipin <label> <target uid> <field offset>
|
ipin <label> <target uid> <field offset> <immediate size>
|
||||||
ipin <label> <target uid> <field offset>
|
ipin <label> <target uid> <field offset> <immediate size>
|
||||||
...
|
...
|
||||||
dpin <local/global> <symbol> <offset> <level> <target uid>
|
dpin <local/global> <symbol> <offset> <level> <target uid>
|
||||||
dpin <local/global> <symbol> <offset> <level> <target uid>
|
dpin <local/global> <symbol> <offset> <level> <target uid>
|
||||||
@ -157,7 +157,8 @@ static bool accumulate_file(const fs::path& path) {
|
|||||||
continue;
|
continue;
|
||||||
} else if (type == "ipin") {
|
} else if (type == "ipin") {
|
||||||
IPIN ipin;
|
IPIN ipin;
|
||||||
if (!(iss >> ipin.symbol) || !(iss >> ipin.local_target) || !(iss >> ipin.field_offset)) {
|
if (!(iss >> ipin.symbol) || !(iss >> ipin.local_target) ||
|
||||||
|
!(iss >> ipin.field_offset) || !(iss >> ipin.imm_size)) {
|
||||||
std::cerr << "Failed to parse ipin declaration!" << std::endl;
|
std::cerr << "Failed to parse ipin declaration!" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,13 +10,12 @@
|
|||||||
struct IPIN {
|
struct IPIN {
|
||||||
struct HIT {
|
struct HIT {
|
||||||
uint64_t vaddr;
|
uint64_t vaddr;
|
||||||
uint32_t imm_offset;
|
|
||||||
uint32_t imm_size;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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::optional<HIT> hit;
|
std::optional<HIT> hit;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,7 +22,6 @@ Notes:
|
|||||||
|
|
||||||
using namespace LIEF::ELF;
|
using namespace LIEF::ELF;
|
||||||
|
|
||||||
static bool disassemble_ipin(const Section* text, IPIN::HIT& pin);
|
|
||||||
static bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector<uint8_t>& program);
|
static bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector<uint8_t>& program);
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
@ -104,24 +103,13 @@ int main(int argc, char** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each ipin, disassemble instruction and find immediate offset
|
// Make sure all ipins were located
|
||||||
const Section* text = bin->get_section(".text");
|
|
||||||
if (!text) {
|
|
||||||
std::cerr << "Unable to locate .text section for ipin disassembly!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& [cu_uid, cu] : units) {
|
for (auto& [cu_uid, cu] : units) {
|
||||||
for (auto& [_, ipin] : cu.ipins) {
|
for (auto& [_, ipin] : cu.ipins) {
|
||||||
if (!ipin.hit.has_value()) {
|
if (!ipin.hit.has_value()) {
|
||||||
std::cerr << "Encountered ipin without vaddr!" << std::endl;
|
std::cerr << "Encountered ipin without vaddr!" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!disassemble_ipin(text, ipin.hit.value())) {
|
|
||||||
std::cerr << "Failed to disassemble ipin!" << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,10 +247,12 @@ bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector<uint8_t>& progra
|
|||||||
// Dump ipins with addresses relative to vaddr_pivot
|
// Dump ipins with addresses relative to vaddr_pivot
|
||||||
auto append_ipin = [&](const CU& cu, const IPIN& ipin) -> bool {
|
auto append_ipin = [&](const CU& cu, const IPIN& ipin) -> bool {
|
||||||
inst.opcode = SPSLR_IPATCH;
|
inst.opcode = SPSLR_IPATCH;
|
||||||
inst.op0.ipatch_ptr = ipin.hit->vaddr + ipin.hit->imm_offset - vaddr_pivot;
|
inst.op0.ipatch_ptr = ipin.hit->vaddr - vaddr_pivot;
|
||||||
inst.op1.ipatch_size = ipin.hit->imm_size;
|
inst.op1.ipatch_size = ipin.imm_size;
|
||||||
inst.op2.ipatch_target = cu.local_targets.at(ipin.local_target);
|
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))
|
if (!targets.at(inst.op2.ipatch_target).fields.contains(ipin.field_offset))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -319,31 +309,3 @@ bool assemble_patcher_program(uint64_t vaddr_pivot, std::vector<uint8_t>& progra
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool disassemble_ipin(const Section* text, IPIN::HIT& pin) {
|
|
||||||
if (!text)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint64_t text_begin = text->virtual_address();
|
|
||||||
uint64_t text_size = text->size();
|
|
||||||
auto text_data = text->content();
|
|
||||||
|
|
||||||
uint64_t pin_addr = pin.vaddr;
|
|
||||||
|
|
||||||
if (pin_addr < text_begin || pin_addr >= text_begin + text_size)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint64_t pin_offset = pin_addr - text_begin;
|
|
||||||
|
|
||||||
// 32 bit mov of immediate to 64 bit register: 0x48 0xc7 [8 bit reg] [32 bit immediate]
|
|
||||||
|
|
||||||
if (text_data[pin_offset] != 0x48 || text_data[pin_offset + 1] != 0xc7) {
|
|
||||||
std::cerr << "Ipin uses not yet handled instruction!" << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pin.imm_offset = 3;
|
|
||||||
pin.imm_size = 4;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@ -99,8 +99,6 @@ bool associate_symbols() {
|
|||||||
|
|
||||||
ipin.hit.emplace();
|
ipin.hit.emplace();
|
||||||
ipin.hit->vaddr = lsyms.symbols.at(ipin_sym);
|
ipin.hit->vaddr = lsyms.symbols.at(ipin_sym);
|
||||||
ipin.hit->imm_offset = 0;
|
|
||||||
ipin.hit->imm_size = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& [dpin_sym, dpin] : cu.dpins) {
|
for (auto& [dpin_sym, dpin] : cu.dpins) {
|
||||||
|
|||||||
@ -10,4 +10,5 @@ target_include_directories(spslr_pinpoint PRIVATE ${GCC_PLUGIN_PATH}/include ${C
|
|||||||
|
|
||||||
add_subdirectory(stage0)
|
add_subdirectory(stage0)
|
||||||
add_subdirectory(stage1)
|
add_subdirectory(stage1)
|
||||||
|
add_subdirectory(stage2)
|
||||||
add_subdirectory(final)
|
add_subdirectory(final)
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <final.h>
|
#include <final.h>
|
||||||
#include <stage0.h>
|
#include <stage0.h>
|
||||||
#include <stage1.h>
|
#include <stage2.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -153,9 +153,9 @@ void on_finish_unit(void* plugin_data, void* user_data) {
|
|||||||
|
|
||||||
// Dump all instruction pins
|
// Dump all instruction pins
|
||||||
|
|
||||||
for (const auto& [uid, ipin] : S1InstructionPin::all()) {
|
for (const auto& [uid, ipin] : s2_pins()) {
|
||||||
// ipin <label> <target uid> <field offset>
|
// ipin <symbol> <target uid> <field offset> <immediate size>
|
||||||
out << "ipin " << SPSLR_PINPOINT_STAGE1_PIN << uid << " "
|
out << "ipin " << ipin.symbol << " "
|
||||||
<< ipin.target << " " << ipin.offset << std::endl;
|
<< ipin.target << " " << ipin.offset << " " << ipin.imm_size << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <stage0.h>
|
#include <stage0.h>
|
||||||
#include <stage1.h>
|
#include <stage1.h>
|
||||||
|
#include <stage2.h>
|
||||||
#include <final.h>
|
#include <final.h>
|
||||||
|
|
||||||
int plugin_is_GPL_compatible;
|
int plugin_is_GPL_compatible;
|
||||||
@ -47,7 +48,7 @@ int plugin_init(struct plugin_name_args* plugin_info, struct plugin_gcc_version*
|
|||||||
separate_offset_pass_info.pos_op = PASS_POS_INSERT_AFTER;
|
separate_offset_pass_info.pos_op = PASS_POS_INSERT_AFTER;
|
||||||
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &separate_offset_pass_info);
|
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &separate_offset_pass_info);
|
||||||
|
|
||||||
// Stage 1 -> stage 0 separators are replaced with inline assembly
|
// Stage 1 -> stage 0 separators are replaced with inline assembly markers
|
||||||
|
|
||||||
struct register_pass_info asm_offset_pass_info;
|
struct register_pass_info asm_offset_pass_info;
|
||||||
asm_offset_pass_info.pass = new asm_offset_pass(nullptr);
|
asm_offset_pass_info.pass = new asm_offset_pass(nullptr);
|
||||||
@ -56,6 +57,15 @@ int plugin_init(struct plugin_name_args* plugin_info, struct plugin_gcc_version*
|
|||||||
asm_offset_pass_info.pos_op = PASS_POS_INSERT_AFTER;
|
asm_offset_pass_info.pos_op = PASS_POS_INSERT_AFTER;
|
||||||
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &asm_offset_pass_info);
|
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &asm_offset_pass_info);
|
||||||
|
|
||||||
|
// Stage 2 -> stage 1 markers are replaced with assembled offset-load instructions with labeled immediates
|
||||||
|
|
||||||
|
struct register_pass_info rtl_pin_lower_pass_info;
|
||||||
|
rtl_pin_lower_pass_info.pass = new rtl_pin_lower_pass(nullptr);
|
||||||
|
rtl_pin_lower_pass_info.ref_pass_instance_number = 1;
|
||||||
|
rtl_pin_lower_pass_info.reference_pass_name = "final";
|
||||||
|
rtl_pin_lower_pass_info.pos_op = PASS_POS_INSERT_BEFORE;
|
||||||
|
register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &rtl_pin_lower_pass_info);
|
||||||
|
|
||||||
// Final stage -> dump accumulated information
|
// Final stage -> dump accumulated information
|
||||||
|
|
||||||
register_callback(plugin_info->base_name, PLUGIN_FINISH_UNIT, on_finish_unit, NULL);
|
register_callback(plugin_info->base_name, PLUGIN_FINISH_UNIT, on_finish_unit, NULL);
|
||||||
|
|||||||
@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
#define SPSLR_ATTRIBUTE "spslr"
|
#define SPSLR_ATTRIBUTE "spslr"
|
||||||
#define SPSLR_PINPOINT_STAGE0_SEPARATOR "__spslr_offsetof"
|
#define SPSLR_PINPOINT_STAGE0_SEPARATOR "__spslr_offsetof"
|
||||||
#define SPSLR_PINPOINT_STAGE1_PIN "__spslr_ipin_" /* suffixed with "<uid>" */
|
|
||||||
#define SPSLR_PINPOINT_CU_UID_LABEL "__spslr_cu_" /* suffixed with "<uid>" */
|
#define SPSLR_PINPOINT_CU_UID_LABEL "__spslr_cu_" /* suffixed with "<uid>" */
|
||||||
#define SPSLR_PINFILE_EXTENSION ".spslr"
|
#define SPSLR_PINFILE_EXTENSION ".spslr"
|
||||||
|
#define SPSLR_PINPOINT_STAGE2_PIN "__spslr_ipin_" /* suffixed with "<uid>" */
|
||||||
|
|||||||
17
pinpoint/safegcc/safe-rtl.h
Normal file
17
pinpoint/safegcc/safe-rtl.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <safe-gcc-plugin.h>
|
||||||
|
|
||||||
|
#ifndef SAFEGCC_RTL_H
|
||||||
|
#define SAFEGCC_RTL_H
|
||||||
|
|
||||||
|
#include <rtl.h>
|
||||||
|
#include <rtl-iter.h>
|
||||||
|
#include <memmodel.h>
|
||||||
|
#include <emit-rtl.h>
|
||||||
|
#include <function.h>
|
||||||
|
#include <expr.h>
|
||||||
|
#include <hard-reg-set.h>
|
||||||
|
|
||||||
|
#undef toupper
|
||||||
|
#undef tolower
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -1,8 +1,9 @@
|
|||||||
#include <stage0.h>
|
#include <stage0.h>
|
||||||
#include <stage1.h>
|
#include <stage1.h>
|
||||||
|
#include <stage2.h>
|
||||||
|
|
||||||
void on_start_unit(void* plugin_data, void* user_data) {
|
void on_start_unit(void* plugin_data, void* user_data) {
|
||||||
TargetType::reset();
|
TargetType::reset();
|
||||||
DataPin::reset();
|
DataPin::reset();
|
||||||
S1InstructionPin::reset();
|
s2_pins_reset();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,18 +4,9 @@
|
|||||||
#include <pinpoint_error.h>
|
#include <pinpoint_error.h>
|
||||||
#include <pinpoint_config.h>
|
#include <pinpoint_config.h>
|
||||||
|
|
||||||
static UID next_pin_uid = 0;
|
const char* s1_ipin_marker = "/*spslr_s1_ipin_marker*/";
|
||||||
static std::unordered_map<UID, S1InstructionPin> pins;
|
|
||||||
|
|
||||||
const std::unordered_map<UID, S1InstructionPin>& S1InstructionPin::all() {
|
|
||||||
return pins;
|
|
||||||
}
|
|
||||||
|
|
||||||
void S1InstructionPin::reset() {
|
|
||||||
pins.clear();
|
|
||||||
next_pin_uid = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/*
|
||||||
static char asm_str_buf[1024];
|
static char asm_str_buf[1024];
|
||||||
|
|
||||||
static const char* make_asm_noarch(UID uid) {
|
static const char* make_asm_noarch(UID uid) {
|
||||||
@ -40,6 +31,7 @@ static const char* make_asm(UID uid, S1InstructionPin::ARCH& arch) {
|
|||||||
return make_asm_noarch(uid);
|
return make_asm_noarch(uid);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static tree make_asm_operand(const char* constraint_text, tree operand_tree) {
|
static tree make_asm_operand(const char* constraint_text, tree operand_tree) {
|
||||||
tree constraint_str = build_string(strlen (constraint_text) + 1, constraint_text);
|
tree constraint_str = build_string(strlen (constraint_text) + 1, constraint_text);
|
||||||
@ -52,15 +44,7 @@ static gimple* make_stage1_pin(tree lhs, UID target, std::size_t offset) {
|
|||||||
if (!lhs)
|
if (!lhs)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
UID uid = next_pin_uid++;
|
const char* asm_str = s1_ipin_marker; // Asm is inserted at a later stage
|
||||||
|
|
||||||
S1InstructionPin pin;
|
|
||||||
pin.target = target;
|
|
||||||
pin.offset = offset;
|
|
||||||
|
|
||||||
const char* asm_str = make_asm(uid, pin.arch);
|
|
||||||
if (!asm_str)
|
|
||||||
pinpoint_fatal("make_stage1_pin failed to generate asm string");
|
|
||||||
|
|
||||||
tree arg0 = build_int_cst(size_type_node, target);
|
tree arg0 = build_int_cst(size_type_node, target);
|
||||||
tree arg1 = build_int_cst(size_type_node, offset);
|
tree arg1 = build_int_cst(size_type_node, offset);
|
||||||
@ -76,15 +60,9 @@ static gimple* make_stage1_pin(tree lhs, UID target, std::size_t offset) {
|
|||||||
if (!new_gasm)
|
if (!new_gasm)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
/*
|
// Asm is intentionally not marked as volatile, gcc may remove it if output is never used
|
||||||
TODO
|
gimple_asm_set_volatile(new_gasm, false);
|
||||||
These asm statements should not actually be volatile.
|
|
||||||
Instead, a final pass has to detect which have been removed.
|
|
||||||
Only data about still present ipins should be given to finalizer!
|
|
||||||
*/
|
|
||||||
gimple_asm_set_volatile(new_gasm, true);
|
|
||||||
|
|
||||||
pins.emplace(uid, pin);
|
|
||||||
return new_gasm;
|
return new_gasm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,17 +3,7 @@
|
|||||||
#include <stage0.h>
|
#include <stage0.h>
|
||||||
#include <safe-gimple.h>
|
#include <safe-gimple.h>
|
||||||
|
|
||||||
struct S1InstructionPin {
|
extern const char* s1_ipin_marker;
|
||||||
enum ARCH {
|
|
||||||
NONE, X86_64
|
|
||||||
} arch;
|
|
||||||
|
|
||||||
UID target;
|
|
||||||
std::size_t offset;
|
|
||||||
|
|
||||||
static const std::unordered_map<UID, S1InstructionPin>& all();
|
|
||||||
static void reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct asm_offset_pass : gimple_opt_pass {
|
struct asm_offset_pass : gimple_opt_pass {
|
||||||
asm_offset_pass(gcc::context* ctxt);
|
asm_offset_pass(gcc::context* ctxt);
|
||||||
|
|||||||
2
pinpoint/stage2/CMakeLists.txt
Normal file
2
pinpoint/stage2/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
target_sources(spslr_pinpoint PRIVATE rtl_pin_lower_pass.cpp)
|
||||||
|
target_include_directories(spslr_pinpoint PRIVATE .)
|
||||||
247
pinpoint/stage2/rtl_pin_lower_pass.cpp
Normal file
247
pinpoint/stage2/rtl_pin_lower_pass.cpp
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
#include <stage2.h>
|
||||||
|
#include <stage1.h>
|
||||||
|
#include <pinpoint_config.h>
|
||||||
|
#include <pinpoint_error.h>
|
||||||
|
|
||||||
|
#include <safe-rtl.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
static UID next_stage2_pin_uid = 0;
|
||||||
|
static std::unordered_map<UID, S2InstructionPin> pins;
|
||||||
|
|
||||||
|
const std::unordered_map<UID, S2InstructionPin>& s2_pins() {
|
||||||
|
return pins;
|
||||||
|
}
|
||||||
|
|
||||||
|
void s2_pins_reset() {
|
||||||
|
pins.clear();
|
||||||
|
next_stage2_pin_uid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UID s2_pin_allocate(const S2InstructionPin& pin) {
|
||||||
|
UID uid = next_stage2_pin_uid++;
|
||||||
|
pins.emplace(uid, pin);
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool read_marker_inputs(rtx src, UID& target, std::size_t& offset) {
|
||||||
|
rtx in0 = ASM_OPERANDS_INPUT(src, 0);
|
||||||
|
rtx in1 = ASM_OPERANDS_INPUT(src, 1);
|
||||||
|
|
||||||
|
if (!CONST_INT_P(in0) || !CONST_INT_P(in1))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
target = (UID) INTVAL(in0);
|
||||||
|
offset = (std::size_t) INTVAL(in1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool extract_set_from_pat(rtx pat, rtx& set_out) {
|
||||||
|
if (!pat)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (GET_CODE(pat) == SET) {
|
||||||
|
set_out = pat;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GET_CODE(pat) == PARALLEL) {
|
||||||
|
int len = XVECLEN(pat, 0);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
rtx elem = XVECEXP(pat, 0, i);
|
||||||
|
if (elem && GET_CODE(elem) == SET) {
|
||||||
|
set_out = elem;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool get_regno_from_dest(rtx dest, unsigned& regno) {
|
||||||
|
if (!dest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (REG_P(dest)) {
|
||||||
|
regno = REGNO(dest);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GET_CODE(dest) == SUBREG) {
|
||||||
|
rtx inner = SUBREG_REG(dest);
|
||||||
|
if (inner && REG_P(inner)) {
|
||||||
|
regno = REGNO(inner);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_stage1_marker_insn(
|
||||||
|
rtx_insn* insn,
|
||||||
|
rtx& set_rtx,
|
||||||
|
rtx& asm_src,
|
||||||
|
UID& target,
|
||||||
|
std::size_t& offset,
|
||||||
|
unsigned& regno
|
||||||
|
) {
|
||||||
|
if (!insn || !INSN_P(insn))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rtx pat = PATTERN(insn);
|
||||||
|
if (!extract_set_from_pat(pat, set_rtx))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rtx dest = SET_DEST(set_rtx);
|
||||||
|
rtx src = SET_SRC(set_rtx);
|
||||||
|
|
||||||
|
if (!src || GET_CODE(src) != ASM_OPERANDS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* templ = ASM_OPERANDS_TEMPLATE(src);
|
||||||
|
if (!templ)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* safer than exact strcmp */
|
||||||
|
if (!std::strstr(templ, s1_ipin_marker))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!read_marker_inputs(src, target, offset))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!get_regno_from_dest(dest, regno))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
asm_src = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const pass_data rtl_pin_lower_pass_data = {
|
||||||
|
RTL_PASS, /* type */
|
||||||
|
"spslr_rtl_pin_lower", /* name */
|
||||||
|
OPTGROUP_NONE, /* optinfo_flags */
|
||||||
|
TV_NONE, /* tv_id */
|
||||||
|
PROP_rtl, /* properties_required */
|
||||||
|
0, /* properties_provided */
|
||||||
|
0, /* properties_destroyed */
|
||||||
|
0, /* todo_flags_start */
|
||||||
|
0 /* todo_flags_finish */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EncodedReg {
|
||||||
|
unsigned rex;
|
||||||
|
unsigned modrm;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Maps the final hard register to:
|
||||||
|
* mov r/m64, imm32 => REX.W + C7 /0 id
|
||||||
|
* with mod=11 and r/m = selected GPR
|
||||||
|
*
|
||||||
|
* This uses reg_names[] because it is easy to keep backend-local and
|
||||||
|
* avoids depending on x86 internal enum values here.
|
||||||
|
*
|
||||||
|
* If your GCC build uses slightly different names, adjust the table.
|
||||||
|
*/
|
||||||
|
static bool x86_64_encode_mov_imm32_to_reg(unsigned regno, EncodedReg& out) {
|
||||||
|
if (!HARD_REGISTER_NUM_P(regno))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* name = reg_names[regno];
|
||||||
|
if (!name)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct RegMapEntry {
|
||||||
|
const char* name;
|
||||||
|
unsigned rex;
|
||||||
|
unsigned rm;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const RegMapEntry regmap[] = {
|
||||||
|
{ "ax", 0x48, 0 }, { "cx", 0x48, 1 }, { "dx", 0x48, 2 }, { "bx", 0x48, 3 },
|
||||||
|
{ "sp", 0x48, 4 }, { "bp", 0x48, 5 }, { "si", 0x48, 6 }, { "di", 0x48, 7 },
|
||||||
|
|
||||||
|
{ "r8", 0x49, 0 }, { "r9", 0x49, 1 }, { "r10", 0x49, 2 }, { "r11", 0x49, 3 },
|
||||||
|
{ "r12", 0x49, 4 }, { "r13", 0x49, 5 }, { "r14", 0x49, 6 }, { "r15", 0x49, 7 },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& e : regmap) {
|
||||||
|
if (std::strcmp(name, e.name) == 0) {
|
||||||
|
out.rex = e.rex;
|
||||||
|
out.modrm = 0xC0 | e.rm; /* mod=11, /0, rm=e.rm */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string make_final_x86_64_asm(UID pin_uid, const EncodedReg& enc, std::size_t imm) {
|
||||||
|
char buf[256];
|
||||||
|
std::snprintf(
|
||||||
|
buf, sizeof(buf),
|
||||||
|
".byte 0x%02x, 0xC7, 0x%02x\n"
|
||||||
|
SPSLR_PINPOINT_STAGE2_PIN "%lu:\n"
|
||||||
|
".long %zu",
|
||||||
|
enc.rex,
|
||||||
|
enc.modrm,
|
||||||
|
static_cast<unsigned long>(pin_uid),
|
||||||
|
imm
|
||||||
|
);
|
||||||
|
return std::string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool lower_stage1_marker_insn(rtx_insn* insn) {
|
||||||
|
rtx set_rtx = nullptr;
|
||||||
|
rtx asm_src = nullptr;
|
||||||
|
UID target = 0;
|
||||||
|
std::size_t offset = 0;
|
||||||
|
unsigned regno = 0;
|
||||||
|
|
||||||
|
if (!is_stage1_marker_insn(insn, set_rtx, asm_src, target, offset, regno))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
EncodedReg enc {};
|
||||||
|
if (!x86_64_encode_mov_imm32_to_reg(regno, enc)) {
|
||||||
|
pinpoint_fatal("stage2: unsupported hard register for ipin lowering: regno=%u", (unsigned)regno);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
S2InstructionPin pin;
|
||||||
|
pin.target = target;
|
||||||
|
pin.offset = offset;
|
||||||
|
pin.imm_size = 4;
|
||||||
|
|
||||||
|
UID pin_uid = s2_pin_allocate(pin);
|
||||||
|
|
||||||
|
auto it = pins.find(pin_uid);
|
||||||
|
if (it == pins.end())
|
||||||
|
pinpoint_fatal("stage2: internal error after s2_pin_allocate");
|
||||||
|
|
||||||
|
it->second.symbol = std::string(SPSLR_PINPOINT_STAGE2_PIN) + std::to_string(pin_uid);
|
||||||
|
|
||||||
|
std::string final_asm = make_final_x86_64_asm(pin_uid, enc, offset);
|
||||||
|
|
||||||
|
ASM_OPERANDS_TEMPLATE(asm_src) = ggc_strdup(final_asm.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtl_pin_lower_pass::rtl_pin_lower_pass(gcc::context* ctxt)
|
||||||
|
: rtl_opt_pass(rtl_pin_lower_pass_data, ctxt) {}
|
||||||
|
|
||||||
|
unsigned int rtl_pin_lower_pass::execute(function* fn) {
|
||||||
|
(void) fn;
|
||||||
|
|
||||||
|
for (rtx_insn* insn = get_insns(); insn; insn = NEXT_INSN(insn)) {
|
||||||
|
(void) lower_stage1_marker_insn(insn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
22
pinpoint/stage2/stage2.h
Normal file
22
pinpoint/stage2/stage2.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stage0.h>
|
||||||
|
#include <safe-rtl.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct S2InstructionPin {
|
||||||
|
UID target;
|
||||||
|
std::size_t offset;
|
||||||
|
std::size_t imm_size;
|
||||||
|
std::string symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::unordered_map<UID, S2InstructionPin>& s2_pins();
|
||||||
|
void s2_pins_reset();
|
||||||
|
UID s2_pin_allocate(const S2InstructionPin& pin);
|
||||||
|
|
||||||
|
struct rtl_pin_lower_pass : rtl_opt_pass {
|
||||||
|
rtl_pin_lower_pass(gcc::context* ctxt);
|
||||||
|
unsigned int execute(function* fn) override;
|
||||||
|
};
|
||||||
9
plan.txt
Normal file
9
plan.txt
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Make labels globally unique
|
||||||
|
- Use hash of object file path to identify CU
|
||||||
|
|
||||||
|
Collect alignment data on struct members
|
||||||
|
Fix bit fields and dynamic size fields (at end of structs) in place
|
||||||
|
|
||||||
|
Move patcher generation to pre-link stage
|
||||||
|
- Aggregate meta data files
|
||||||
|
- Generate patcher object file than links against symbols
|
||||||
Loading…
Reference in New Issue
Block a user