Assembly 将指向Rust数组的指针传递到x86-64 Asm中--指针偏移1

Assembly 将指向Rust数组的指针传递到x86-64 Asm中--指针偏移1,assembly,rust,x86-64,ffi,Assembly,Rust,X86 64,Ffi,当我将指向数组的指针从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 i

当我将指向数组的指针从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到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

我用
gcc-cfoo.S
组装了你的asm,因为我认为我会从
byte
而不是
byte ptr
得到一个组装时间错误,并且与qword寄存器不匹配

在GAS语法中,
byte
计算为整数常量
1
,因此
mov byte[rsi],rax
相当于
mov 1[rsi],rax
。这在GAS语法中有效,相当于
[1+rsi]

当您使用
objdump-dwrC-Mintel
反汇编
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    
或者使用愚蠢的额外指令,首先对寄存器执行mov:

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

为什么对1字节常量使用7字节
mov r64、扩展符号\u imm32
mov字节ptr[rsi],0xff
/
mov字节ptr[rdi],0xee
/
xor eax,eax
短得多,效率更高。作为奖励,它将实际组装rax,而不像
mov byte[rdi],后者在字节和qword操作数大小之间不匹配。(
al
是RAX的低位字节)。另外,GAS的
.intel\u语法类似于MASM,因此需要
字节ptr
,而不是NASM样式的
字节
。除非Rust使用不同的汇编程序,看起来像GAS,否则这不是你真正的asm代码。@PeterCordes我发布的程序是从我试图做的事情简化而来的。我的实际程序使用Asm将RDI指向的136字节数组转换为RSI中的17元素u64数组。我发布的内容在我构建简化程序并直接从中复制时运行。我不再传入指针,而是传入一个借用的数组引用,至少在本例中,这导致了off-by-one错误消失。看起来像是外国金融机构的窃听者。我将在代码中尝试您的建议。这纠正了问题。我曾尝试将即时信息转换为[rdi]和[rsi],但编译器对此提出了投诉。使用“mov byte ptr”而不是“mov byte”允许直接立即赋值,并消除了我无意中引入到程序中的“off by one”错误。@WDS:没有操作数大小说明符,
mov[mem],imm
是不明确的,并给出了一个错误,是的。这是你第一次暗示你的语法没有达到你想要的效果。
mov byte[rsi]、rax
(带有qword寄存器)没有给出错误,即使您试图指定字节操作数大小,这一事实是您的代码(对GAS)不是您想要的意思的另一个线索。
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