前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >汇编学习(8) 宏,IO

汇编学习(8) 宏,IO

作者头像
一只小虾米
发布2022-12-13 17:31:05
4740
发布2022-12-13 17:31:05
举报
文章被收录于专栏:Android点滴分享Android点滴分享

本篇介绍

本篇介绍下汇编中的宏和IO操作,其中IO操作包括控制台IO和文件IO

首先宏并不是汇编支持的,而是nasm 汇编器支持的,这个也容易想到,汇编本身是一套指令,而宏就是将若干指令替换成一个符号,在编译的时候再展开到代码中,这完全是编译层面的能力。 接下来看一个代码例子,nasm汇编的使用;

代码语言:javascript
复制
; macro.asm
extern printf

%define double_it(r)    sal r, 1    ; single line macro

%macro  prntf   2           ; multiline macro with 2 arguments
    section .data
            %%arg1  db  %1,0            ; first argument
            %%fmtint    db  "%s %ld",10,0   ; formatstring
    section .text               ; the printf arguments
        mov rdi, %%fmtint
        mov rsi, %%arg1
        mov rdx,[%2]        ; second argument
        mov rax,0           ; no floating point  
        call printf
%endmacro

section .data                           
    number  dq  15                  
section .bss
section .text                           
    global main                     
main:
push rbp
mov rbp,rsp
    prntf   "The number is", number
    mov     rax, [number]
    double_it(rax)
    mov     [number],rax
    prntf   "The number times 2 is", number
leave
ret 
结果如下:
The number is 15
The number times 2 is 30

可以看到有2种宏,一种是单行的,这时候用%define 就可以了。另外一种是多行的,这时候需要用%macro 和 %endmacro。而且对于多行的宏,可以指定参数的个数,%n表示第n个入参地址,如果宏内部需要用变量,变量名字前就需要用%% 做前缀,比如%%arg1,%%fmtint。%% 就是告诉nasm每次调用宏就需要创建新的变量实例,这样就不会遇到变量重复定义的问题了。 接下来也可以反编译看下结果:

代码语言:javascript
复制
0000000000401130 <main>:
  401130:   55                      push   rbp
  401131:   48 89 e5                mov    rbp,rsp
  401134:   48 bf 46 40 40 00 00    movabs rdi,0x404046
  40113b:   00 00 00 
  40113e:   48 be 38 40 40 00 00    movabs rsi,0x404038
  401145:   00 00 00 
  401148:   48 8b 14 25 30 40 40    mov    rdx,QWORD PTR ds:0x404030
  40114f:   00 
  401150:   b8 00 00 00 00          mov    eax,0x0
  401155:   e8 d6 fe ff ff          call   401030 <printf@plt>
  40115a:   48 8b 04 25 30 40 40    mov    rax,QWORD PTR ds:0x404030
  401161:   00 
  401162:   48 d1 e0                shl    rax,1
  401165:   48 89 04 25 30 40 40    mov    QWORD PTR ds:0x404030,rax
  40116c:   00 
  40116d:   48 bf 64 40 40 00 00    movabs rdi,0x404064
  401174:   00 00 00 
  401177:   48 be 4e 40 40 00 00    movabs rsi,0x40404e
  40117e:   00 00 00 
  401181:   48 8b 14 25 30 40 40    mov    rdx,QWORD PTR ds:0x404030
  401188:   00 
  401189:   b8 00 00 00 00          mov    eax,0x0
  40118e:   e8 9d fe ff ff          call   401030 <printf@plt>
  401193:   c9                      leave  
  401194:   c3                      ret 

这样就可以看到宏被展开后的结果了,基本可以和把宏用指令替换对上。

控制台 IO

有时候我们需要直接从控制台读写,这时候除了用c的io函数外,也可以直接用read,write的系统调用,下面是一个例子,用来从控制台读取内容,然后显示到控制台上:

代码语言:javascript
复制
; console2.asm
section .data                           
    msg1    db      "Hello, World!",10,0            
    msg2    db      "Your turn (only a-z): ",0
    msg3    db      "You answered: ",0
    inputlen equ    10          ;inputbuffer
    NL      db      0xa                 
section .bss                            
    input resb inputlen+1       ;provide space for ending 0
section .text                           
    global main                     
main:
push    rbp 
mov     rbp,rsp
    mov     rdi, msg1       ; print first string 
    call    prints    
    mov     rdi, msg2   ; print second string, no NL 
    call    prints
    mov     rdi, input      ; address of inputbuffer
    mov     rsi, inputlen   ; length of inputbuffer 
    call    reads           ; wait for input 
    mov     rdi, msg3       ; print third string and add the input string
    call    prints
    mov     rdi, input      ; print the inputbuffer
    call    prints
    mov     rdi,NL          ; print NL
    call    prints     
leave
ret
;----------------------------------------------------------
prints:
push    rbp
mov     rbp, rsp
push    r12                 ; callee saved

; Count characters 
        xor     rdx, rdx    ; length in rdx
        mov     r12, rdi   
.lengthloop:
        cmp     byte [r12], 0
        je      .lengthfound
        inc     rdx
        inc     r12
        jmp     .lengthloop
.lengthfound:       ; print the string, length in rdx
        cmp     rdx, 0      ; no string (0 length)
        je      .done
        mov     rsi,rdi     ; rdi contains address of string
        mov     rax, 1      ; 1 = write
        mov     rdi, 1      ; 1 = stdout
        syscall
.done:
pop r12
leave 
ret
;----------------------------------------------------------
reads:
section .data
section .bss
        .inputchar  resb    1  
section .text
push    rbp
mov rbp, rsp
    push    r12         ; callee saved
    push    r13         ; callee saved
    push    r14         ; callee saved
    mov     r12, rdi    ; address of stringbuffer
    mov     r13, rsi    ; max length in r13
    xor     r14, r14    ; character counter
.readc: 
        mov     rax, 0          ; read
        mov     rdi, 1          ; stdin
        lea     rsi, [.inputchar]   ; address of input
        mov     rdx, 1          ; # of characters to read
        syscall
        mov     al, [.inputchar]    ; char is NL?
        cmp     al, byte[NL]
        je      .done           ; NL end
        cmp     al, 97          ; lower than a?
        jl      .readc          ; ignore it
        cmp     al, 122         ; higher than z?
        jg      .readc          ; ignore it
        inc     r14             ; inc counter
        cmp     r14, r13
        ja      .readc          ; buffer max reached, ignore
        mov     byte [r12], al  ; safe the char in the buffer
        inc     r12             ; point to next char in buffer
        jmp     .readc 
.done:
        inc     r12
        mov     byte [r12],0    ; add end 0 to stringbuffer
    pop     r14         ; callee saved
    pop     r13         ; callee saved
    pop     r12         ; callee saved
leave
ret

输出:
./console2 
Hello, World!
Your turn (only a-z): hello
You answered: hello

这儿的关键点在于读写时候的系统调用,比如写的时候也是用rdi,rsi,rdx来传参的,用rax指定系统调用号,用代码中可以看到,读的系统调用号是0,写是1。

文件IO

接下来是一段文件IO 的例子,涉及到创建文件,读写文件,关闭删除文件,代码比较多,不过逻辑比较简单:

代码语言:javascript
复制
; file.asm
section .data
; expressions used for conditional assembly
    CREATE      equ     1
    OVERWRITE   equ     1
    APPEND      equ     1
    O_WRITE     equ     1
    READ        equ     1
    O_READ      equ     1
    DELETE      equ     1
            
; syscall symbols
    NR_read     equ     0 
    NR_write    equ     1 
    NR_open     equ     2 
    NR_close    equ     3
    NR_lseek    equ     8 
    NR_create   equ     85
    NR_unlink   equ     87

; creation and status flags
    O_CREAT     equ     00000100q  
    O_APPEND    equ     00002000q

; access mode    
    O_RDONLY    equ     000000q 
    O_WRONLY    equ     000001q 
    O_RDWR      equ     000002q

; create mode (permissions)
    S_IRUSR     equ     00400q  ;user read permission
    S_IWUSR     equ     00200q  ;user write permission
 
    NL          equ     0xa                 
    bufferlen   equ     64
   
    fileName db     "testfile.txt",0
    FD       dq     0   ; file descriptor

    text1    db     "1. Hello...to everyone!",NL,0
    len1     dq     $-text1-1                  ;remove 0
    text2    db     "2. Here I am!",NL,0
    len2     dq     $-text2-1                   ;remove 0
    text3    db     "3. Alife and kicking!",NL,0
    len3     dq     $-text3-1                   ;remove 0
    text4    db     "Adios !!!",NL,0
    len4     dq     $-text4-1

    error_Create    db "error creating file",NL,0
    error_Close     db "error closing file",NL,0
    error_Write     db "error writing to file",NL,0
    error_Open      db "error opening file",NL,0
    error_Append    db "error appending to file",NL,0
    error_Delete    db "error deleting file",NL,0
    error_Read      db "error reading file",NL,0
    error_Print     db "error printing string",NL,0
    error_Position  db "error positioning in file",NL,0
        
    success_Create  db "File created and opened",NL,0
    success_Close   db "File closed",NL,NL,0
    success_Write   db "Written to file",NL,0
    success_Open    db "File opened for reading/(over)writing/updating",NL,0
    success_Append  db "File opened for appending",NL,0
    success_Delete  db "File deleted",NL,0
    success_Read    db "Reading file",NL,0
    success_Position db "Positioned in file",NL,0
    
section .bss                            
    buffer resb bufferlen
section .text                           
    global main                     
main:
    push rbp
    mov  rbp,rsp
%IF CREATE
;CREATE AND OPEN A FILE, THEN CLOSE -----------------------------------------
; create and open file
    mov     rdi, fileName
    call    createFile
    mov     qword [FD], rax ; save descriptor

; write to file #1
    mov     rdi, qword [FD]
    mov     rsi, text1
    mov     rdx, qword [len1]
    call    writeFile
    
; close file
    mov     rdi, qword [FD]
    call    closeFile
%ENDIF
%IF OVERWRITE
;OPEN AND OVERWRITE A FILE, THEN CLOSE ---------------------------------------
; open file 
    mov     rdi, fileName 
    call    openFile  
    mov     qword [FD], rax ; save file descriptor
    
; write to file #2 OVERWRITE!
    mov     rdi, qword [FD]
    mov     rsi, text2
    mov     rdx, qword [len2]
    call    writeFile    

; close file
    mov     rdi, qword [FD]
    call    closeFile    
%ENDIF
%IF APPEND
;OPEN AND APPEND TO A FILE, THEN CLOSE ---------------------------------------
; open file to append
    mov     rdi, fileName 
    call    appendFile  
    mov     qword [FD], rax ; save file descriptor
    
; write to file #3 APPEND!
    mov     rdi, qword [FD]
    mov     rsi, text3
    mov     rdx, qword [len3]
    call    writeFile       

; close file
    mov     rdi, qword [FD]
    call    closeFile 
%ENDIF
%IF O_WRITE
;OPEN AND OVERWRITE AT AN OFFSET IN A FILE, THEN CLOSE -----------------------
; open file to write
    mov     rdi, fileName 
    call    openFile  
    mov     qword [FD], rax ; save file descriptor

; position file at offset
    mov     rdi, qword[FD]
    mov     rsi, qword[len2] ;offset at this location
    mov     rdx, 0
    call    positionFile    

; write to file at offset
    mov     rdi, qword[FD]
    mov     rsi, text4
    mov     rdx, qword [len4]
    call    writeFile 

; close file
    mov     rdi, qword [FD]
    call    closeFile 
%ENDIF
%IF READ
;OPEN AND READ FROM A FILE, THEN CLOSE ---------------------------------------
; open file to read
    mov     rdi, fileName 
    call    openFile  
    mov     qword [FD], rax ; save file descriptor  
      
; read from file
    mov     rdi, qword [FD]
    mov     rsi, buffer
    mov     rdx, bufferlen    
    call    readFile
    mov     rdi,rax
    call    printString

; close file
    mov     rdi, qword [FD]
    call    closeFile 
%ENDIF
%IF O_READ
;OPEN AND READ AT AN OFFSET FROM A FILE, THEN CLOSE ---------------------------------------
; open file to read
    mov     rdi, fileName 
    call    openFile  
    mov     qword [FD], rax ; save file descriptor  

; position file at offset
    mov     rdi, qword[FD]
    mov     rsi, qword[len2]        ;skip the first line
    mov     rdx, 0
    call    positionFile          

; read from file
    mov     rdi, qword [FD]
    mov     rsi, buffer
    mov     rdx, 10    ;number of characters to read
    call    readFile
    mov     rdi,rax
    call    printString

; close file
    mov     rdi, qword [FD]
    call    closeFile 
%ENDIF
%IF DELETE
;DELETE A FILE --------------------------------------------------   
; delete file   UNCOMMENT NEXT LINES TO USE
    mov     rdi, fileName
    call    deleteFile                                      
%ENDIF


leave
ret

; FILE MANIPULATION FUNCTIONS-------------------------------------
;-----------------------------------------------------------------
global readFile
readFile:
    mov     rax, NR_read
    syscall                         ; rax contains # of characters read
    cmp     rax, 0 
    jl      readerror
    mov     byte [rsi+rax],0    ; add a terminating zero to the string
    mov     rax, rsi
    
    mov     rdi, success_Read
    push    rax     ; caller saved
    call    printString
    pop     rax     ; caller saved
    ret
readerror:
        mov     rdi, error_Read 
        call    printString
        ret  
;-----------------------------------------------------------------
global deleteFile
deleteFile:
    mov     rax, NR_unlink
    syscall
    cmp     rax, 0 
    jl      deleteerror
    mov     rdi, success_Delete
    call    printString
    ret
deleteerror:
        mov     rdi, error_Delete 
        call    printString
        ret  
;-----------------------------------------------------------------
global appendFile
appendFile:
    mov     rax, NR_open 
    mov     rsi,  O_RDWR|O_APPEND
    syscall
    cmp     rax, 0 
    jl      appenderror
    mov     rdi, success_Append
    push    rax     ; caller saved
    call    printString
    pop     rax     ; caller saved
    ret
appenderror:
        mov     rdi, error_Append 
        call    printString
        ret  
;-----------------------------------------------------------------
global openFile
openFile:
    mov     rax, NR_open 
    mov     rsi, O_RDWR
    syscall
    cmp     rax, 0 
    jl      openerror
    mov     rdi, success_Open
    push    rax     ; caller saved
    call    printString
    pop     rax     ; caller saved
    ret
openerror:
        mov     rdi, error_Open 
        call    printString
        ret  
;-----------------------------------------------------------------
global writeFile
writeFile:
    mov     rax, NR_write
    syscall
    cmp     rax, 0 
    jl      writeerror
    mov     rdi, success_Write
    call    printString
    ret
writeerror:
        mov     rdi, error_Write 
        call    printString
        ret

;-----------------------------------------------------------------
global positionFile
positionFile:
    mov     rax, NR_lseek
    syscall
    cmp     rax, 0 
    jl      positionerror
    mov     rdi, success_Position
    call    printString
    ret
positionerror:
        mov     rdi, error_Position 
        call    printString
        ret    
;-----------------------------------------------------------------
global closeFile
closeFile:
    mov     rax, NR_close
    syscall
    cmp     rax, 0 
    jl      closeerror
    mov     rdi, success_Close
    call    printString
    ret
closeerror:
        mov     rdi, error_Close 
        call    printString
        ret    
;-----------------------------------------------------------------
global createFile
createFile:
    mov     rax, NR_create
    mov     rsi, S_IRUSR |S_IWUSR 
    syscall
    cmp     rax, 0          ; file descriptor in rax
    jl      createerror
    mov     rdi, success_Create
    push    rax     ; caller saved
    call    printString
    pop     rax     ; caller saved
    ret
createerror:
        mov     rdi, error_Create 
        call    printString
        ret    

; PRINT FEEDBACK
;-----------------------------------------------------------------
global printString
printString:

; Count characters 
    mov     r12, rdi
    mov     rdx, 0 
strLoop:
    cmp     byte [r12], 0
    je      strDone
    inc     rdx                 ;length in rdx
    inc     r12
    jmp     strLoop
strDone:
    cmp     rdx, 0              ; no string (0 length)
    je      prtDone
    mov     rsi,rdi
    mov     rax, 1 
    mov     rdi, 1
    syscall
prtDone:

    ret

运行结果:
File created and opened
Written to file
File closed

File opened for reading/(over)writing/updating
Written to file
File closed

File opened for appending
Written to file
File closed

File opened for reading/(over)writing/updating
Positioned in file
Written to file
File closed

File opened for reading/(over)writing/updating
Reading file
2. Here I am!
Adios !!!
3. Alife and kicking!
File closed

File opened for reading/(over)writing/updating
Positioned in file
Reading file
Adios !!!
File closed

File deleted

这儿都是通过系统调用操作的IO,libc的文件IO本质上也是这样,当然libc还会有一层cache。从这段代码可以看出系统调用的返回值也是通过rax传递的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-12-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本篇介绍
  • 控制台 IO
  • 文件IO
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档