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

兰斯·波拉德

我是组装的新手,并且想要首先尝试直观地了解如何在终端上打印字符串而不需要进行操作系统抽象(Linux或OSX)的工作。

(编者注:接受的答案仅适用于Linux。x86-64 MacOS使用类似的系统调用约定,但使用不同的电话号码。)

tl; dr如何在可能的最低级别(即不使用syscall)下使用NASM在OSX上向x86-64程序集写入stdout(打印到终端)?BareMetal OS如何做到这一点?

大多数示例显示类似这样

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用来打印字符串,这取决于操作系统我不是在寻找那个,而是在如何以最低的级别直接将字符串写入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(打印到终端)?

大卫·兰金

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

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

输出:

$ ./hello-stack_64

  Hello StackOverflow!!!

对于一般用途,我将过程分为两部分(1)获取长度和(2)写入stdoutstrprn函数下面将向写入任何字符串stdout它调用strsz以获取长度,同时在堆栈上保留目标索引。这减少了向其中写入字符串的任务,stdout并防止了代码中的很多重复。

; szstr computes the lenght of a string.
; rdi - string address
; rdx - contains string length (returned)
section .text
        strsz:
                xor     rcx, rcx                ; zero rcx
                not     rcx                     ; set rcx = -1 (uses bitwise id: ~x = -x-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 -> absolute value
                dec     rcx                     ; -1 to skip the null-term, rcx contains length
                mov     rdx, rcx                ; size returned in rdx, ready to call write
                ret

; strprn writes a string to the file descriptor.
; rdi - string address
; rdx - contains string length
section .text
        strprn:
                push    rdi                     ; push string address onto stack
                call    strsz                   ; call strsz to get length
                pop     rsi                     ; pop string to rsi (source index)
                mov     rax, 0x1                ; put write/stdout number in rax (both 1)
                mov     rdi, rax                ; set destination index to rax (stdout)
                syscall                         ; call kernel
                ret

为了进一步自动化对stdoutNASM宏的常规输出,提供了一种方便的解决方案。示例strn(的缩写string_n)。它带有两个参数,即字符串的地址和要写入的字符数:

%macro  strn    2
        mov     rax, 1
        mov     rdi, 1
        mov     rsi, %1
        mov     rdx, %2
        syscall
%endmacro

对于缩进,换行或编写完整的字符串很有用。您可以通过传递3个参数(包括的目标位置)来进一步概括rdi

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不使用js的情况下将java中的json字符串化

在程序集x86中处理字符串(移动并打印到屏幕)

如何在不使用 Hashmap 的情况下对字符串中的字符重新排序?

PHP 在某些情况下将缓冲区字符串打印到网页中?

如何在不使用to_string或stoi的情况下将int转换为C ++ 11中的字符串?

如何在不使用doubleval函数的情况下将字符串转换为php中的double?

如何在不使用Jackson Api的情况下将Java中的字符串转换为List <String>

如何在不使用字典的情况下将字符串转换为python中的变量?

如何在 C 中不使用括号的情况下修改字符串文字的内容?

如何在不使用.replace的情况下替换Java字符串中的单词

如何在不使用数组的情况下删除字符串中的重复单词?

如何在不使用 javascript 中的替换函数的情况下替换字符串?

如何在不使用列表的情况下转换字符串中的数字?

如何在不使用 indexof 的情况下比较字符串并包含在 jquery 中

如何在不使用python中的字符串函数的情况下将字符串的字符从小写转换为大写,反之亦然?

如何在 Mac 上的 x86 程序集 (NASM) 中打印有符号整数

如何在不使用反射和第三方软件的情况下确定是否使用平台目标AnyCPU,AnyCPU Prefer32位,x86,x64构建了.NET程序集

如何在不使用Collections.shuffle(...)的情况下随机播放字符串中的字符?

如何在不使用任何for或while循环的情况下将列表列表打印到python中的单个列表中?

如何在不使用bash -x的情况下将命令保存在变量中并打印翻译后的命令

如何在不使用正则表达式的情况下使用javascript搜索数组中的字符串

在Dart中,如何在不使用dart.io的情况下将字符串保存到用户的本地文件中?

如何在x86汇编中获取长字符串的长度以在断言时打印

如何在不使用循环的情况下搜索在其键中包含给定字符串的对象?

在 Perl 中,如何在不使用模块的情况下判断字符串是否为数字?

如何在不使用内置函数的情况下对字符串数组中的重复项进行排序和删除?

如何在不使用方法字符串名称的情况下获取Java中的Method对象

如何在不使用XmlService的情况下解析Google Apps脚本中的HTML字符串?

如何在不使用rowindex的情况下获取字符串中的gridview行值?