• Linux汇编教程03:大小比较操作


    我们在上一讲中,简单了解了汇编程序大概的样子。接下来我们来了解一下,汇编程序的大小比较操作。所以我们以编写寻找一堆数中的最大值作为学习的载体。

    在编写程序之前,先要分析我们的目的,在得出解决方案。

    目的:在一堆数中找到最大的数

    思路:要实现这个目的,首先,我们一定要对数据进行索引,每一次比较,两个数应该分别占用一个寄存器,得到最大值,所以,我们有一个寄存器一定是存放最大值的。一开始没有最大值,我们不妨设第一个数为最大值,后面一次索引大小比较。得出最大值。索引中还会用到循环结构。

    解决方案——代码

    在代码之前,先说一下用到的寄存器

    %eax – 用来存储当前数据

    %ebx – 用来存储最大值

    %edi – 存储索引

    
    .section .data
    
    data_items:
    .long 3, 14, 15, 9, 26, 53, 58, 97, 93, 2, 38, 4, 36, 0
    
    .section .text
    .globl _start
    _start:
    movl $0, %edi
    movl data_items( , %edi, 4), %eax
    movl %eax, %ebx
    
    start_loop:
    cmpl $0, %eax
    je loop_exit
    incl %edi
    movl data_items( , %edi, 4 ), %eax
    cmpl %ebx, %eax
    jle start_loop
    movl %eax, %ebx
    jmp start_loop
    
    loop_exit:
    movl $1, %eax
    int $0x80
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    把上面的代码保存为maximum.s,在编译链接,运行。正常情况下最大应该是97。

    Selection_002

    现在来具体解释代码:

    .section .data 为数据段,前面一节我们提到过。
    • 1
    data_items
    .long 3, 14, 15, 9, 26, 53, 58, 97, 93, 2, 38, 4, 36, 0
    • 1
    • 2

    这是数据段里面的内容,data_items 是标签,代表一个地址。在这个位置后面是一堆数字,这些数字的类型是long(长整形,4字节)。而data_items标签代表的地址就是这段数字的开头,在这个例子中,data_items对应的地址下的内容为long类型的数字3。

    这个数据项的末尾的0是人为添加,在这里来作为是否到达末尾的判断依据。

    movl $0, %edi
    movl data_items( , %edi, 4), %eax
    movl %eax, %ebx
    • 1
    • 2
    • 3

    这里是为循环做好准备,我们要把索引寄存器%edi的值变为0,应为我们要从数据的第一个数字开始获取数据。

    movl data_items( , %edi, 4), %eax 这句是把数据的第一个数据载入到%eax里面。
    这里的源操作数是data_items( , %edi, 4),目的操作数是%eax,而源操作数比较复杂,这里涉及到内存里的寻址方式。这一点也是汇编中十分重要的内容。我们下一讲具体来讲解。这里想讲最基本的。在内存中地址引用的通用格式是下面这样:

    地址或偏移(%基址寄存器,%索引寄存器,比例因子)

    实际地址 = 地址或偏移 + %基址寄存器 + 比例因子 * %索引寄存器

    这里用到的是索引寻址方式,是利用地址或偏移、%索引寄存器、比例因子来实现。所以出现了上面代码的表现形式。

    在这个例子中data_items为起始地址,后面的各项一一对应,这里的比例因子是4是因为long类型为4字节。

    movl %eax, %ebx 把第一个数载入到%ebx中作为最大值。

    后面我进入了循环,我们用start_loop来标记循环的入口(位置)。

    start_loop:
    cmpl $0, %eax
    je loop_exit
    incl %edi
    movl data_items( , %edi, 4 ), %eax
    cmpl %ebx, %eax
    jle start_loop
    movl %eax, %ebx
    jmp start_loop
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    一个循环第一考虑的问题就是,循环结束的条件,不然写出死循环就麻烦了。cmpl —— compare long,比较long类型的大小,结果会记录在%eflags(状态寄存器)中je = jump equal 如果值相等,就跳转。

    cmpl $0, %eax
    je loop_exit
    • 1
    • 2

    表示%eax的值为0就跳转到loop_exit的位置,执行这个位置后面的操作。如果不相等就不跳转,而是继续执行后面紧更的操作。

    incl %edi
    movl data_items( , %edi, 4 ), %eax
    • 1
    • 2

    incl —— increase long,所以 incl %edi 是让%edi的值加1,类似于C语言的 i++ 的效果

    所以这两句很在一起的效果就是索引数据,要检测的数着存放在%eax中。

    cmpl %ebx, %eax
    jle start_loop
    movl %eax, %ebx
    jmp start_loop
    • 1
    • 2
    • 3
    • 4

    jle —— jump less equal如果小于等于,跳转

    jmp —— 无条件跳转

    所以这里就是,如果%eax里的大值比%ebx中的目前最大值小或相等(注意:比较的方式,到底是那个比那个小),这跳转到start_loop位置,执行这个位置后面的代码,也就是跳过后面操作,回到循环的开头。如果不成立,执行下面步骤,就是把%eax里面的值载入到%ebx作为新的最大值。跳会循环开始处。

    movl $1, %eax
    int $0x80
    • 1
    • 2

    对于这个程序,这么解释,实在是太累了,最为教程的前几期,会讲的详细,每一步都讲,到后面基本之讲重点。

    最后,最好在回顾一遍,在写一遍,你可以对其进行改进,这一次写,可不是对着代码敲下来,而是自己写。

    附加内容:

    数据类型

    • .byte —— 字节类型,只占用一个字节
    • .int —— 整型,占用2个字节
    • .long —— 长整型,占用4个字节
    • .ascii —— ascii码类型字符,一个字符占1个字节

    大小判断

    • je = jump equal 如果值相等,就跳转。
    • jg = jump greater 如果第二个值大于第一个值,跳转
    • jge = jump greater equal 如果第二个值大于等于第一个值,跳转
    • jl = jump less equal如果第二个值小于第一个值,跳转
    • jle = jump less equal如果第二个值小于等于第一个值,跳转
    • jmp  无条件跳转

    注意:这里的等于只是方便大家理解命令便于理解记忆。

  • 相关阅读:
    XML属性
    4.9Java游戏项目练习
    关于JVM结构的学习
    HelloWorld之Struts2
    进程调度
    JVM垃圾回收总结
    学会阅读Java字节码
    关于产品需求文档的各种D
    刘强东学习亚马逊:控制供应链 技术是最大障碍
    JVM内存溢出的方式
  • 原文地址:https://www.cnblogs.com/guochaoxxl/p/10468711.html
Copyright © 2020-2023  润新知