【问题标题】:NASM - Storing the address of one variable in another variableNASM - 将一个变量的地址存储在另一个变量中
【发布时间】:2020-12-27 13:24:27
【问题描述】:

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

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

Accordingtosomeotherposts,我可以检索(例如mov):

  • 变量x的内容使用[x]
  • 变量地址x使用x

到目前为止,这是我想出的:

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 -&gt; 0)
  3. 对字段 0 和 1 重复相同的操作:0 -&gt; 1、1 -&gt; 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,但结果相同。

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

我还尝试使用lea assembly instruction 中建议的lea 指令,结果相同。

有人可以帮我解决这个问题吗?提前致谢

【问题讨论】:

    标签: assembly x86 nasm memory-address


    【解决方案1】:

    一个 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 语言编写它并查看编译器输出。 How to remove "noise" from GCC/clang assembly output?

    【讨论】:

      【解决方案2】:

      好吧,在阅读了更多关于此的内容之后,解决方案非常明显。 每个地址对应一个字节。如果我所有的单元格都是 qwords,我需要将每个循环中的地址增加 4,而不是 1:

      section .bss
          head resq 4         ; three qwords
      
      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        ; eax -> 0
          add ebx, 12         ; ebx -> 3
          mov [ebx], eax      ; 3 -> 0
      
          loop:               ; first run     second run
          inc ecx             ; counter = 0 counter = 1
          mov ebx, eax        ; ebx -> 0      ebx -> 1
          add eax, 4          ; eax -> 1      eax -> 2
          mov [ebx], eax      ; 0 -> 1            1 -> 2
          cmp ecx, 3          ; 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
      

      地址(至少对于我的设置而言)最多 32 位 = 4 个字节,所以我的第一次尝试没有奏效,因为我用写入的下一个地址覆盖了每个地址。这就是为什么只有第二个值是正确的——它是最后一个被写入的值。

      【讨论】:

      • “我想编写一个以 三个 变量相互指向的变量结束的程序”曾经发生过什么这个答案现在处理 4 个变量!还有为什么要保留 4 个Q字而不是 3 个D字?
      猜你喜欢
      • 1970-01-01
      • 2022-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 2018-07-20
      相关资源
      最近更新 更多