首页 > 解决方案 > NASM - 将一个变量的地址存储在另一个变量中

问题描述

我目前正在学习汇编。我想编写一个程序,它以三个相互指向的变量结束:

0x804a000: 0x804a001  ; 0 -> 1
0x804a001: 0x804a002  ; 1 -> 2
0x804a002: 0x804a000  ; 2 -> 0

根据 其他一些帖子,我可以 检索(例如 for ): mov

这是我到目前为止提出的:

section .bss
    head resd 3         ; reserve three dwords

section .text
  global _start
    
_start:

  xor eax, eax
  xor ebx, ebx
  xor ecx, ecx          ; counter = 0

  mov eax, head         ; move the address of head into eax: eax -> 0
  mov ebx, eax          ; move the address of head from eax into ebx: ebx -> 0
  add ebx, 2            ; ebx -> 2
  mov [ebx], eax        ; move the value of eax ( = the address of 0 ) into the address in ebx ( = the address of 2)
  
  loop:                 ; first run     second run
    inc ecx             ; eax -> 0      eax -> 1
    mov ebx, eax        ; ebx -> 0      ebx -> 1
    add eax, 1          ; eax -> 1      eax -> 2
    mov [ebx], eax      ; 0 -> 1            1 -> 2
    cmp ecx, 2          ; ecx = 1 < 2   ecx = 2 == 2
  jl loop

  mov eax, head         ; eax points to the first element
    
  mov   eax,1           ; system call number (sys_exit)
  int   0x80            ; call kernel

这应该基本上是0。保留三个dword,其中第一个在地址head

  1. 将 0 的地址装入eax, 将 2 的地址装入ebx
  2. mov [ebx], eax将 0 的地址写入 2 ( 2 -> 0)
  3. 对字段 0 和 1 重复相同的操作0 -> 11 -> 2
  4. 将head的地址存入eax

现在我组装并运行整个事情

nasm -f elf -g -F dwarf test.asm
ld -m elf_i386 -o test.out test.o

但是, 和 中的值0都是2错误的,因为我可以使用以下方法进行检查gdb

gdb test.out
(gdb) b 27 // break after mov eax, head
(gdb) r
(gdb) i r eax
eax     0x804a000    134520832 // eax points to head
(gdb) print *134520832
$1 = 77595137                  // cell 0 does not point to cell 1
(gdb) print *134520833
$2 = 134520834                 // cell 1 does point to cell 2
(gdb) print *134520834
$3 = 134743200                 // cell 2 does not point to cell 1

这些错误的价值观从何而来?

也许这是因为我尝试将整个 32 位eax写入 16 位双字?我尝试将线条更改为mov [ebx], ax但最终得到相同的结果。

我能想出的另一个原因是内存地址大于 a dword,所以我尝试使用qwords 代替,但最终得到了另一个错误的结果。

我还尝试使用lea assembly instructionlea中所建议的指令,这会导致相同的结果。

有人可以帮我弄这个吗?提前致谢

标签: assemblyx86nasmmemory-address

解决方案


一个 dword 在 x86 中是 32 位的,所以是 4 个字节。“双字”,其中“字”是 16 位的(因为 x86 是从 16 位 8086 演变而来的)。是的,正如您所发现的,x86 是字节可寻址的,就像所有现代主流 ISA 一样。

此外,您的标题问题的答案将是mov dword [head], head+4例如。 head+4在汇编+链接时计算,并变成一个 32 位立即操作数保存该地址,而head变成一个 32 位位移保存另一个地址。

或者您可以像您正在做的那样使用循环,但简化mov [eax-4], eax为将当前元素的地址存储到前一个元素中,并add eax,4推进指针。无需复制到 EBX,只需对内存操作数使用寻址模式以获得恒定偏移量。

如果您想要整个循环/函数的完整示例,请用 C 语言编写并查看编译器输出。如何从 GCC/clang 程序集输出中删除“噪音”?


推荐阅读