Melewati Pointer ke Rust Array ke x86-64 Asm Pointer Off satu per satu

Saat saya meneruskan pointer ke array dari Rust ke x86-64 Asm, register yang relevan (rdi, rsi) tampak meleset satu, menunjuk ke elemen 1 array, bukan elemen 0. Saya dapat mengurangi register untuk mengakses yang diinginkan lokasinya, tetapi saya khawatir dengan perilaku yang tidak terduga. Apakah ada penjelasan yang mungkin untuk hal ini yang saya abaikan?

Bagian paling relevan dari program sederhana untuk menggambarkan hal ini adalah sebagai berikut.

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

person WDS    schedule 16.12.2018    source sumber
comment
Mengapa Anda menggunakan 7-byte mov r64, sign_extended_imm32 untuk konstanta 1-byte? mov byte ptr [rsi], 0xff / mov byte ptr [rdi], 0xee / xor eax,eax jauh lebih pendek dan efisien. Sebagai bonus, itu akan benar-benar dirakit, tidak seperti mov byte [rdi], rax yang memiliki ketidakcocokan antara ukuran operan byte dan qword. (al adalah byte rendah RAX). Selain itu, .intel_syntax GAS mirip MASM, jadi Anda memerlukan byte ptr, bukan byte bergaya NASM. Kecuali Rust menggunakan assembler lain yang hanya terlihat seperti GAS, ini bukan kode asm Anda yang sebenarnya.   -  person Peter Cordes    schedule 16.12.2018
comment
@PeterCordes program yang saya posting disederhanakan dari apa yang saya coba lakukan. Program saya yang sebenarnya menggunakan Asm untuk mengubah array 136 byte yang ditunjuk oleh RDI menjadi array 17 elemen u64 di RSI. Apa yang saya posting berjalan saat saya membuat program yang disederhanakan dan menyalin langsung darinya. Saya beralih dari meneruskan sebuah pointer, alih-alih meneruskan referensi pinjaman ke array, dan setidaknya dalam kasus ini, itu menyebabkan kesalahan off by one hilang. Sepertinya bug FFI. Saya akan mencoba saran Anda dalam kode saya.   -  person WDS    schedule 16.12.2018


Jawaban (1)


Saya merakit asm Anda dengan gcc -c foo.S, karena saya pikir saya akan mendapatkan kesalahan waktu perakitan dari byte bukannya byte ptr, dan ketidakcocokan dengan register qword.

Dalam sintaksis GAS, byte bernilai konstanta bilangan bulat 1, sehingga mov byte [rsi], rax setara dengan mov 1[rsi], rax. Ini valid dalam sintaks GAS, dan setara dengan [1+rsi]

Saat Anda membongkar foo.o dengan objdump -dwrC -Mintel, Anda lihat

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    

Perhatikan mode pengalamatan [rsi+1] dan [rdi+1].

Sintaks GAS untuk apa yang Anda coba lakukan adalah:

mov   byte ptr [rsi], 0xff
mov   byte ptr [rdi], 0xee
xor   eax,eax
ret

Atau dengan instruksi tambahan yang bodoh untuk melakukan mov-immediate ke register terlebih dahulu:

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
person Peter Cordes    schedule 16.12.2018
comment
Ini memperbaiki masalahnya. Saya telah mencoba memindahkan langsung ke [rdi] dan [rsi] dan mendapat keluhan dari kompiler tentang hal itu. Menggunakan mov byte ptr alih-alih mov byte memungkinkan penugasan langsung dan menghilangkan kesalahan dengan satu kesalahan yang secara tidak sengaja saya masukkan ke dalam program. - person WDS; 16.12.2018
comment
@WDS: tanpa penentu ukuran operan, mov [mem], imm bersifat ambigu dan memberikan kesalahan, ya. Itu adalah petunjuk pertama Anda bahwa sintaksis Anda tidak sesuai dengan keinginan Anda. Fakta bahwa mov byte [rsi], rax (dengan register qword) tidak memberikan kesalahan meskipun Anda mencoba menentukan ukuran operan byte adalah petunjuk lain bahwa kode Anda tidak berarti (untuk GAS) seperti yang Anda disengaja. - person Peter Cordes; 16.12.2018