本文分爲3個模塊。數組
示例---該指令的示例函數
解釋---爲指令很差理解的地方spa
練習---爲了更熟悉該指令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: