mirror of
https://github.com/lief-project/LIEF
synced 2026-06-08 15:30:44 +00:00
Add support for contextual assembly patching
This commit is contained in:
@@ -367,9 +367,12 @@ void create<Binary>(nb::module_& m) {
|
||||
)doc"_doc
|
||||
)
|
||||
|
||||
.def("assemble", [] (Binary& self, uint64_t address, const std::string& Asm) {
|
||||
return nb::to_bytes(self.assemble(address, Asm));
|
||||
}, "address"_a, "assembly"_a,
|
||||
.def("assemble",
|
||||
[] (Binary& self, uint64_t address, const std::string& Asm,
|
||||
assembly::AssemblerConfig& config)
|
||||
{
|
||||
return nb::to_bytes(self.assemble(address, Asm, config));
|
||||
}, "address"_a, "assembly"_a, "config"_a = assembly::AssemblerConfig::default_config(),
|
||||
R"doc(
|
||||
Assemble **and patch** the provided assembly code at the specified address.
|
||||
|
||||
@@ -383,6 +386,9 @@ void create<Binary>(nb::module_& m) {
|
||||
xor rax, rbx;
|
||||
mov rcx, rax;
|
||||
""")
|
||||
|
||||
If you need to configure the assembly engine or to define addresses for
|
||||
symbols, you can provide your own :class:`~.assembly.AssemblerConfig` instance.
|
||||
)doc"_doc
|
||||
)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ target_sources(pyLIEF PRIVATE
|
||||
init.cpp
|
||||
pyEngine.cpp
|
||||
pyInstruction.cpp
|
||||
pyAssemblerConfig.cpp
|
||||
)
|
||||
|
||||
add_subdirectory(aarch64)
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace LIEF::assembly {
|
||||
class Engine;
|
||||
class Instruction;
|
||||
class AssemblerConfig;
|
||||
}
|
||||
|
||||
namespace LIEF::assembly::py {
|
||||
@@ -20,6 +21,7 @@ void init(nb::module_& m) {
|
||||
|
||||
create<LIEF::assembly::Engine>(mod);
|
||||
create<LIEF::assembly::Instruction>(mod);
|
||||
create<LIEF::assembly::AssemblerConfig>(mod);
|
||||
|
||||
aarch64::py::init(mod);
|
||||
x86::py::init(mod);
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#include "LIEF/asm/AssemblerConfig.hpp"
|
||||
#include "asm/pyAssembly.hpp"
|
||||
|
||||
#include <nanobind/stl/string.h>
|
||||
#include <nanobind/trampoline.h>
|
||||
#include "nanobind/extra/stl/lief_optional.h"
|
||||
|
||||
#include "nanobind/extra/stl/lief_optional.h"
|
||||
|
||||
namespace LIEF::assembly::py {
|
||||
|
||||
class PyAssemblerConfig : public assembly::AssemblerConfig {
|
||||
public:
|
||||
static constexpr auto NB_NUM_SLOTS = 3;
|
||||
NB_TRAMPOLINE(assembly::AssemblerConfig, NB_NUM_SLOTS);
|
||||
|
||||
optional<uint64_t> resolve_symbol(const std::string& name) override {
|
||||
NB_OVERRIDE(resolve_symbol, name);
|
||||
}
|
||||
|
||||
~PyAssemblerConfig() override = default;
|
||||
};
|
||||
|
||||
template<>
|
||||
void create<assembly::AssemblerConfig>(nb::module_& m) {
|
||||
nb::class_<assembly::AssemblerConfig, PyAssemblerConfig> obj(m, "AssemblerConfig",
|
||||
R"doc(
|
||||
This class exposes the different elements that can be configured to assemble
|
||||
code.
|
||||
)doc"_doc
|
||||
);
|
||||
|
||||
nb::enum_<assembly::AssemblerConfig::DIALECT>(obj, "DIALECT",
|
||||
"The different supported dialects"_doc
|
||||
)
|
||||
.value("DEFAULT_DIALECT", assembly::AssemblerConfig::DIALECT::DEFAULT_DIALECT)
|
||||
.value("X86_INTEL", assembly::AssemblerConfig::DIALECT::X86_INTEL,
|
||||
"Intel syntax"_doc)
|
||||
.value("X86_ATT", assembly::AssemblerConfig::DIALECT::X86_ATT,
|
||||
"AT&T syntax"_doc)
|
||||
;
|
||||
|
||||
obj
|
||||
.def(nb::init<>())
|
||||
.def_static("default_config", &assembly::AssemblerConfig::default_config,
|
||||
"Default configuration"_doc
|
||||
)
|
||||
.def_rw("dialect", &assembly::AssemblerConfig::dialect,
|
||||
"The dialect of the input assembly code"_doc
|
||||
)
|
||||
.def("resolve_symbol", &assembly::AssemblerConfig::resolve_symbol,
|
||||
R"doc(
|
||||
This function aims to be overloaded in order to resolve symbols used
|
||||
in the assembly listing.
|
||||
|
||||
For instance, given this assembly code:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
0x1000: mov rdi, rbx
|
||||
0x1003: call _my_function
|
||||
|
||||
The function ``_my_function`` will remain undefined unless we return its
|
||||
address in :meth:`~.resolve_symbol`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyConfig(lief.assembly.AssemblerConfig):
|
||||
def __init__(self):
|
||||
super().__init__() # This is important
|
||||
|
||||
@override
|
||||
def resolve_symbol(self, name: str) -> int | None:
|
||||
if name == '_my_function':
|
||||
return 0x4000
|
||||
return None # Or super().resolve_symbol(name)
|
||||
)doc"_doc, "name"_a)
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -311,13 +311,14 @@ void init(nb::module_& m) {
|
||||
LIEF::py::init_hash(m);
|
||||
LIEF::py::init_json(m);
|
||||
|
||||
LIEF::assembly::py::init(m);
|
||||
|
||||
LIEF::py::init_abstract(m);
|
||||
|
||||
LIEF::dwarf::py::init(m);
|
||||
LIEF::pdb::py::init(m);
|
||||
LIEF::objc::py::init(m);
|
||||
LIEF::dsc::py::init(m);
|
||||
LIEF::assembly::py::init(m);
|
||||
|
||||
#if defined(LIEF_ELF_SUPPORT)
|
||||
LIEF::ELF::py::init(m);
|
||||
|
||||
Reference in New Issue
Block a user