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。

现在来具体解释代码:

.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  无条件跳转

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

原文地址:https://www.cnblogs.com/guochaoxxl/p/10468711.html

时间: 2024-10-18 15:21:59

Linux汇编教程03:大小比较操作的相关文章

Linux汇编教程01: 基本知识

在我们开始学习Linux汇编之前,需要简单的了解一下计算机的体系结构.我们不需要特别深入的了解,理解了一些基本概念对与我们理解程序会很有帮助.现在计算机的结构体系都是采用冯诺依曼体系结构的基础上发展过来的.而冯诺依曼的体系有两个主要组成部分:CPU和内存.而我们的汇编语言和这两个部分十分密切. 1.1 内存结构 内存的结构就像一排连续的房子,或者是一种矩阵.每个空间的大小是固定的,且每一个存储单元都有自己的地址或者编号.房子的地址是门牌号,而内存的每个单元都有自己的地址. 计算机的内存有数以万计

Linux汇编教程02:编写第一个汇编程序

学习一门语言,最好的方式就是在运用中学习,那么在这一章节中,我们开始编写我们的第一个汇编程序.当然作为第一个程序,其实十分的简单,但可以给大家一个基本的轮廓,了解汇编大概是这样的. 我们这个程序实际上没什么作用,只是简单的推出而已.下面就是程序的范例 # 目的: 退出程序并向Linux内核返回一个状态码 # 输入: 无 # 输出: 返回一个状态码.在程序运行结束后可以通过 echo $? 来读取状态码 # 变量: %eax保存系统调用号 %ebx保存返回状态 .section .data .se

linux基础教程---用户和组操作

用户和组操作 linux 操作系统之所以稳定.安全,与它的"用户和组"的管理是分不开的,我先来看下,现实生活中项目组中的简单管理: 给用户设置操作文件权限的工作非常繁琐,不要落实. linux 创建用户的时候,会考虑给用户创建一个组别 系统增减文件的时候,也会把一个文件划分为一个组别里边 这样系统管理员每天只需要关心用户是那个组别的即可,就可以知道该用户具体有什么文件 操作权限. linux用的用户和组的操作: 1.组操作(/etc/group) ① 增加组信息 groupadd(是连

Linux汇编教程04:寻址方式

这一节,我们主要来讨论寻址方式,这一点十分重要. 我们上一节有稍微提了一下,内存地址引用的通用格式: 地址或偏移(%基址寄存器, %索引寄存器, 比例因子 ) 结果地址 = 地址或偏移 + %基址寄存器 + 比例因子 + %索引寄存器 地址或偏移和比例因子必须是常数,剩下的那两个必须是寄存器,在缺省的情况下,都用0来代替. 立即寻址方式 直接将值加载到目地位置中 movl $221, %eax</p> 1 直接寻址方式 通过使用地址或偏移来实现 movl ADDRESS, %eax</p

Unix/Linux环境C编程入门教程(40) 初识文件操作

?? 1.函数介绍 close(关闭文件) 相关函数 open,fcntl,shutdown,unlink,fclose 表头文件 #include<unistd.h> 定义函数 int close(int fd); 函数说明 当使用完文件后若已不再需要则可使用close()关闭该文件,二close()会让数据写回磁盘,并释放该文件所占用的资源.参数fd为先前由open()或creat()所返回的文件描述词. 返回值 若文件顺利关闭则返回0,发生错误时返回-1. 错误代码 EBADF 参数fd

Linux makefile 教程 很具体,且易懂

近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了下面这篇文章.通俗易懂.然后把它贴出来,方便学习. 后记,看完发现这篇文章和<Linux环境下的C编程指南>的makefile一章所讲述的惊人的类似,仅仅是这篇文章从一个实例切入,在有些地方比較好理解.能让人看懂就是好文章. 跟我一起写 Makefile陈皓 (CSDN)概述--什么是makefile?也许非常多Winodws的程序

很详细、很移动的Linux makefile教程:介绍,总述,书写规则,书写命令,使用变量,使用条件推断,使用函数,Make 的运行,隐含规则 使用make更新函数库文件 后序

很详细.很移动的Linux makefile 教程 内容如下: Makefile 介绍 Makefile 总述 书写规则 书写命令 使用变量 使用条件推断 使用函数 make 的运行 隐含规则 使用make更新函数库文件 后序 近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到makefile就越看越迷糊,可能是我的理解能不行. 于是google到了以下这篇文章.通俗易懂.然后把它贴出来,方便学习. 后记,看完发现这篇文章和<Linux环境下的C编程指南>

Linux makefile教程之隐含规则九[转]

隐含规则 ———— 在 我们使用Makefile时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译C/C++的源程序为中间目标文件(Unix下是[.o] 文件,Windows下是[.obj]文件).本章讲述的就是一些在Makefile中的“隐含的”,早先约定了的,不需要我们再写出来的规则. “隐含规则”也就是一种惯例,make会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile中没有书写这样的规则.例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来,ma

Linux培训教程 linux系统下分割大文件的方法

在linux中分割大文件,比如一个5gb日志文件,需要把它分成多个小文件,分割后以利于普通的文本编辑器读取. 有时,需要传输20gb的大文件,Linux培训 教程件到另一台服务器,也需要把它分割成多个文件,这样便于传输数据. 以下通过五个不同的例子,来讲解Linux下分割大文件的方法,供大家参考. 例1.以每个文件1000行分割 split命令分割文件成每个文件1000行,并且文件名依次为 [前缀]aa,[前缀]ab, [前缀]ac等,默认的前缀是X,每个文件的行数为1000行. 命令: 复制代