如何在不进行系统调用的情况下将字符串打印到x86-64程序集(NASM)中的终端?

问题描述 投票:4回答:1

我是汇编语言的新手,想首先尝试获得一种直观的感觉,即如何在不经过操作系统抽象(Linux或OSX)的情况下将字符串打印到终端将如何工作。

tl; dr如何在OSX上使用NASM在x86-64程序集中以最低级别(即不使用syscall)写入stdout(打印到终端)? 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。我不是在寻找它,而是在如何尽可能低的级别直接向stdout写一个字符串。

我有这个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代码片段的方式,如何在OSX上使用NASM在x86-64程序集中写入stdout(打印到终端?)>

我是汇编语言的新手,想首先尝试获得一种直观的感觉,以了解如何在终端上打印字符串如何工作,而无需经历操作系统抽象(Linux或OSX)。 tl; dr ...

macos assembly x86-64 nasm
1个回答
8
投票

这是一个很好的练习。您将使用syscall(否则将无法访问stdout),但是您可以在没有任何外部库提供输出例程的情况下进行“裸机”写入(如调用printf)。作为x86_64中对stdout的基本“裸机”写入的示例,我整理了一个没有任何内部或系统函数调用的示例:

section .data
    string1 db  0xa, "  Hello StackOverflow!!!", 0xa, 0xa, 0

section .text
    global _start

    _start:
        ; calculate the length of string
        mov     rdi, string1        ; string1 to destination index
        xor     rcx, rcx            ; zero rcx
        not     rcx                 ; set rcx = -1
        xor     al,al               ; zero the al register (initialize to NUL)
        cld                         ; clear the direction flag
        repnz   scasb               ; get the string length (dec rcx through NUL)
        not     rcx                 ; rev all bits of negative results in absolute value
        dec     rcx                 ; -1 to skip the null-terminator, rcx contains length
        mov     rdx, rcx            ; put length in rdx
        ; write string to stdout
        mov     rsi, string1        ; string1 to source index
        mov     rax, 1              ; set write to command
        mov     rdi,rax             ; set destination index to rax (stdout)
        syscall                     ; call kernel

        ; exit 
        xor     rdi,rdi             ; zero rdi (rdi hold return value)
        mov     rax, 0x3c           ; set syscall number to 60 (0x3c hex)
        syscall                     ; call kernel

; Compile/Link
;
; nasm -f elf64 -o hello-stack_64.o hello-stack_64.asm
; ld  -o hello-stack_64 hello-stack_64.o
© www.soinside.com 2019 - 2024. All rights reserved.