【发布时间】:2015-02-20 01:22:03
【问题描述】:
我是汇编新手,我想先尝试直观地了解将字符串打印到终端的工作原理,而无需通过操作系统抽象(Linux 或 OSX)。
(编者注:接受的答案仅涵盖 Linux。x86-64 MacOS 使用类似的系统调用约定,但调用号不同。)
tl;dr 如何在 OSX 上使用 NASM 在 x86-64 程序集中以尽可能低的级别(即没有系统调用)写入标准输出(打印到终端)? BareMetal OS 是如何做到这一点的?
大多数示例显示类似this:
global start
section .text
start:
mov rax, 1
mov rdi, 1
mov rsi, message
mov rdx, 13
syscall
mov eax, 60
xor rdi, rdi
syscall
message:
db "Hello world", 10
在那里,他们使用syscall 打印字符串,即relying on the operating system。我不是在寻找那个,而是在寻找如何以尽可能低的级别直接将字符串写入标准输出。
我认为有这个 exokernel 项目 BareMetal OS 正在这样做。虽然由于我是组装新手,但我还没有足够的知识来弄清楚他们是如何做到这一点的。看起来,两个重要的文件是:
似乎要打印的相关代码是这样的(从这两个文件中提取):
;
; Display text in terminal.
;
; IN: RSI = message location (zero-terminated string)
; OUT: All registers preserved
;
os_output:
push rcx
call os_string_length
call os_output_chars
pop rcx
ret
;
; Displays text.
;
; IN: RSI = message location (an ASCII string, not zero-terminated)
; RCX = number of chars to print
; OUT: All registers preserved
;
os_output_chars:
push rdi
push rsi
push rcx
push rax
cld ; Clear the direction flag.. we want to increment through the string
mov ah, 0x07 ; Store the attribute into AH so STOSW can be used later on
;
; Return length of a string.
;
; IN: RSI = string location
; OUT: RCX = length (not including the NULL terminator)
;
; All other registers preserved
;
os_string_length:
push rdi
push rax
xor ecx, ecx
xor eax, eax
mov rdi, rsi
not rcx
cld
repne scasb ; compare byte at RDI to value in AL
not rcx
dec rcx
pop rax
pop rdi
ret
但这对我来说并不完整(虽然我还不知道,因为我是新手)。
所以我的问题是,按照 BareMetal OS sn-p 的思路,您如何在 OSX 上使用 NASM 的 x86-64 程序集中写入标准输出(打印到终端)?
【问题讨论】:
-
所以您认为
syscalls中的代码不涉及系统调用?您希望如何绕过操作系统(管理操作系统是其工作之一)来执行任何类型的 I/O? -
嗯,在整个 repo 中根本没有提到
syscall或int 0x80,这就是为什么我想知道他们是如何做到的。 -
stdout 是一种操作系统抽象。我不明白你在做什么。
-
Bare Metal OS 通过将字节写入视频内存来做到这一点。 Linux 不会让你这样做。
-
@FrankKotler:仅在与 IBM 兼容的计算机上,在某些视频模式下,使用某些(不是太旧的)显卡...
标签: linux assembly x86-64 nasm