AT&T 汇编-4: 简单四则运算

加法

用于加法的是 add 系列指令。

# add.s

.section .rodata
output:
   .asciz "the result is: %d.\n"

.section .text
.globl main
main:
   movl  $7,   %eax
   addl  $5,   %eax
   pushl %eax
   pushl $output
   call  printf
   addl  $8,   %esp

   pushl $0
   call  exit

add 系列指令的格式是:

add source, destination

计算 destination + source 的值,并把结果保存在 destination 中。与 mov 系列指令类似,在 add 后面加上不同的字母表示操作数的宽度,例如 addl 表示两个 32 位的数相加,而 addw 则表示两个 16 位的数相加,等等。

第 10 行把 eax 的值设为 5;第 11 行计算 7+5 的值,并把最后结果 12 保存在 eax 中,第 12-14 行显示计算结果。

减法

用于减法的是 sub 系列指令。

# sub.s

.section .rodata
output:
   .asciz "the result is: %d.\n"

.section .text
.globl main
main:
   movl  $7,   %eax
   subl  $5,   %eax
   pushl %eax
   pushl $output
   call  printf
   addl  $8,   %esp

   pushl $0
   call  exit

sub 系列指令的一般格式是:

sub source, destination

计算 destination – source 的值,并且把结果保存在 destination 中。类似的,通过不同的后缀区分不同宽度的数据,如 l 表示两个 32 位的值相减,w 表示两个 16 位的值相减等。

乘法

乘法指令比较特殊,无符号整数使用 mul,有符号整数使用 imul。

# mul.s

.section .rodata
output:
   .asciz   "The result is: %d.\n"

.section .text
.globl main
main:
   movw  $5,   %ax
   movw  $7,   %bx
   mulw  %bx

   pushw %dx
   pushw %ax
   pushl $output
   call  printf
   addl  $8,   %esp

   pushl $0
   call  exit

mul 系列指令的一般格式是:

mul source

其中 source 只能是寄存器或者内存中的位置,不能是立即数。第 10-12 行:

movw  $5,   %ax
movw  $7,   %bx
mulw  %bx

这里只有一个操作数,另外一个隐含的操作数在 ax 寄存器中(使用 mulw,即两个 16 位的整数相乘)。根据所使用的 mul 指令的不同将使用不同的 ax 的寄存器的形式,例如 mull 则会使用 eax 的值,而 mulb 则使用 al 的值。

因为乘法很容易产生两倍长度于操作数的结果(例如两个 2 位数相乘的结果通常是 4 位数,两个 4 位数相乘的结果常常是 8 位数等),所以用来保存结果的位置宽度通常是操作数的两倍。而为了向前兼容老式的处理器,intel 使用两个不同的寄存器来保存乘法结果,如两个 16 位操作数相乘,结果保存在 dx:ax 寄存器对中,dx 保存结果的高 2 个字节,ax 保存结果的低 2 个字节。如果 mul 的操作数是 32 位则使用 edx:eax 寄存器对。

这三句把 ax 的值设为 5(隐含操作数),另一个乘数 bx 设为 7,结果保存在 dx:ax 中。

pushw %dx
pushw %ax
pushl $output
call  printf

因为栈中存放内容的顺序和内存中的一致,所以先把高字节的 dx 先入栈,然后是 ax,接着是字符串地址,最后输出结果。

imul 指令用于有符号整数乘法的计算。这个指令有点复杂,有三种不同的形式。

第一种形式和 mul 指令一样:

imul source

除了 source 是有符号整数外其它行为与 mul 指令相似。

第二种形式是

imul source, destination

计算 source * destination 的值,结果保存在 destination 中而不是 dx:ax 寄存器对。其中 source 可以是 16 位或 32 位的值,destination 必须是 16 位或 32 位的通用寄存器。使用这种形式要注意结果不要超过 destination 寄存器的范围。

第三种形式是

imul multiplier, source, destination

其中 multiplier 是一个立即数,source 只能是寄存器或内存中的值,destination 是通用寄存器。这条命令计算 multiplier 和 source 的积,结果保存在 destination 中。

# imul.s

.section .rodata
output:
   .asciz   "The result is: %d.\n"

.section .text
.globl main
main:
   movw  $5,   %ax
   movw  $-7,  %bx
   imulw %bx

   pushw %dx
   pushw %ax
   pushl $output
   call  printf
   addl  $8,   %esp

   movl  $-12, %ecx
   imull $5,   %ecx

   pushl %ecx
   pushl $output
   call  printf
   addl  $8,   %esp

   movl  $6,   %ebx
   imull $5,   %ebx, %ecx

   pushl %ecx
   pushl $output
   call  printf
   addl  $8,   %esp

   pushl $0
   call  exit

除法

和乘法相似,除法也分有符号除法和无符号除法,对应的指令分别是 div 和 idiv,两者都只有一种格式

div divisor

同 mul 相似,divisor 不能是立即数。被除数保存在 ax(16 位),dx:ax(32 位)或者 edx:eax(64 位)中,而除数的最大长度只能是被除数的一半,即对于 64 位的被除数,除数只能是 32 位;对于 32 位的被除数,除数最大只能是 16 位。

结果分为两部分:商和余数。如果被除数是 16 位(存放在 ax 中),则商放在 al,余数放在 ah;如果被除数是 32 位(放在 dx:ax 中),结果商放在 ax,余数在 dx;如果被除数是 64 位(edx:eax),商放在 eax,余数放在 edx。

# div.s

.section .rodata
output:
   .asciz   "The quitient is: %d and the remainer is %d.\n"
num:
   .int  -72

.section .text
.globl main
main:
   movw  $0,   %dx
   movw  $72,  %ax
   movw  $5,   %cx
   divw  %cx

   pushw $0
   pushw %dx
   pushw $0
   pushw %ax
   pushl $output
   call  printf
   addl  $8,   %esp

   pushl $0
   call  exit
发表于 2011年5月10日
本文目前尚无任何评论.

发表评论

XHTML: 您可以使用这些标签: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>