feat(ld.so): lazy binding
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
+11
-2
@@ -7,7 +7,11 @@ use core::{
|
||||
sync::atomic::{AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use crate::{c_str::CStr, ld_so::tcb::Tcb, platform::types::*};
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
ld_so::{linker::Resolve, tcb::Tcb},
|
||||
platform::types::*,
|
||||
};
|
||||
|
||||
pub const RTLD_LAZY: c_int = 0x0001;
|
||||
pub const RTLD_NOW: c_int = 0x0002;
|
||||
@@ -42,6 +46,11 @@ pub unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut c_void {
|
||||
//TODO support all sort of flags
|
||||
let resolve = if flags & RTLD_NOW == RTLD_NOW {
|
||||
Resolve::Now
|
||||
} else {
|
||||
Resolve::Lazy
|
||||
};
|
||||
|
||||
let filename = if cfilename.is_null() {
|
||||
None
|
||||
@@ -69,7 +78,7 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
|
||||
let cbs_c = linker.cbs.clone();
|
||||
let cbs = cbs_c.borrow();
|
||||
|
||||
let id = match (cbs.load_library)(&mut linker, filename) {
|
||||
let id = match (cbs.load_library)(&mut linker, filename, resolve) {
|
||||
Err(err) => {
|
||||
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
|
||||
return ptr::null_mut();
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use super::linker::Linker;
|
||||
use super::linker::{Linker, Resolve};
|
||||
use crate::platform::types::c_void;
|
||||
use alloc::boxed::Box;
|
||||
use goblin::error::Result;
|
||||
|
||||
pub struct LinkerCallbacks {
|
||||
pub unload: Box<dyn Fn(&mut Linker, usize)>,
|
||||
pub load_library: Box<dyn Fn(&mut Linker, Option<&str>) -> Result<usize>>,
|
||||
pub load_library: Box<dyn Fn(&mut Linker, Option<&str>, Resolve) -> Result<usize>>,
|
||||
pub get_sym: Box<dyn Fn(&Linker, usize, &str) -> Option<*mut c_void>>,
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ fn unload(linker: &mut Linker, lib_id: usize) {
|
||||
linker.unload(lib_id)
|
||||
}
|
||||
|
||||
fn load_library(linker: &mut Linker, name: Option<&str>) -> Result<usize> {
|
||||
linker.load_library(name)
|
||||
fn load_library(linker: &mut Linker, name: Option<&str>, resolve: Resolve) -> Result<usize> {
|
||||
linker.load_library(name, resolve)
|
||||
}
|
||||
|
||||
fn get_sym(linker: &Linker, lib_id: usize, name: &str) -> Option<*mut c_void> {
|
||||
|
||||
+37
-6
@@ -1,3 +1,5 @@
|
||||
//! See <https://refspecs.linuxfoundation.org/elf/elf.pdf>.
|
||||
|
||||
use super::{
|
||||
debug::{RTLDDebug, _r_debug},
|
||||
linker::Symbol,
|
||||
@@ -33,10 +35,32 @@ use goblin::elf64::{
|
||||
sym,
|
||||
};
|
||||
use goblin::{
|
||||
elf::Elf,
|
||||
elf::{
|
||||
sym::{STB_GLOBAL, STB_WEAK},
|
||||
Dynamic, Elf,
|
||||
},
|
||||
error::{Error, Result},
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum SymbolBinding {
|
||||
/// Global symbols are visible to all object files being combined. One
|
||||
/// file's definition of a global symbol will satisfy another file's
|
||||
/// undefined reference to the same global symbol.
|
||||
Global = STB_GLOBAL,
|
||||
/// Weak symbols resemble global symbols, but their definitions have lower
|
||||
/// precedence.
|
||||
Weak = STB_WEAK,
|
||||
}
|
||||
|
||||
impl SymbolBinding {
|
||||
#[inline]
|
||||
pub fn is_global(&self) -> bool {
|
||||
matches!(self, Self::Global)
|
||||
}
|
||||
}
|
||||
|
||||
/// Use to represent a library as well as all the symbols that is loaded withen it.
|
||||
#[derive(Default)]
|
||||
pub struct DSO {
|
||||
@@ -57,6 +81,9 @@ pub struct DSO {
|
||||
pub tls_module_id: usize,
|
||||
pub tls_offset: usize,
|
||||
pub use_count: usize,
|
||||
|
||||
pub dynamic: Option<Dynamic>,
|
||||
pub dynsyms: Vec<goblin::elf::sym::Sym>,
|
||||
}
|
||||
|
||||
impl DSO {
|
||||
@@ -106,15 +133,19 @@ impl DSO {
|
||||
0
|
||||
},
|
||||
tls_offset: tls_offset,
|
||||
|
||||
dynamic: elf.dynamic.map(|dynamic| dynamic),
|
||||
dynsyms: elf.dynsyms.iter().collect(),
|
||||
};
|
||||
return Ok((dso, tcb_master));
|
||||
|
||||
Ok((dso, tcb_master))
|
||||
}
|
||||
|
||||
pub fn get_sym(&self, name: &str) -> Option<(Symbol, bool)> {
|
||||
pub fn get_sym(&self, name: &str) -> Option<(Symbol, SymbolBinding)> {
|
||||
if let Some(value) = self.global_syms.get(name) {
|
||||
Some((*value, true))
|
||||
Some((*value, SymbolBinding::Global))
|
||||
} else if let Some(value) = self.weak_syms.get(name) {
|
||||
Some((*value, false))
|
||||
Some((*value, SymbolBinding::Weak))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -404,7 +435,7 @@ impl DSO {
|
||||
.iter()
|
||||
.filter(|s| s.sh_type == SHT_INIT_ARRAY || s.sh_type == SHT_FINI_ARRAY)
|
||||
{
|
||||
let addr = if is_pie_enabled(&elf) {
|
||||
let addr = if is_pie_enabled(elf) {
|
||||
mmap_addr + section.vm_range().start
|
||||
} else {
|
||||
section.vm_range().start
|
||||
|
||||
+289
-49
@@ -6,7 +6,12 @@ use alloc::{
|
||||
};
|
||||
use core::{cell::RefCell, mem::transmute, ptr};
|
||||
use goblin::{
|
||||
elf::{program_header, reloc, sym::STT_TLS, Elf},
|
||||
elf::{
|
||||
dynamic::{DT_PLTGOT, DT_STRTAB},
|
||||
program_header, reloc,
|
||||
sym::STT_TLS,
|
||||
Elf,
|
||||
},
|
||||
error::{Error, Result},
|
||||
};
|
||||
|
||||
@@ -19,8 +24,9 @@ use crate::{
|
||||
unistd::F_OK,
|
||||
},
|
||||
io::{self, Read},
|
||||
ld_so::dso::SymbolBinding,
|
||||
platform::{
|
||||
types::{c_int, c_void},
|
||||
types::{c_char, c_int, c_uint, c_void},
|
||||
Pal, Sys,
|
||||
},
|
||||
};
|
||||
@@ -68,6 +74,16 @@ impl Symbol {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq)]
|
||||
pub enum Resolve {
|
||||
/// Resolve all undefined symbols immediately.
|
||||
Now,
|
||||
/// Perform lazy binding (i.e. symbols will be resolved when they are first
|
||||
/// used).
|
||||
#[default]
|
||||
Lazy,
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DebugFlags: u32 {
|
||||
@@ -141,53 +157,50 @@ impl Linker {
|
||||
}
|
||||
|
||||
pub fn load_program(&mut self, path: &str, base_addr: Option<usize>) -> Result<usize> {
|
||||
self.load_object(path, &None, base_addr, false)?;
|
||||
return Ok(self.objects.get(&root_id).unwrap().entry_point);
|
||||
self.load_object(path, &None, base_addr, false, Resolve::default())?;
|
||||
// TODO(andypython): make self.load_object() return a reference to the
|
||||
// loaded object, thereby remove the ugly unwrap().
|
||||
Ok(self.objects.get(&root_id).unwrap().entry_point)
|
||||
}
|
||||
|
||||
pub fn load_library(&mut self, name: Option<&str>) -> Result<usize> {
|
||||
pub fn load_library(&mut self, name: Option<&str>, resolve: Resolve) -> Result<usize> {
|
||||
match name {
|
||||
Some(name) => {
|
||||
if let Some(id) = self.name_to_object_id_map.get(name) {
|
||||
let obj = self.objects.get_mut(id).unwrap();
|
||||
obj.use_count += 1;
|
||||
return Ok(*id);
|
||||
Ok(*id)
|
||||
} else {
|
||||
let parent_runpath = &self
|
||||
.objects
|
||||
.get(&root_id)
|
||||
.and_then(|parent| parent.runpath.clone());
|
||||
let lib_id = self.next_object_id;
|
||||
self.load_object(name, parent_runpath, None, true)?;
|
||||
self.load_object(name, parent_runpath, None, true, resolve)?;
|
||||
|
||||
return Ok(lib_id);
|
||||
Ok(lib_id)
|
||||
}
|
||||
}
|
||||
None => return Ok(root_id),
|
||||
|
||||
None => Ok(root_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_sym(&self, lib_id: usize, name: &str) -> Option<*mut c_void> {
|
||||
match self.objects.get(&lib_id) {
|
||||
Some(obj) => {
|
||||
return obj.get_sym(name).map(|(s, strong)| {
|
||||
if s.sym_type != STT_TLS {
|
||||
s.as_ptr()
|
||||
} else {
|
||||
unsafe {
|
||||
let mut tls_index = dl_tls_index {
|
||||
ti_module: obj.tls_module_id as u64,
|
||||
ti_offset: s.value as u64,
|
||||
};
|
||||
__tls_get_addr(&mut tls_index)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
self.objects.get(&lib_id).and_then(|obj| {
|
||||
obj.get_sym(name).map(|(s, _binding)| {
|
||||
if s.sym_type != STT_TLS {
|
||||
s.as_ptr()
|
||||
} else {
|
||||
let mut tls_index = dl_tls_index {
|
||||
ti_module: obj.tls_module_id as u64,
|
||||
ti_offset: s.value as u64,
|
||||
};
|
||||
|
||||
unsafe { __tls_get_addr(&mut tls_index) }
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn unload(&mut self, lib_id: usize) {
|
||||
@@ -219,6 +232,7 @@ impl Linker {
|
||||
runpath: &Option<String>,
|
||||
base_addr: Option<usize>,
|
||||
dlopened: bool,
|
||||
resolve: Resolve,
|
||||
) -> Result<()> {
|
||||
unsafe { _r_debug.state = RTLDState::RT_ADD };
|
||||
_dl_debug_state();
|
||||
@@ -335,7 +349,7 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
|
||||
self.relocate(&new_objects, &objects_data)?;
|
||||
self.relocate(&new_objects, &objects_data, resolve)?;
|
||||
self.run_init(&new_objects);
|
||||
|
||||
for obj in new_objects.into_iter() {
|
||||
@@ -420,7 +434,7 @@ impl Linker {
|
||||
)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn search_object(&self, name: &str, parent_runpath: &Option<String>) -> Result<String> {
|
||||
@@ -474,7 +488,102 @@ impl Linker {
|
||||
return Ok(data);
|
||||
}
|
||||
|
||||
fn relocate(&self, new_objects: &Vec<DSO>, objects_data: &Vec<Vec<u8>>) -> Result<()> {
|
||||
fn resolve_sym<'a>(name: &str, objs: impl Iterator<Item = &'a DSO>) -> Option<Symbol> {
|
||||
let mut res = None;
|
||||
|
||||
for dso in objs {
|
||||
if let Some((sym, binding)) = dso.get_sym(name) {
|
||||
if binding.is_global() {
|
||||
return Some(sym);
|
||||
}
|
||||
|
||||
res = Some(sym);
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// Perform lazy relocations.
|
||||
fn lazy_relocate<'a>(
|
||||
&self,
|
||||
obj: &DSO,
|
||||
new_objects: &[DSO],
|
||||
elf: &Elf,
|
||||
resolve: Resolve,
|
||||
) -> Result<()> {
|
||||
let object_base_addr = obj.mmap.as_ptr() as u64;
|
||||
|
||||
if let Some(dynamic) = elf.dynamic.as_ref() {
|
||||
// Global Offset Table
|
||||
let got = if let Some(ptr) = {
|
||||
dynamic
|
||||
.dyns
|
||||
.iter()
|
||||
.find(|r#dyn| r#dyn.d_tag == DT_PLTGOT)
|
||||
.map(|r#dyn| r#dyn.d_val)
|
||||
} {
|
||||
(object_base_addr + ptr) as *mut usize
|
||||
} else {
|
||||
assert_eq!(dynamic.info.jmprel, 0);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
unsafe {
|
||||
got.add(1).write(obj.id);
|
||||
got.add(2).write(__plt_resolve_trampoline as usize);
|
||||
}
|
||||
|
||||
for rel in elf.pltrelocs.iter() {
|
||||
match (rel.r_type, resolve) {
|
||||
(reloc::R_X86_64_JUMP_SLOT, Resolve::Lazy) => unsafe {
|
||||
*((object_base_addr + rel.r_offset) as *mut u64) += object_base_addr;
|
||||
},
|
||||
|
||||
(reloc::R_X86_64_JUMP_SLOT, Resolve::Now) => {
|
||||
let sym = elf.dynsyms.get(rel.r_sym).ok_or(Error::Malformed(format!(
|
||||
"missing symbol for relocation {:?}",
|
||||
rel
|
||||
)))?;
|
||||
|
||||
let name =
|
||||
elf.dynstrtab
|
||||
.get_at(sym.st_name)
|
||||
.ok_or(Error::Malformed(format!(
|
||||
"missing name for symbol {:?}",
|
||||
sym
|
||||
)))?;
|
||||
|
||||
// FIXME(andypython): warn on unresolved symbols?
|
||||
let resolved = Linker::resolve_sym(
|
||||
name,
|
||||
self.objects.values().chain(new_objects.iter()),
|
||||
)
|
||||
.map(|sym| sym.as_ptr())
|
||||
.unwrap_or(ptr::null_mut());
|
||||
|
||||
let addend = rel.r_addend.unwrap_or(0) as u64;
|
||||
|
||||
unsafe {
|
||||
*((object_base_addr + rel.r_offset) as *mut u64) =
|
||||
resolved as u64 + addend;
|
||||
}
|
||||
}
|
||||
|
||||
_ => todo!("unsupported relocation type {:?}", rel.r_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn relocate(
|
||||
&self,
|
||||
new_objects: &Vec<DSO>,
|
||||
objects_data: &Vec<Vec<u8>>,
|
||||
resolve: Resolve,
|
||||
) -> Result<()> {
|
||||
let symbols_lookup_objects: Vec<&DSO> =
|
||||
self.objects.values().chain(new_objects.iter()).collect();
|
||||
|
||||
@@ -489,12 +598,7 @@ impl Linker {
|
||||
let b = mmap.as_ptr() as usize;
|
||||
|
||||
// Relocate
|
||||
for rel in elf
|
||||
.dynrelas
|
||||
.iter()
|
||||
.chain(elf.dynrels.iter())
|
||||
.chain(elf.pltrelocs.iter())
|
||||
{
|
||||
for rel in elf.dynrelas.iter().chain(elf.dynrels.iter()) {
|
||||
trace!(
|
||||
" rel {}: {:x?}",
|
||||
reloc::r_to_str(rel.r_type, elf.header.e_machine),
|
||||
@@ -520,21 +624,20 @@ impl Linker {
|
||||
reloc::R_X86_64_COPY => 1,
|
||||
_ => 0,
|
||||
};
|
||||
for lookup_id in lookup_start..symbols_lookup_objects.len() {
|
||||
let lookup_obj = &symbols_lookup_objects[lookup_id];
|
||||
if let Some((s, strong)) = lookup_obj.get_sym(name) {
|
||||
for lookup_obj in symbols_lookup_objects.iter().skip(lookup_start) {
|
||||
if let Some((s, binding)) = lookup_obj.get_sym(name) {
|
||||
trace!(
|
||||
"symbol {} from {} found in {} ({})",
|
||||
"symbol {} from {} found in {} ({:?})",
|
||||
name,
|
||||
obj.name,
|
||||
lookup_obj.name,
|
||||
if strong { "strong" } else { "weak" }
|
||||
binding
|
||||
);
|
||||
symbol = Some(s);
|
||||
t = lookup_obj.tls_offset;
|
||||
found = true;
|
||||
// Stop looking if any strong symbol is found
|
||||
if strong {
|
||||
if binding.is_global() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -607,7 +710,7 @@ impl Linker {
|
||||
let sym = symbol
|
||||
.as_ref()
|
||||
.expect("R_X86_64_COPY called without valid symbol");
|
||||
ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size as usize);
|
||||
ptr::copy_nonoverlapping(sym.as_ptr() as *const u8, ptr, sym.size);
|
||||
},
|
||||
_ => {
|
||||
panic!(
|
||||
@@ -639,7 +742,7 @@ impl Linker {
|
||||
prot |= sys_mman::PROT_WRITE;
|
||||
}
|
||||
|
||||
let res = unsafe {
|
||||
unsafe {
|
||||
let ptr = if is_pie_enabled(&elf) {
|
||||
mmap.as_ptr().add(vaddr)
|
||||
} else {
|
||||
@@ -649,18 +752,22 @@ impl Linker {
|
||||
Sys::mprotect(ptr as *mut c_void, vsize, prot).map_err(|_| {
|
||||
Error::Malformed(format!("failed to mprotect {}", obj.name))
|
||||
})?;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
for (i, obj) in new_objects.iter().enumerate() {
|
||||
self.lazy_relocate(obj, new_objects, &Elf::parse(&objects_data[i])?, resolve)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_init(&self, objects: &Vec<DSO>) {
|
||||
use crate::platform::{self, types::*};
|
||||
|
||||
for obj in objects.iter().rev() {
|
||||
if let Some((symbol, true)) = obj.get_sym("__relibc_init_environ") {
|
||||
if let Some((symbol, SymbolBinding::Global)) = obj.get_sym("__relibc_init_environ") {
|
||||
unsafe {
|
||||
symbol
|
||||
.as_ptr()
|
||||
@@ -673,3 +780,136 @@ impl Linker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GOT[1] = object_id
|
||||
// GOT[2] = __plt_resolve_trampoline
|
||||
//
|
||||
// The stubs in .plt will push the relocation index and the object ID onto the stack and jump to
|
||||
// [`__plt_resolve_trampoline`]. The trampoline will then call this function to resolve the symbol
|
||||
// and update the respective GOT entry. The trampoline will then jump to the resolved symbol.
|
||||
//
|
||||
// FIXME(andypython): 32-bit
|
||||
extern "C" fn __plt_resolve_inner(object_id: usize, relocation_index: c_uint) -> *mut c_void {
|
||||
let tcb = unsafe { Tcb::current() }.unwrap();
|
||||
assert!(!tcb.linker_ptr.is_null());
|
||||
|
||||
let linker = unsafe { &*tcb.linker_ptr }.lock();
|
||||
|
||||
let obj = linker.objects.get(&object_id).unwrap();
|
||||
let obj_base = obj.mmap.as_ptr() as usize;
|
||||
let dynamic = obj.dynamic.as_ref().unwrap();
|
||||
let jmprel = dynamic.info.jmprel as usize;
|
||||
|
||||
let rela = unsafe {
|
||||
&*((obj_base + jmprel) as *const reloc::reloc64::Rela).add(relocation_index as usize)
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
reloc::reloc64::r_type(rela.r_info),
|
||||
reloc::R_X86_64_JUMP_SLOT
|
||||
);
|
||||
|
||||
let sym = obj
|
||||
.dynsyms
|
||||
.get(reloc::reloc64::r_sym(rela.r_info) as usize)
|
||||
.expect("symbol not found");
|
||||
assert_ne!(sym.st_name, 0);
|
||||
|
||||
let strtab_offset = dynamic
|
||||
.dyns
|
||||
.iter()
|
||||
.find(|r#dyn| r#dyn.d_tag == DT_STRTAB)
|
||||
.unwrap()
|
||||
.d_val;
|
||||
|
||||
let name = unsafe {
|
||||
CStr::from_ptr((strtab_offset + sym.st_name as u64 + obj_base as u64) as *const c_char)
|
||||
};
|
||||
|
||||
let resolved = Linker::resolve_sym(name.to_str().unwrap(), linker.objects.values())
|
||||
.expect("symbol not found")
|
||||
.as_ptr();
|
||||
|
||||
unsafe {
|
||||
println!(
|
||||
"@plt: {} -> *mut {:#x}",
|
||||
name.to_string_lossy(),
|
||||
resolved as usize
|
||||
);
|
||||
|
||||
*((obj_base as u64 + rela.r_offset) as *mut u64) = resolved as u64;
|
||||
}
|
||||
|
||||
resolved
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __plt_resolve_trampoline() -> usize;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
core::arch::global_asm!(
|
||||
"
|
||||
.global __plt_resolve_trampoline
|
||||
.hidden __plt_resolve_trampoline
|
||||
__plt_resolve_trampoline:
|
||||
push rsi
|
||||
push rdi
|
||||
|
||||
mov rdi, qword ptr [rsp + 0x10]
|
||||
mov rsi, qword ptr [rsp + 0x18]
|
||||
|
||||
// stash the floating point argument registers
|
||||
sub rsp, 128
|
||||
movdqu [rsp + 0x00], xmm0
|
||||
movdqu [rsp + 0x10], xmm1
|
||||
movdqu [rsp + 0x20], xmm2
|
||||
movdqu [rsp + 0x30], xmm3
|
||||
movdqu [rsp + 0x40], xmm4
|
||||
movdqu [rsp + 0x50], xmm5
|
||||
movdqu [rsp + 0x60], xmm6
|
||||
movdqu [rsp + 0x70], xmm7
|
||||
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push r8
|
||||
push r9
|
||||
push r10
|
||||
|
||||
push rbp
|
||||
mov rbp, rsp
|
||||
and rsp, 0xfffffffffffffff0
|
||||
call {__plt_resolve_inner}
|
||||
mov r11, rax
|
||||
mov rsp, rbp
|
||||
pop rbp
|
||||
|
||||
pop r10
|
||||
pop r9
|
||||
pop r8
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
|
||||
movdqu xmm7, [rsp + 0x70]
|
||||
movdqu xmm6, [rsp + 0x60]
|
||||
movdqu xmm5, [rsp + 0x50]
|
||||
movdqu xmm4, [rsp + 0x40]
|
||||
movdqu xmm3, [rsp + 0x30]
|
||||
movdqu xmm2, [rsp + 0x20]
|
||||
movdqu xmm1, [rsp + 0x10]
|
||||
movdqu xmm0, [rsp + 0x00]
|
||||
add rsp, 128
|
||||
|
||||
pop rdi
|
||||
pop rsi
|
||||
|
||||
add rsp, 0x10
|
||||
jmp r11
|
||||
|
||||
ud2
|
||||
.size __plt_resolve_trampoline, . - __plt_resolve_trampoline
|
||||
",
|
||||
__plt_resolve_inner = sym __plt_resolve_inner
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user