有没有办法确定 VTable 中每个特征方法的偏移量?
Is there a way to determine the offsets of each of the trait methods in the VTable?
我想我可以尝试 或多或少 从头开始构建特征对象而不使用 impl
块。详细说明:
trait SomeTrait {
fn fn_1(&self);
fn fn_2(&self, a: i64);
fn fn_3(&self, a: i64, b: i64);
}
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
fn dtor(this: *mut ()) {
// ...
}
fn imp_1(this: *mut ()) {
// ...
}
fn imp_2(this: *mut (), a: i64) {
// ...
}
fn imp_3(this: *mut (), a: i64, b: i64) {
// ...
}
fn main() {
let data = &... as *mut (); // something to be the object
let vtable = [dtor as *mut (),
8 as *mut (),
8 as *mut (),
imp_1 as *mut (),
imp_2 as *mut (),
imp_3 as *mut ()]; // ignore any errors in typecasting,
//this is not what I am worried about getting right
let to = TraitObject {
data: data,
vtable: vtable.as_ptr() as *mut (),
};
// again, ignore any typecast errors,
let obj: &SomeTrait = unsafe { mem::transmute(to) };
// ...
obj.fn_1();
obj.fn_2(123);
obj.fn_3(123, 456);
}
据我了解,成员函数在特征定义中出现的顺序并不总是与函数指针在 VTable 中出现的顺序相同。有没有办法确定 VTable 中每个特征方法的偏移量?
如果您不介意在运行时检测布局,那么您可以比较特定偏移处的函数地址,并将它们与已知的虚拟实现的地址进行比较以匹配它们。这假定您知道特征中有多少方法,因为您可能需要阅读所有方法。
use std::mem;
trait SomeTrait {
fn fn_1(&self);
fn fn_2(&self, a: i64);
fn fn_3(&self, a: i64, b: i64);
}
struct Dummy;
impl SomeTrait for Dummy {
fn fn_1(&self) { unimplemented!() }
fn fn_2(&self, _a: i64) { unimplemented!() }
fn fn_3(&self, _a: i64, _b: i64) { unimplemented!() }
}
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
fn main() {
unsafe {
let fn_1 = Dummy::fn_1 as *const ();
let fn_2 = Dummy::fn_2 as *const ();
let fn_3 = Dummy::fn_3 as *const ();
let dummy = &mut Dummy as &mut SomeTrait;
let dummy: TraitObject = mem::transmute(dummy);
let vtable = dummy.vtable as *const *const ();
let vtable_0 = *vtable.offset(3);
let vtable_1 = *vtable.offset(4);
let vtable_2 = *vtable.offset(5);
// Mapping vtable offsets to methods is left as an exercise to the reader. ;)
println!("{:p} {:p} {:p}", fn_1, fn_2, fn_3);
println!("{:p} {:p} {:p}", vtable_0, vtable_1, vtable_2);
}
}
我想我可以尝试 或多或少 从头开始构建特征对象而不使用 impl
块。详细说明:
trait SomeTrait {
fn fn_1(&self);
fn fn_2(&self, a: i64);
fn fn_3(&self, a: i64, b: i64);
}
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
fn dtor(this: *mut ()) {
// ...
}
fn imp_1(this: *mut ()) {
// ...
}
fn imp_2(this: *mut (), a: i64) {
// ...
}
fn imp_3(this: *mut (), a: i64, b: i64) {
// ...
}
fn main() {
let data = &... as *mut (); // something to be the object
let vtable = [dtor as *mut (),
8 as *mut (),
8 as *mut (),
imp_1 as *mut (),
imp_2 as *mut (),
imp_3 as *mut ()]; // ignore any errors in typecasting,
//this is not what I am worried about getting right
let to = TraitObject {
data: data,
vtable: vtable.as_ptr() as *mut (),
};
// again, ignore any typecast errors,
let obj: &SomeTrait = unsafe { mem::transmute(to) };
// ...
obj.fn_1();
obj.fn_2(123);
obj.fn_3(123, 456);
}
据我了解,成员函数在特征定义中出现的顺序并不总是与函数指针在 VTable 中出现的顺序相同。有没有办法确定 VTable 中每个特征方法的偏移量?
如果您不介意在运行时检测布局,那么您可以比较特定偏移处的函数地址,并将它们与已知的虚拟实现的地址进行比较以匹配它们。这假定您知道特征中有多少方法,因为您可能需要阅读所有方法。
use std::mem;
trait SomeTrait {
fn fn_1(&self);
fn fn_2(&self, a: i64);
fn fn_3(&self, a: i64, b: i64);
}
struct Dummy;
impl SomeTrait for Dummy {
fn fn_1(&self) { unimplemented!() }
fn fn_2(&self, _a: i64) { unimplemented!() }
fn fn_3(&self, _a: i64, _b: i64) { unimplemented!() }
}
struct TraitObject {
data: *mut (),
vtable: *mut (),
}
fn main() {
unsafe {
let fn_1 = Dummy::fn_1 as *const ();
let fn_2 = Dummy::fn_2 as *const ();
let fn_3 = Dummy::fn_3 as *const ();
let dummy = &mut Dummy as &mut SomeTrait;
let dummy: TraitObject = mem::transmute(dummy);
let vtable = dummy.vtable as *const *const ();
let vtable_0 = *vtable.offset(3);
let vtable_1 = *vtable.offset(4);
let vtable_2 = *vtable.offset(5);
// Mapping vtable offsets to methods is left as an exercise to the reader. ;)
println!("{:p} {:p} {:p}", fn_1, fn_2, fn_3);
println!("{:p} {:p} {:p}", vtable_0, vtable_1, vtable_2);
}
}