将指向 Rust 数组的指针传递给 x86-64 Asm——指针偏移一
Passing Pointer to Rust Array into x86-64 Asm -- Pointer Off by One
当我将指向数组的指针从 Rust 传递到 x86-64 Asm 时,相关寄存器(rdi、rsi)似乎偏移了 1,指向数组的元素 1 而不是元素 0。我可以递减注册访问所需位置,但我担心意外行为。是否有我忽略的可能解释?
以下是说明这一点的简单程序中最相关的部分。
main.rs
extern crate utilities;
fn main() {
let input: [u8;8] = [0;8];
let output: [u64; 1] = [0;1];
let input_ptr = input.as_ptr();
let output_ptr = output.as_ptr();
utilities::u8tou64(input_ptr,output_ptr);
for i in 0..8 {print!("{:02X}", input[i]);} // byte 1 will be 0xEE
println!();
println!("{:016X}", output[0].swap_bytes()); /* byte 1 position of the u64
will be 0xFF */
println!("{:02X}", unsafe{*input_ptr.offset(1)}); /* modifying byte at address
passed into rdi in Asm function modifies input_ptr.offset(1) when expected
behavior was modification of input_ptr with no offset, e.g. input[0] */
}
u8_to_u64.S
.globl u8_to_u64
.intel_syntax noprefix
u8_to_u64:
mov rax, 0xff
mov byte [rsi], rax
mov rax, 0xee
mov byte [rdi], rax
xor rax, rax
retq
我 assemble 用 gcc -c foo.S
编写了你的 asm,因为我认为我会从 byte
而不是 byte ptr
得到一个 assemble 时间错误, 以及与 qword 寄存器不匹配。
在 GAS 语法中,byte
计算为整数常量 1
,因此 mov byte [rsi], rax
等同于 mov 1[rsi], rax
。这在 GAS 语法中有效,等同于 [1+rsi]
当你用 objdump -dwrC -Mintel
拒绝 assemble foo.o
时,你会看到
0000000000000000 <u8_to_u64>:
0: 48 c7 c0 ff 00 00 00 mov rax,0xff
7: 48 89 46 01 mov QWORD PTR [rsi+0x1],rax
b: 48 c7 c0 ee 00 00 00 mov rax,0xee
12: 48 89 47 01 mov QWORD PTR [rdi+0x1],rax
16: 48 31 c0 xor rax,rax
19: c3 ret
注意 [rsi+1]
和 [rdi+1]
寻址模式。
您要执行的操作的 GAS 语法是:
mov byte ptr [rsi], 0xff
mov byte ptr [rdi], 0xee
xor eax,eax
ret
或者使用愚蠢的额外指令首先对寄存器执行 mov-immediate:
mov eax, 0xff
mov [rsi], al
mov eax, 0xee # mov al, 0xee is shorter but false dependency on the old RAX
mov [rdi], al
xor eax,eax
ret
当我将指向数组的指针从 Rust 传递到 x86-64 Asm 时,相关寄存器(rdi、rsi)似乎偏移了 1,指向数组的元素 1 而不是元素 0。我可以递减注册访问所需位置,但我担心意外行为。是否有我忽略的可能解释?
以下是说明这一点的简单程序中最相关的部分。
main.rs
extern crate utilities;
fn main() {
let input: [u8;8] = [0;8];
let output: [u64; 1] = [0;1];
let input_ptr = input.as_ptr();
let output_ptr = output.as_ptr();
utilities::u8tou64(input_ptr,output_ptr);
for i in 0..8 {print!("{:02X}", input[i]);} // byte 1 will be 0xEE
println!();
println!("{:016X}", output[0].swap_bytes()); /* byte 1 position of the u64
will be 0xFF */
println!("{:02X}", unsafe{*input_ptr.offset(1)}); /* modifying byte at address
passed into rdi in Asm function modifies input_ptr.offset(1) when expected
behavior was modification of input_ptr with no offset, e.g. input[0] */
}
u8_to_u64.S
.globl u8_to_u64
.intel_syntax noprefix
u8_to_u64:
mov rax, 0xff
mov byte [rsi], rax
mov rax, 0xee
mov byte [rdi], rax
xor rax, rax
retq
我 assemble 用 gcc -c foo.S
编写了你的 asm,因为我认为我会从 byte
而不是 byte ptr
得到一个 assemble 时间错误, 以及与 qword 寄存器不匹配。
在 GAS 语法中,byte
计算为整数常量 1
,因此 mov byte [rsi], rax
等同于 mov 1[rsi], rax
。这在 GAS 语法中有效,等同于 [1+rsi]
当你用 objdump -dwrC -Mintel
拒绝 assemble foo.o
时,你会看到
0000000000000000 <u8_to_u64>:
0: 48 c7 c0 ff 00 00 00 mov rax,0xff
7: 48 89 46 01 mov QWORD PTR [rsi+0x1],rax
b: 48 c7 c0 ee 00 00 00 mov rax,0xee
12: 48 89 47 01 mov QWORD PTR [rdi+0x1],rax
16: 48 31 c0 xor rax,rax
19: c3 ret
注意 [rsi+1]
和 [rdi+1]
寻址模式。
您要执行的操作的 GAS 语法是:
mov byte ptr [rsi], 0xff
mov byte ptr [rdi], 0xee
xor eax,eax
ret
或者使用愚蠢的额外指令首先对寄存器执行 mov-immediate:
mov eax, 0xff
mov [rsi], al
mov eax, 0xee # mov al, 0xee is shorter but false dependency on the old RAX
mov [rdi], al
xor eax,eax
ret