在64位Linux上为x86_64编写一个putchar程序集?

mw3dktmi  于 2023-03-07  发布在  Linux
关注(0)|答案(1)|浏览(194)

我尝试使用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
zzlelutf

zzlelutf1#

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

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

它接受一个指向内存中缓冲区的指针(const void *buf),但不能通过值传递char,所以必须将其存储到内存中并传递一个指针。
(Don不要一次打印一个字符,除非你只有一个字符要打印,这是非常低效的。在内存中构造一个缓冲区并打印它。例如,x86 - 64 Linux NASM函数:如何在汇编级编程中打印一个整数而不从c库中打印?(itoa,整数到十进制ASCII字符串)
GCC的NASM版本:内联程序集中的putchar(char):

; 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     eax, 1                ; __NR_write syscall number from unistd_64.h
    mov     edi, 1                ; EDI = fd=1 = stdout
    lea     rsi, [rsp-4]          ; RSI = buf
    mov     edx, edi              ; RDX = len = 1  happens to be the same as fd and call #
    syscall                    ; rax = write(1, buf, 1)
    ret

如果你在RSI中传递了一个无效的指针,比如'2'(整数50),系统调用将在RAX中返回-EFAULT-14)。(内核在指向系统调用的坏指针上返回错误代码,而不是像你在用户空间中deref那样传递SIGSEGV)。
另请参见What are the return values of system calls in Assembly?
在玩具程序/实验中,您应该在strace ./a.out下运行它们,而不是编写代码来检查返回值,特别是如果您编写自己的_start而不使用libc,那么在启动过程中不会有任何其他系统调用,您自己也不会这样做,因此非常容易读取输出。How should strace be used?

相关问题