美文网首页
汇编学习(4), 整数,栈,浮点

汇编学习(4), 整数,栈,浮点

作者: android小奉先 | 来源:发表于2022-12-02 20:40 被阅读0次

    本篇介绍

    本篇介绍汇编的整数,浮点运算,还有栈。

    整数运算

    代码如下:

    ; icalc.asm
    extern printf
    section .data                           
        number1 dq  128 ; the numbers to be used to                     
        number2 dq  19  ; show the arithmetic
        neg_num dq  -12 ; to show sign extension
        fmt     db  "The numbers are %ld and %ld",10,0                  
        fmtint  db  "%s %ld",10,0 
        sumi    db  "The sum is",0  
        difi    db  "The difference is",0
        inci    db  "Number 1 Incremented:",0
        deci    db  "Number 1 Decremented:",0
        sali    db  "Number 1 Shift left 2 (x4):",0
        sari    db  "Number 1 Shift right 2 (/4):",0
        sariex  db  "Number 1 Shift right 2 (/4) with "
                db  "sign extension:",0
        multi   db  "The product is",0
        divi    db  "The integer quotient is",0
        remi    db  "The modulo is",0 
    section .bss
            resulti resq    1
            modulo  resq    1
    section .text                           
        global main                     
    main:
        push    rbp
        mov     rbp,rsp
    ; displaying the numbers
            mov rdi, fmt
            mov rsi, [number1]
            mov rdx, [number2]
            mov rax, 0
            call printf
    ; adding---------------------------------------------------------------------
        mov rax, [number1]
        add rax, [number2]      ; add number2 to rax
        mov [resulti], rax      ; move sum to result
        ; displaying the result
            mov rdi, fmtint
            mov rsi, sumi
            mov rdx, [resulti]
            mov rax, 0
            call printf
    ; substracting---------------------------------------------------------------
        mov rax, [number1]
        sub rax, [number2]      ; subtract number2 from rax
        mov [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, difi
            mov rdx, [resulti]
            mov rax, 0
            call printf
    ; incrementing----------------------------------------------------------------- 
        mov rax, [number1]
        inc rax         ; increment rax with 1
        mov [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, inci
            mov rdx, [resulti]
            mov rax, 0
            call printf
    ; decrementing-----------------------------------------------------------------
        mov rax, [number1]
        dec rax         ; decrement rax with 1
            mov [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, deci
            mov rdx, [resulti]
            mov rax, 0
            call printf
    ; shift arithmetic left------------------------------------------------------
        mov rax, [number1]
        sal rax, 2          ; multiply rax by 4
        mov [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, sali
            mov rdx, [resulti]
            mov rax, 0
            call printf
    ; shift arithmetic right------------------------------------------------------
        mov rax, [number1]
        sar rax, 2          ; divide rax by 4
        mov [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, sari
            mov rdx, [resulti]
            mov rax, 0
            call    printf
    ; shift arithmetic right with sign extension ---------------------------------
        mov rax, [neg_num]
        sar rax, 2          ; divide rax by 4
        mov [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, sariex
            mov rdx, [resulti]
            mov rax, 0
            call    printf
    ; multiply-------------------------------------------------------------------
        mov     rax, [number1]
        imul    qword [number2]     ; multiply rax with number2
        mov     [resulti], rax
        ; displaying the result
            mov rdi, fmtint
            mov rsi, multi
            mov rdx, [resulti]
            mov rax, 0
            call    printf
    ; divide---------------------------------------------------------------------
        mov     rax, [number1]
        mov     rdx, 0          ; rdx needs to be 0 before idiv
        idiv    qword [number2]     ; divide rax by number2, modulo in rdx
        mov     [resulti], rax
        mov     [modulo], rdx   ; rdx to modulo
        ; displaying the result
            mov rdi, fmtint
            mov rsi, divi
            mov rdx, [resulti]
            mov rax, 0
            call    printf
            mov rdi, fmtint
            mov rsi, remi
            mov rdx, [modulo]
            mov rax, 0
            call    printf      
    mov rsp,rbp
    pop rbp
    ret
    
    结果如下:
    The numbers are 128 and 19
    The sum is 147
    The difference is 109
    Number 1 Incremented: 129
    Number 1 Decremented: 127
    Number 1 Shift left 2 (x4): 512
    Number 1 Shift right 2 (/4): 32
    Number 1 Shift right 2 (/4) with sign extension: -3
    The product is 2432
    The integer quotient is 6
    The modulo is 14
    
    

    add,sub

    可以用于有符号,也可以用于无符号,第二个操作数会加到第一个操作数上。对于有符号数,如果第一个操作数放不下结果,那么CF 标记会置位,对于无符号数,OF标记会置位,如果结果是0,ZF标记会置位,如果结果是负数,那么SF标记会置位。
    sub 和add类似,无需重复。

    sal,sar

    算术左移,算术右移,在移动的 时候会考虑符号位,比如对于负数,在做sar的时候,就会在最高位补1。这儿会见证一次数字的神奇:

    举一个例子, 比如一个8位的寄存器,需要表示 -4,那么结果如下:
    0000 0100
    =>
    1111 1011 
    + 1
    1111 1100 (-4 的补码,也就是计算机中真正的存储形式)
    
    算术右移1位
    1111 1110 (-2)
    也就是高位补一个符号位,就可以正确表示除以2的结果!
    

    imul, idiv

    mul用于无符号数乘法,imul用于有符号数乘法,rax用来存放第一个参数,乘法会用到rdx,rax2个寄存器,rdx用来存放高64位,rax存放低64位。
    对于除法,rax用来存放被除数,也用来存放结果的整数部分,rdx用来存放余数,因此使用idiv之前,需要将rdx清零。

    先看一个代码,反转字符串:

    ; stack.asm
    extern printf
    section .data                           
        string      db  "ABCDE",0
        stringLen   equ $ - string-1        ; stringlength without 10 and 0
        fmt1        db  "The original string: %s",10,0
        fmt2        db  "The reversed string: %s",10,0
    section .bss
    section .text                           
        global main                     
    main:
        push rbp
        mov rbp,rsp
    
    ; Print the original string
        mov     rdi, fmt1
        mov     rsi, string
        mov     rax, 0      
        call    printf      
    
    ;push the string char per char on the stack    
            xor rax, rax            
            mov rbx, string     ; address of string in rbx
            mov rcx, stringLen  ; length in rcx counter     
            mov r12, 0      ; use r12 as pointer
        pushLoop:
    ; push char per char on the stack
            mov al, byte [rbx+r12] ; move char into rax
            push rax            ;push rax on the stack  
            inc r12         ; increase char pointer with 1
            loop pushLoop       ; continue loop
    
    ;pop the string char per char from the stack
    ;this will reverse the original string 
            mov rbx, string     ; address of string in rbx
            mov rcx, stringLen  ; length in rcx counter 
            mov r12, 0      ; use r12 as pointer
        popLoop:
            pop rax         ; pop a char from the stack
            mov byte [rbx+r12], al ;move the popped char into string
            inc r12         ; increase char pointer with 1
            loop popLoop        ; continue loop
            mov byte [rbx+r12],0        ; terminate string with 0
    
    ; Print the reversed string
        mov     rdi, fmt2
        mov     rsi, string
        mov     rax, 0      
        call    printf                  
    
        mov rsp,rbp
        pop rbp
        ret
    
    结果:
    The original string: ABCDE
    The reversed string: EDCBA
    

    上面程序本质上就是按照栈的FILO规则,第一个loop先将字符串push到栈上,第二个loop再读出来,这样就把字符串反过来了。可以在第一个循环结束后打一个断点,显示rsp指向地址的内容

    > i registers rsp
     rsp            0x7fffffffe468      0x7fffffffe468
    > x /5cg 0x7fffffffe468
     0x7fffffffe468:    69 'E'  68 'D'
    0x7fffffffe478: 67 'C'  66 'B'
    0x7fffffffe488: 65 'A'
    

    浮点

    首先看下浮点在计算机中的表示:
    32位单精度
    1 个符号位,8个指数位,23个分数位
    64位双精度
    1个符号位,11个指数位,52个分数位

    对于指数位,还有一个偏移值,对于单精度,偏移值是127,双精度偏移值是1023。接下来看一个例子:

    1101010.01011 (106 + 1/4 + 1/16 + 1/32 = 106 + 11/32)
    
    =1.0101001011 x 2^6
    
    由于是正数,符号位是0,指数位是 6 + 127 = 133,那么表示结果就是:
    0 10000101 01010010110000000000000
    

    接下来看一点浮点的代码:

    ; fcalc.asm
    extern printf
    section .data                           
        number1 dq  9.0                 
        number2 dq  73.0
        fmt db  "The numbers are %f and %f",10,0                    
        fmtfloat    db  "%s %f",10,0 
        f_sum   db  "The float sum of %f and %f is %f",10,0
        f_dif   db  "The float difference of %f and %f is %f",10,0
        f_mul   db  "The float product of %f and %f is %f",10,0
        f_div   db  "The float division of %f by %f is %f",10,0
            f_sqrt  db  "The float squareroot of %f is %f",10,0
    section .bss
    section .text                           
        global main                 
    main:
        push    rbp     ; necessary because of printf with float
        mov     rbp,rsp
    ; print the numbers
        movsd xmm0, [number1]
        movsd xmm1, [number2]
        mov rdi,fmt
        mov rax,2   ; two floats
        call    printf
    ; sum   
        movsd xmm2, [number1]   ; double precision float into xmm
        addsd xmm2, [number2]   ; add into to xmm
            ; print the result
            movsd xmm0, [number1]
            movsd xmm1, [number2]
            mov rdi,f_sum
            mov rax,3   ; one float
            call    printf
    ; difference    
        movsd xmm2, [number1]   ; double precision float into xmm
        subsd xmm2, [number2]   ; subtract from xmm
            ; print the result
            movsd xmm0, [number1]
            movsd xmm1, [number2]
                    mov rdi,f_dif
            mov rax,3   ; three floats
            call    printf
    ; multiplication  
        movsd xmm2, [number1]   ; double precision float into xmm
        mulsd xmm2, [number2]   ; multiply with xmm 
            ; print the result
                    mov rdi,f_mul
                    movsd xmm0, [number1]
            movsd xmm1, [number2]
            mov rax,3   ; three floats
            call    printf
    ; division
        movsd xmm2, [number1]   ; double precision float into xmm
        divsd xmm2, [number2]   ; dividdatae xmm0 
            ; print the result
                    mov rdi,f_div
                    movsd xmm0, [number1]
            movsd xmm1, [number2]
            mov rax,1   ; one float
            call    printf
    ; squareroot
       sqrtsd xmm1, [number1]   ; squareroot double precision float in xmm
            ; print the result
                    mov rdi,f_sqrt
                    movsd xmm0, [number1]
            mov rax,2   ; one float
            call    printf
    ; exit
        mov rsp,rbp              
        pop rbp     ; undo the push at the beginning
        ret
    
            mov rdi,f_sum
            mov rax,3   ; one float
            call    printf
    ; difference    
        movsd xmm2, [number1]   ; double precision float into xmm
        subsd xmm2, [number2]   ; subtract from xmm
            ; print the result
            movsd xmm0, [number1]
            movsd xmm1, [number2]
                    mov rdi,f_dif
            mov rax,3   ; three floats
            call    printf
    ; multiplication  
        movsd xmm2, [number1]   ; double precision float into xmm
        mulsd xmm2, [number2]   ; multiply with xmm 
            ; print the result
                    mov rdi,f_mul
                    movsd xmm0, [number1]
            movsd xmm1, [number2]
            mov rax,3   ; three floats
            call    printf
    ; division
        movsd xmm2, [number1]   ; double precision float into xmm
        divsd xmm2, [number2]   ; divide xmm0 
            ; print the result
                    mov rdi,f_div
                    movsd xmm0, [number1]
            movsd xmm1, [number2]
            mov rax,1   ; one float
            call    printf
    ; squareroot
       sqrtsd xmm1, [number1]   ; squareroot double precision float in xmm
            ; print the result
                    mov rdi,f_sqrt
                    movsd xmm0, [number1]
            mov rax,2   ; one float
            call    printf
    ; exit
        mov rsp,rbp              
        pop rbp     ; undo the push at the beginning
        ret
    
    结果如下:
    The numbers are 9.000000 and 73.000000
    The float sum of 9.000000 and 73.000000 is 82.000000
    The float difference of 9.000000 and 73.000000 is -64.000000
    The float product of 9.000000 and 73.000000 is 657.000000
    The float division of 9.000000 by 73.000000 is 0.123288
    The float squareroot of 9.000000 is 3.000000
    
    

    对于浮点,参数传递用的就是xmm0,xmm1,等,这时候调用printf时指定的rax值就作用出来了,会告诉系统从哪里获取参数。
    movsd 用于双精度,movss用于单精度。

    相关文章

      网友评论

          本文标题:汇编学习(4), 整数,栈,浮点

          本文链接:https://www.haomeiwen.com/subject/vxyufdtx.html