mirror of
https://github.com/facebookexperimental/reverie.git
synced 2025-01-23 05:06:23 +00:00
Fix VDSO patching of small entries
Summary: On Ubuntu 22.04, this is the disassembly of `gettimeofday` and `clock_gettime`: ``` 0000000000000bd0 <__vdso_gettimeofday@LINUX_2.6>: bd0: e9 4b fe ff ff jmp a20 <LINUX_2.6@LINUX_2.6+0xa20> bd5: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1) bdc: 00 00 00 00 0000000000000c10 <__vdso_clock_gettime@LINUX_2.6>: c10: e9 9b fb ff ff jmp 7b0 <LINUX_2.6@LINUX_2.6+0x7b0> c15: 66 66 2e 0f 1f 84 00 data16 cs nopw 0x0(%rax,%rax,1) c1c: 00 00 00 00 ``` These implementations just `jmp` to another internal function. The dynamic symbol table reports that these functions are 5 bytes in size, but we can see that they are aligned up to 16 bytes and they are still safe to patch. Thus, our patcher should take this padding and alignment into account. Fixes https://github.com/facebookexperimental/hermit/issues/16. Differential Revision: D41565913 fbshipit-source-id: 164aca876abf92642e7ebf4ce96d0860b276647b
This commit is contained in:
parent
fa44c91a66
commit
5478e47a25
1 changed files with 22 additions and 2 deletions
|
@ -138,6 +138,11 @@ const VDSO_SYMBOLS: &[(&str, &[u8])] = &[
|
|||
("__kernel_rt_sigreturn", vdso_syms::rt_sigreturn),
|
||||
];
|
||||
|
||||
/// Rounds up `value` so that it is a multiple of `alignment`.
|
||||
fn align_up(value: usize, alignment: usize) -> usize {
|
||||
(value + alignment - 1) & alignment.wrapping_neg()
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref VDSO_PATCH_INFO: HashMap<&'static str, (u64, usize, &'static [u8])> = {
|
||||
let info = vdso_get_symbols_info();
|
||||
|
@ -145,14 +150,20 @@ lazy_static! {
|
|||
|
||||
for (k, v) in VDSO_SYMBOLS {
|
||||
if let Some(&(base, size)) = info.get(*k) {
|
||||
// NOTE: There is padding at the end of every VDSO entry to
|
||||
// bring it up to a 16-byte size alignment. The dynamic symbol
|
||||
// table doesn't report the aligned size, so we must do the same
|
||||
// alignment here. For example, some VDSO entries might only be
|
||||
// 5 bytes, but they have padding to align them up to 16 bytes.
|
||||
let aligned_size = align_up(size, 16);
|
||||
assert!(
|
||||
v.len() <= size,
|
||||
v.len() <= aligned_size,
|
||||
"vdso symbol {}'s real size is {} bytes, but trying to replace it with {} bytes",
|
||||
k,
|
||||
size,
|
||||
v.len()
|
||||
);
|
||||
res.insert(*k, (base, size, *v));
|
||||
res.insert(*k, (base, aligned_size, *v));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,6 +263,15 @@ where
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_align_up() {
|
||||
assert_eq!(align_up(0, 16), 0);
|
||||
assert_eq!(align_up(1, 16), 16);
|
||||
assert_eq!(align_up(15, 16), 16);
|
||||
assert_eq!(align_up(16, 16), 16);
|
||||
assert_eq!(align_up(17, 16), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_find_vdso() {
|
||||
assert!(
|
||||
|
|
Loading…
Reference in a new issue