Когда я передаю указатели на массивы из Rust в x86-64 Asm, соответствующие регистры (rdi, rsi) кажутся смещенными на единицу, указывая на элемент 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
mov r64, sign_extended_imm32
для 1-байтовых констант?mov byte ptr [rsi], 0xff
/mov byte ptr [rdi], 0xee
/xor eax,eax
намного короче и эффективнее. В качестве бонуса он действительно будет собираться, в отличие отmov byte [rdi], rax
, у которого несоответствие между размером операнда в байтах и qword. (al
— младший байт RAX). Кроме того,.intel_syntax
GAS похож на MASM, поэтому вам нуженbyte ptr
, а неbyte
в стиле NASM. Если Rust не использует другой ассемблер, который только немного похож на GAS, это не ваш настоящий ассемблерный код. - person Peter Cordes   schedule 16.12.2018