彙編總結:無符號除法,有符號除法,取餘,無符號乘法,有符號乘法指令

本文分爲3個模塊。數組

  1. 示例---該指令的示例函數

  2. 解釋---爲指令很差理解的地方spa

  3. 練習---爲了更熟悉該指令code


1.1 有符號除法指令及取餘example:orm

    在c語言裏要完成 8 / 2的彙編指令以下:ip

    在c語言裏要完成 8 % 2的彙編指令以下:內存

.section .text
.global _start
_start:
    movl $8, %eax   #被除數是%edx:%eax 是這兩個寄存器拼起來的%eax存放低位%edx存儲高位
    movl %eax, %edx
    shrl $31, %edx  #根據符號位填充%edx寄存器
    movl $2, %ecx
    idivl %ecx      #%eax保存商 %edx保存餘數

    上面的也是4個字節除法及取餘運算示列,跟據所使用的類型不一樣(c語言有同類概念)還有以下變種:ci

  1個字節的除法及取餘運算示例以下:字符串

.section .text
.global _start
_start:
    movw $8, %ax #被除數是%ax寄存器
    movb $2, %cl 
    idivb %cl    #除數能夠是通用寄存器,這裏的demo是%cl。%al存放商。%ah存放餘數

  2個字節的除法及取餘運算示例以下:原型

.section .text
.global _start
_start:
    movw $8, %ax   #被除數是%dx:%ax 是這兩個寄存器拼起來的%ax存放低位%dx存儲高位
    movw %ax, %dx
    shrw $15, %dx
    movw $2, %cx
    idivw %cx      #%ax保存商 %dx保存餘數

  8個字節的除法及取餘運算示例以下:

.section .text
.global _start
_start:
    movq $8, %rax  #被除數是%rdx:%rax 是這兩個寄存器拼起來的%rax存放低位%rdx存儲高位
    movq %rax, %rdx
    shrq $63, %rdx
    movq $5, %rcx
    idivq %rcx     #%rax保存商 %rdx保存餘數


1.2 下面的除數指令裏爲何用右移指令操做%edx寄存器?

.section .text
.global _start
_start:
    movl $8, %eax   #1
    movl %eax, %edx #2
    shrl $31, %edx  #3
    movl $2, %ecx   #4
    idivl %ecx      #5

上面的例子第2+3行其實根據被除數%eax裏的符號將%edx設置爲全零或者全一。這樣一來,兩個寄存器就拼成了64位的寄存器(%edx:%eax--被除數)


1.3 無符號除法指令用法

    無符號除法指令和有符號除法指令差很少,只要把idiv換成div就行。


2.1 有符號乘法指令example:

    在c語言裏要完成 4 * 3的彙編指令以下:

    根據imul的操做數的個數不一樣可分爲兩種,一種是兩個操做數。這時執行imull指令,結果存在第二個操做數裏。另外一種是一個操做數。這時候的結果保存到%edx:%eax兩個寄存器。

    2.1.1 雙操做數imul指令example:

            c語言要完成a = 3; a *= 4;可用以下指令完成同等效果

.section .text
.global _start
_start:
    movw $3, %cx
    imulw $4, %cx

    movl  $3, %ecx
    imull $4, %ecx

    movq  $3, %rcx
    imulq $4, %rcx

  注意:雙操做數imul指令沒有imulb版本的

    2.1.2 單操做數imul示例以下:

    1個字節的乘法運算示例以下:

.section .text
.global _start
_start:
    movb $0x7f, %al #被乘數需放至%al寄存器中
    movb $4, %cl    #乘數可爲通用寄存器或者內存地址
    imulb %cl       #ah存儲高位 al存儲低位,可用ax引用結果

    2個字節的乘法運算示例以下:

.section .text
.global _start
_start:
    movw $0x7fff, %ax #被乘數需放至%ax寄存器中
    movw $4, %cx      #乘數可爲通用寄存器或者內存地址
    imulw %cx         #dx存儲高位 ax存儲低位。結果保存在dx:ax兩個寄存器中

    4個字節的乘法運算示例以下:

.section .text
.global _start
_start:
    movl $0x7fffffff, %eax #被乘數需放至%eax寄存器中
    movl $4, %ecx          #乘數可爲通用寄存器或者內存地址
    imull %ecx             #edx存儲高位 eax存儲低位 結果保存在edx:eax兩個寄存器中

    8個字節的乘法運算示例以下:

.section .text
.global _start
_start:
    movq $0x7fffffffffffffff, %rax #被乘數需放至%rax寄存器中
    movq $4, %rcx                  #乘數可爲通用寄存器或者內存地址
    imulq %rcx                     #rdx存儲高位 rax存儲低位 結果保存在rdx:rax兩個寄存器中

2.2 無符號乘法指令用法

    無符號乘法和有符號乘法指令差很少,只要把imul換成mul就行。

3.1 編寫函數,實現字符串轉數字。函數原型以下:

int str2int(const char *str, int base);

   base範圍爲2-36,可把str裏的數組解釋爲2-36進制的數

   須要提供必定的進制猜想能力。當base爲0時打開進制猜想能力。str以0b或0B開頭,默認爲2進制。以0開頭默認爲8進制。以0x或0X開頭,默認爲16進制,其他默認爲10進制。

   str以'-'開頭。base 爲10時,認爲是10進制的負數。其他進制?

   彙編code:

.equ SIGN_SIZE, 4
.equ SIGN, -4

#str2int(const char *str, int base)
.section .text
.global str2int
.type str2int, @function
str2int:
    pushq %rbp
    movq %rsp, %rbp

    subq $SIGN_SIZE, %rsp
    movl $1, SIGN(%rbp)

    #初始化返回值
    movl $0, %eax
    #判斷base的值
    cmpl $0, %esi
    je str2int_init_base
    cmpl $2, %esi
    jl str2int_exit
    cmpl $36, %esi
    jg str2int_exit
    jmp str2int_skip_space

str2int_init_base:
    movl $10, %r9d

str2int_skip_space:

    movb (%rdi), %r8b
    cmpb $0, %r8b
    je str2int_exit

    cmpb $' ', %r8b
    je str2int_skip_space_next
    cmpb $'\r', %r8b
    je str2int_skip_space_next
    cmpb $'\n', %r8b
    je str2int_skip_space_next
    cmpb $'\t', %r8b
    je str2int_skip_space_next

    jmp str2int_sign
str2int_skip_space_next:
    incq %rdi
    jmp str2int_skip_space

str2int_sign:
    cmpb $'-', %r8b
    jne str2int_guess_hex
    incq %rdi
    movl $-1, SIGN(%rbp)

str2int_guess_hex:
    cmpb $'0', %r8b
    jne str2int_check_base
    movl $8, %r9d
    incq %rdi
    movb (%rdi), %r8b
    cmpb $0, %r8b
    je str2int_exit

    cmpb $'b', %r8b
    je str2int_guess_hex_2
    cmpb $'B', %r8b
    je str2int_guess_hex_2
    cmpb $'x', %r8b
    je str2int_guess_hex_16
    cmpb $'X', %r8b
    je str2int_guess_hex_16
    jmp str2int_check_base

str2int_guess_hex_2:
    movl $2, %r9d
    incq %rdi
    jmp str2int_check_base

str2int_guess_hex_16:
    movl $16, %r9d
    incq %rdi

str2int_check_base:
    cmpl $0, %esi
    jne str2int_cal
    movl %r9d, %esi


str2int_cal:
    xorl %r9d, %r9d
    movb (%rdi), %r9b
    cmpb $0, %r9b
    je str2int_exit

    orb $0x20, %r9b

    #if (c >= 'a' && c <= 'z')
    cmpb $'a', %r9b
    jl str2int_cal_10
    cmpb $'z', %r9b
    jg str2int_exit
    subb $'a', %r9b
    addb $10, %r9b
    jmp str2int_cal_next

str2int_cal_10:
    #if (c >= '0' && c <= '9')
    cmpb $'0', %r9b
    jl str2int_exit
    cmpb $'9', %r9b
    jg str2int_exit
    subb $'0', %r9b

str2int_cal_next:
    imull %esi, %eax
    addl %r9d, %eax
    incq %rdi
    jmp str2int_cal

str2int_exit:
    imull SIGN(%rbp), %eax
    movq %rbp, %rsp
    popq %rbp
    ret

3.2  編寫函數,實現數字轉字符串,函數原型以下:

char *int2str(int val, char *str, int base);

  base範圍爲2-36,可把val裏的數字解釋爲2-36進制的字符串,並存入str中。

  val是輸入。str是輸出。

  彙編code:

相關文章
相關標籤/搜索