linux平台学x86汇编(十):整数运算

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】

这一节介绍如何在编语言中上使用整数运算,包括加法、减法、乘法和除法。

  • 加法指令

add指令用于把两个整数想加。格式如下:

add src, dest

其中src可以是立即数值、内存地址、寄存器。dest可以是寄存器或内存中的值,不能同时使用内存地址作为源和目标。结果存放在dest中。和其他GNU汇编指令一样,需要在add结尾添加b、w、l来指定操作数长度。如果没有使用整个寄存器,就要确保零填充目标寄存器,使得寄存器高位没有内容。add指令可以对所有带符号的整数执行加法操作。

在执行整数想加时,应该注意EFLAGS寄存器,当在无符号数做加法操作造成进位(结果大于允许的最大值)情况时,进位标志会被置为1。在有符号整数出现溢出情况时(结果小于允许最小负值或大于允许最大正值),溢出标志会被设置为1。下面示例演示无符号整数加法进位的情况:

<span style="font-family:Microsoft YaHei;">#add1.s
.section .text
.globl _start
_start:
    nop
    movl $0, %ebx
    movb $240, %bl
     movb $20, %al
#    movb $2, %al
    addb %al, %bl
    jc over
    movl $1, %eax
    int $0x80

over:
    movl $1, %eax
    movl $0, %ebx
    int $0x80</span>

如果加法操作造成进位,则把进位标志设置为1,程序返回0,否则返回加法的结果。我们分别修改上述代码使其造成进位和不进位(取消代码注释行且注释上一行代码),分别make、执行结果如下:

<span style="font-family:Microsoft YaHei;">$ make
as -o add1.o add1.s --gstabs
ld -o add add1.o
$ ./add
$ echo $?
0

$ vim add1.s//修改代码,使其不进位
$ make clean;make
rm -f add1.o add *~
as -o add1.o add1.s --gstabs
ld -o add add1.o
$ ./add
$ echo $?
242    //不进位时程序返回加法结果
</span>

在执行无符号整数加法时,总应该检查进位标志,如果知道输入值界限,就可以不必检查进位标志。

在处理有符号整数,不需要判断进位标志,而是需要注意溢出标志,当结果溢出正值或负值界限时,这个标志会被设置为1。

使用adc指令可以处理大于双字数据长度的加法。

  • 减法指令

减法操作和加法操作类似,减法指令是sub,格式类似加法指令:

sub src, dest

减法指令也需要在sub末尾添加b、w、l。和add指令类似,sub指令也会修改EFLAGS寄存器的位。

使用进位标志确定无符号整数减法产生负数结果的情况。有符号数的减法需要依靠溢出标志来判断数据长度界限的情况。

sbb指令类似adc指令,可以使用进位情况帮助执行大的无符号整数的减法操作。

  • 递增递减指令

inc指令和dec指令可分别对无符号整数值进行递增和递减操作。这两个指令不会影响进位标志。指令格式如下:

dec dest

inc dest

dest可以是8位、16位、32位寄存器和内存中的值。

  • 乘法指令

mul指令用于两个无符号整数相乘,格式如下:

mul src

src可以是8、16、32位寄存器或内存值。使用GNU汇编器时,命令助记符结尾加上正确长度字符。该指令的目标操作数是隐含的。根据元操作数的值长度,乘法操作使用另一个操作数必须放在al、ax、eax寄存器中。由于乘法可能产生很大的值,所以mul指令目标位置必须是元操作数的两倍长度。下表是无符号整数乘法的需求:

源操作数长度(位)
目标操作数

目标位置

8

AL

AX

16

AX

DX:AX

32

EAX

EDX:EAX

imul命令可以进行有符号整数的乘法。 imul指令有三种指令格式:

imul src    #这种指令格式和mul的使用一样

imul src,dest    #允许指定eax之外的目标操作数

imul multipler, src, dest    #multipler是立即值

  • 除法指令

无符号除法指令:div divisor

有符号除法指令:idiv divisor

divisor是隐含被除数要除以的值。

  • 移位指令

在平时编写高级语言时,都知道乘法和除法是很消耗处理器时间的,有些时候会使用移位来代替乘除法。在汇编语言中一样,也可以使用移位,移位指令提供基于2的乘方的乘法和除法。把二进制数字左移1就是乘以2,左移2位就是乘以4,移位操作比执行二进制乘法操作要快得多。

向左移位命令:sal(算数左移)和shl(逻辑左移),这两个指令执行相同操作。有3种格式:

sal dest    #左移一位,等同于乘以2

sal %cl, dest    #左移cl寄存器中的数

sal shifter, dest    #左移shifter值指定的数

左移指令可以对无符号和有符号整数执行向左移位指令,空位补0,超出数据长度的位首先存放在进位标志中,在下一次移位操作中被丢弃。

向右移位指令:shr和sar

shr对无符号整数进行移位操作,右移位产生的空位用0填充。

sar指令根据整数符号位来判断移位产生的空位的填充数,负数空位填1,正数空位填0。

右移位移出的数据元素首先被移动到进位标志,然后再移出去,这里和左移一样。

  • 逻辑操作指令

布尔逻辑操作:add、not、or、xor

and、or、xor指令格式一样:

and src, dest

not指令使用单一操作数。

清空寄存器最高效的方式就是使用xor指令对寄存器和他本身进行异或操作。

位测试指令:test src, dest

test指令最常见的用途是检查EFLAGS寄存器中的标志。

时间: 2024-11-07 10:19:22

linux平台学x86汇编(十):整数运算的相关文章

linux平台学x86汇编(十九):C语言中调用汇编函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 除了内联汇编以外,还有一种途径可以把汇编代码整合到C/C++语言中,C/C++语言可以直接调用汇编函数,把输入值传递给函数,然后从函数获得输出值. 如果希望汇编语言函数和C/C++程序一起工作,就必须显示地遵守C样式的函数格式,也就是说所有输入变量都必须从堆栈读取,并且大多数输入值都返回到EAX嫁寄存器中.在汇编函数代码中,C样式函数对于可以修改哪些寄存器和函数必须保留哪些寄

linux平台学x86汇编(二十):汇编库的使用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 汇编语言和C一样,可以通过使用库来简化阻止大量函数的目标文件的问题.GNU C编译器可以不在命令行中独立地包含每个独立地函数目标文件,它允许吧所有目标文件组合在单一存档文件中.在编译C程序时,要做的工作就是包含单一的目标库文件,在编译时,编译器可以从库文件中挑出所需的正确目标文件.在库文件中,经常按照应用程序类型或者函数类型把函数分组在一起,单一应用程序项目可以使用多个库文件

linux平台学x86汇编(十六):在汇编语言中调用C库函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 其实在汇编语言中也是可以使用C库函数的,这一节我们来看一下如何在汇编语言中调用C库函数以使得我们的程序看上去很方便地和用户交互. C库包括C程序通用的喝多函数,如printf和exit等,下面我们紧接着上一节的知识来实现一个两整数想加的计算并输出计算结果的程序. # libc.s .section .data output: .asciz "The result is %d.

linux平台学x86汇编(十八):内联汇编

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 使用汇编语言笔编程最常见的方式是在高级语言(C和C++)程序内编写汇编函数,这种吧汇编语言直接写到C和C++语言程序内的技术称为内联汇编. GNU的C编译器使用asm关键字指出使用汇编语言编写的源代码段落.asm段的基本格式如下: asm("as code"): 括号中的汇编指令必须在括号,指令超过一条的话必须使用新的行分隔汇编语言代码每一行,因为编译器逐字地取得a

linux平台学x86汇编(十四):函数的使用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 和高级语言一样,汇编语言在多个项目之间可能会编写相同的过程和处理,如果使用函数的话就可以不必每次需要时都重复编写实用程序代码,从而在需要它的时候调用它. 函数包含完成特定功能所需的代码,数据从主程序传递给函数,然后结果返回给主程序.调用函数时,程序执行路径被改变,切换到函数代码的第一条指令.处理器从这个位置开始执行指令,直到函数表明它可以把控制返回到主程序中的原始位置. 在汇

linux平台学x86汇编(十五):使用命令行参数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在高级语言中,程序在命令行上启动时常常带一个或多个参数,在汇编语言中也可以实现这一特性.在实现这一特性之前,我们先了解一下linux如何从命令行执行程序. 每一个应用程序开始执行时,系统都会为该程序分配一块内存区域,并且每个程序都分配相同的虚拟内存地址.虚拟内存地址由操作系统映射到物理内存地址.在Linux中,程序的虚拟内存地址是从0x80480000开始,到地址0xbfff

linux平台学x86汇编(十二):字符串的存储与加载

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 字符串的存储与加载是指,将字符串的值加载到寄存器和将其传回内存位置中.其使用指令lods指令和stos指令. lods指令用于把内存中的字符串值传送到eax寄存器中,该指令有三种不同格式:lodsb(1字节).lodsw(2字节).lodsl(4字节).lods指令使用esi寄存器作为隐含的源操作数.esi寄存器必须包含要加载的字符串所在的内存地址. 在使用lods指令把字符

linux平台学x86汇编(三):相关开发工具

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 类似于其它高级语言,编写汇编语言,必须有一个开发环境,那么也就需要适当的工具了.搭建汇编语言至少应该有下面这些工具:汇编器.链接器.调试器.下下面看看在汇编语言开发环境中如何使用它们. 汇编器 汇编器用于把汇编语言源代码转换为处理器指令码.选择的汇编器必须能够生成所在系统的处理器系列指令码.汇编语言源代码程序有3个部分:操作码助记符.数据段.命令.但是每种汇编器对于每个部分使

linux平台学x86汇编(十七):在汇编中使用linux系统调用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在前面章节我们已经看到,启动系统调用需要使用INT指令.linux系统调用位于中断0x80,执行INT指令时,所有操作转移到内核中的系统调用处理程序,完成后执行转移到INT指令之后的下一条指令. linux的系统调用在如下文件(32位系统)可以查看: $ cat /usr/include/asm/unistd_32.h #ifndef _ASM_X86_UNISTD_32_H