用 64 位 Linux 为 x86_64 编写一个 putchar?
Writing a putchar in Assembly for x86_64 with 64 bit Linux?
我正在尝试使用写入 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
从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
如果你做在RSI中传递一个无效的指针,例如'2'
(整数50
),系统调用将return -EFAULT
(-14
) 在 RAX 中。 (内核 return 错误代码指向系统调用的错误指针,而不是像在 user-space 中取消引用时那样传递 SIGSEGV。
另见
与其编写代码来检查 return 值,在玩具程序/实验中你应该 运行 它们在 strace ./a.out
下,特别是如果你正在编写自己的 [=21] =] 如果没有 libc,在启动期间将不会有任何其他不是您自己创建的系统调用,因此读取输出非常容易。 How should strace be used?
我正在尝试使用写入 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
从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
如果你做在RSI中传递一个无效的指针,例如'2'
(整数50
),系统调用将return -EFAULT
(-14
) 在 RAX 中。 (内核 return 错误代码指向系统调用的错误指针,而不是像在 user-space 中取消引用时那样传递 SIGSEGV。
另见
与其编写代码来检查 return 值,在玩具程序/实验中你应该 运行 它们在 strace ./a.out
下,特别是如果你正在编写自己的 [=21] =] 如果没有 libc,在启动期间将不会有任何其他不是您自己创建的系统调用,因此读取输出非常容易。 How should strace be used?