【问题标题】:Understanding pointers in assembly language理解汇编语言中的指针
【发布时间】:2021-05-28 13:17:39
【问题描述】:

我们是否将变量或寄存器括在括号中以指定汇编中的指针?

示例1;

    MOV eax, array+4
    LEA eax, [array+4]

示例2;

section .data
    array DB 116,97

section .bss
    variable RESB 0

section .text
    global _start:

_start:
    mov eax,[array]

    ;exit
    mov eax,1
    int 0x80

我在编译或运行上述代码时没有遇到任何错误。数组的零索引地址是否放在EAX寄存器中?

例子3;

    INC [variable]

编译上述代码时,我收到“未指定操作大小”错误。以及为什么不能将命令用作INC variable

示例4;

section .data
    array DB 116,97

section .bss
    variable RESB 97

section .text
    global _start:

_start:
    mov eax,4
    mov ebx,1
    mov ecx,variable
    mov edx,1
    int 0x80

    ;exit
    mov eax,1
    int 0x80

而且这段代码不工作。

【问题讨论】:

  • [] 表示内存引用。没有它,它是一个可以是地址的文字数字。 nasm 不跟踪变量类型,因此如果无法推断,您需要告诉它大小。所以inc byte [variable] 会起作用。 inc variable 将不起作用,因为它会尝试增加文字常量(variable 的地址)。最后一个示例#4 正在运行,但您正在从variable 打印一个零字节。也许你的意思是mov ecx, array
  • 我不明白你所说的#4 是什么意思。我到底错在哪里?谢谢你的其他事情。 @小丑
  • 不清楚您希望示例 #4 做什么。它确实有效。它打印variable 的第一个字节,这是一个二进制零。也许你想要db 97 而不是resb 97?这只能在.data 中工作,因为.bss 全为零。 resb 97 分配 97 个零。

标签: pointers assembly x86 nasm


【解决方案1】:

我们是否将变量或注册器括在括号中以指定一个 汇编中的指针?

示例1;

MOV eax, array+4
LEA eax, [array+4]

括号类似于 C 中的取消引用运算符 (*ptr)。他们在方括号内的结果地址处获取值。至于这个例子,这两者本质上都是做同样的事情。第一个将array 标签的地址+4 移动到eax。第二个使用lea,它加载其源操作数的有效地址。所以你得到array + 4,取消引用它,然后用lea再次获取地址并将其加载到eax中。

示例2;

section .data
    array DB 116,97

section .bss
    variable RESB 0

section .text
    global _start:

_start:
    mov eax,[array]

    ;exit
    mov eax,1
    int 0x80

在编译或运行上述代码时,我没有收到任何错误。 是放在eax中的数组零索引的地址 注册?

有点。由于您要将其移动到 32 位寄存器 eax 中,因此假设您要将地址 array 处的前 4 个字节移动到 eax 中。但是array只有2个字节:11697。所以这可能不是你想要的。要将array 的第一个字节加载到eax,请执行movzx eax, BYTE [array],这会将array[0] 移动到eax 的LSByte 中,并将较高的字节清零。 mov al, [array] 也可以,但不会将高位字节归零。

例子3;

INC [variable]

编译上述代码时,我得到“操作大小不 指定”错误。为什么不能将命令用作INC变量。

错误说明了一切。 variable 只是一个地址。当你使用[]时,应该占用多少字节?您需要指定尺寸。例如,要获取第一个字节,您可以使用inc BYTE [variable]。但是,从前面的示例中,您似乎没有在 variable 保留任何内容,因此尝试访问其中的任何字节可能会导致一些问题。至于“为什么不能将命令用作INC variable”,正如我刚才所说,variable 只是一个转换为某个地址的标签。您无法更改variable 转换为的地址。

示例4;

section .data
    array DB 116,97

section .bss
    variable RESB 97

section .text
    global _start:

_start:
    mov eax,4
    mov ebx,1
    mov ecx,variable
    mov edx,1
    int 0x80

    ;exit
    mov eax,1
    int 0x80

而且这段代码不工作。

它似乎没有打印任何东西,但实际上是。 .bss 对您保留的任何内存进行零初始化。这意味着当您在variable 打印第一个字节时,它只打印 NUL 字符。但是,当您打印它时,您似乎看不到它,因此似乎没有打印任何内容。

(顺便说一句,你确定你知道resb 做了什么吗?在一个示例中,您保留了 0 个字节,而在另一个示例中,您无缘无故地保留了 97 个字节。您可能想再看看resb 实际做了什么。)

【讨论】:

  • 感谢您所做的一切。我应该怎么做才能在最后一个代码中打印字母“a”? (使用变量)
  • @yulaf_ve_abant RESB 保留字节。就像我说的,你会想再看看 RESB 是做什么的。对于打印'a',您可能希望将variable resb 97 替换为.data.rodata 中的variable db 97
  • 请注意mov eax, BYTE [array] 无效。你的意思可能是movzx
  • 天哪。我认为 .data 部分中的数据是不可更改的。好的,我知道了,谢谢。地址TutorialPoint写着,.data段的数据不能更改。
  • @yulaf_ve_abant 我不知道这是怎么回事,因为你可以:/ 虽然正如我之前提到的,.rodata 专门用于无法更改的数据。
【解决方案2】:
array            ; variable address
byte[array]      ; value of first byte of array
word[array]      ; value of first word of array
byte[array + 1]  ; value of second byte of array

将变量名视为指针,使用size[name] 获取指向的值(类似于C 中的*name,其中name 是一个指针)

【讨论】:

  • Asm 标签的工作方式与 C 中的 extern char foo[] 很相似——使用裸标签名称给出地址,这与其他类型的 C 变量不同,其中隐式访问内存。 C 语言中的char *foo 表示某处有一些数据存储器,其字节保存地址;对于 asm 标签,情况并非如此。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-19
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多