【问题标题】:Writing a putchar in Assembly for x86_64 with 64 bit Linux?使用 64 位 Linux 在汇编中为 x86_64 编写 putchar?
【发布时间】:2018-11-13 19:38:21
【问题描述】:

我正在尝试使用 write syscall 来重现打印单个字符的 putchar 函数行为。我的代码如下,

asm_putchar:
  push    rbp
  mov     rbp, rsp

  mov     r8, rdi

call:
  mov     rax, 1
  mov     rdi, 1
  mov     rsi, r8
  mov     rdx, 1
  syscall

return:
  mov     rsp, rbp
  pop     rbp
  ret

【问题讨论】:

  • 您是否验证了rdi 包含有效的字符串地址?另外,你是在 64 位 Linux 系统上运行的,对吧?
  • 你能用C写吗?请注意,putchar 接受一个字符,但 write 需要一个指针。
  • 是的,我在 64 位 Linux 上运行,我知道 write 需要一个指针,但大多数使用此系统调用的人使用数据部分来存储字符串
  • @Lucas 将所需字符压入堆栈,然后将指向该字符的指针传递给系统调用。
  • 您不需要额外的注册。你需要记忆。此外,您根本不需要触摸rbp(包括推送/弹出)。你可以只在开头push rdi 将字符存入堆栈(= 内存),然后mov rsi,rsp 将存储的char 的内存地址存入rsi。并记住在sys_write 之后释放存储的字符,例如add rsp,8(或pop 到您不再需要的某个寄存器中,pop rcx 可能是不错的候选者,因为rcx 已被@987654336 修改@ 已经)。

标签: linux assembly nasm x86-64 system-calls


【解决方案1】:

man 2 write可以看到write的签名是,

ssize_t write(int fd, const void *buf, size_t count);

它需要一个指针 (const void *buf) 指向内存中的缓冲区。你不能通过值传递char,所以你必须将它存储到内存并传递一个指针。

(不要一次打印一个字符,除非你只有一个要打印,那真的很低效。在内存中构造一个缓冲区并打印它。例如这个 x86-64 Linux NASM 函数:How do I print an integer in Assembly Level Programming without printf from the c library?

GCC: putchar(char) in inline assembly 的 NASM 版本:

; x86-64 System V calling convention: input = byte in DIL
; clobbers: RDI, RSI, RDX,  RCX, R11 (last 2 by syscall itself)
; returns:  RAX = write return value: 1 for success, -1..-4095 for error
writechar:
    mov    byte [rsp-4], dil      ; store the char from RDI

    mov     edi, 1                ; EDI = fd=1 = stdout
    lea     rsi, [rsp-4]          ; RSI = buf
    mov     edx, edi              ; RDX = len = 1
    syscall                    ; rax = write(1, buf, 1)
    ret

【讨论】:

    猜你喜欢
    • 2012-11-20
    • 2011-09-22
    • 2021-05-29
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 2015-01-09
    相关资源
    最近更新 更多