【问题标题】:Do I NEED a data section in assembler? [duplicate]我需要汇编程序中的数据部分吗? [复制]
【发布时间】:2020-12-23 04:59:55
【问题描述】:

我在带有 x64 程序集的 linux 上使用 nasm。

我已经编写了一些有效的 hello world 类型的程序,并开始想知道是否可以打印单个字符而不必有数据部分。我认为这样的事情会起作用,但它不起作用,我不明白为什么。

section .text
        global _start

_start:
        
        mov rdx, 1      ;length - 1 character
        mov rcx, 0x41   ;character 'A'
        mov rbx, 1      ;stdout
        mov rax, 4      ;write syscall
        int 0x80        ;kernel interrupt
        
        mov rax, 1      ;exit syscall
        int 0x80        ;kernel interrupt

【问题讨论】:

  • 不,你当然不需要.data 部分;或任何静态数据。但是write 需要一个指针,而不是一个值。你可以push 'A' / mov rsi, rsp。但当然,您需要使用 64 位 syscall ABI 而不是 32 位 int 0x80 ABI 才能使用 64 位指针。
  • 优秀。谢谢!在这种情况下,堆栈似乎是处理指针的一种更简单的方法。

标签: assembly x86-64 nasm


【解决方案1】:

首先don't use int 0x80 in 64-bit code;请改用syscall interface

write() 系统调用需要一个指向要写入的数据的指针。如果您将0x41 放入该寄存器中(rcx 在您的代码中,但应该是rsisyscall),它将尝试写入地址 0x41 处的任何数据,这当然会失败,因为该页面不是映射。如果你检查系统调用的返回值,这总是一个好主意,你会看到-EFAULT

这对于写入单个字节可能看起来有点低效。您可能希望有一个类似于 C 的 putc 的单独系统调用,它只写入一个字符,并在寄存器中传递。但这是一个非常罕见的案例,可能不值得费心去实施它。大多数应用程序将缓冲它们的写入,以便不必为每个字节进行系统调用。无论如何,与首先进行系统调用的更大开销相比,使用内存的开销可以忽略不计。

所以你的信 A 必须在内存中的某个地方。但它不一定必须在.data 部分。静态数据的任何其他部分都可以:.rodata.bss 如果您在运行时初始化它,甚至在 .text 如果您小心不要执行它。

另一个非常好的选择是将其放入堆栈。

    push 0x41       ; actually pushes 8 bytes but that's okay,
                    ; `0x41` is the low byte because x86 is little-endian
    mov rsi, rsp    ; `rsp` points at what was most recently pushed
    mov edi, 1      ; file descriptor
                    ; it's ok to use edi instead of rdi because writes to 32-bit
                    ; registers are zero extended
    mov edx, 1      ; number of bytes to write
    mov eax, 1      ; system call number for write()
                    ; syscall uses different numbers than int 0x80
    syscall
    add rsp, 8      ; clean up the stack.  
                    ; pop rdi or any other unneeded register would work too, and be shorter

【讨论】:

  • 最终找到了一个关于传递值而不是指针的好副本,提到了strace 和所有内容:How to print a character in Linux x86 NASM?。我知道我之前已经看过(并改进了答案)关于这个问题的一个很好的问答,我花了几分钟才找到。 (它适用于 32 位代码,但这基本上是一个单独的问题;正如您所说,OP 正在尝试的内容不适用于 32 位代码,或者如果使用 64 位 ABI。)
  • 堆栈指针似乎是一种很好的方法。我没有意识到我混合了 32 位和 64 位语法。我正在拉扯我的头发,想知道为什么在进行更正后我会遇到段错误......但我忘记在最后添加退出系统调用。天哪!
猜你喜欢
  • 1970-01-01
  • 2021-10-25
  • 2021-07-03
  • 1970-01-01
  • 2012-04-06
  • 1970-01-01
  • 2011-03-25
  • 2021-02-01
  • 2013-07-02
相关资源
最近更新 更多