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

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

作者头像
一只小虾米
发布2022-12-07 15:49:46
2490
发布2022-12-07 15:49:46
举报
文章被收录于专栏:Android点滴分享Android点滴分享

本篇介绍

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

整数运算

代码如下:

代码语言:javascript
复制
; 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。这儿会见证一次数字的神奇:

代码语言:javascript
复制
举一个例子, 比如一个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清零。

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

代码语言:javascript
复制
; 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指向地址的内容

代码语言:javascript
复制
> 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。接下来看一个例子:

代码语言:javascript
复制
1101010.01011 (106 + 1/4 + 1/16 + 1/32 = 106 + 11/32)

=1.0101001011 x 2^6

由于是正数,符号位是0,指数位是 6 + 127 = 133,那么表示结果就是:
0 10000101 01010010110000000000000

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

代码语言:javascript
复制
; 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用于单精度。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本篇介绍
  • 整数运算
    • add,sub
      • sal,sar
        • imul, idiv
        • 浮点
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档