汇编语言学习篇5——GAS汇编实践篇(3)- maximum.s-数据类型、跳跃指令、寻址模式

说明
  本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
  QQ 群 号:513683159 【相互学习】
内容来源
  《ProgrammingGroundUp-1-0-lettersize》
  《Computer Systems A Programmer’s Perspective》

上下文链接

  上篇:汇编语言学习篇5——GAS汇编实践篇(2)- helloworld.s
  下篇:汇编语言学习篇5——GAS汇编实践篇(4)- power.s

第三个程序:maximum.s

  功能:找到一个数字列表的最大值
  
  寄存器作用
    %edi将保留列表中的当前位置 。 ==》 索引变量
    %ebx将保存列表中当前的最高值。 ==》 保存最大值变量
    %eax将保存当前正在检查的元素。 ==》 保存正检测变量
  
  Data_items—保存数字列表数据。0用于终止数据
  思路:
  1. 检查当前列表元素(%eax),看看它是否是零(终止元素)。
  2. 如果是零,退出。
  3. 增加当前位置(%edi)。
  4. 将列表中的下一个值加载到当前值寄存器(%eax)。这里我们可能使用什么寻址模式?为什么?
  5. 比较当前值(%eax)和当前最大值(%ebx)。
  6. 如果当前值大于当前最大值,则将当前最大值替换为当前值。
  7. 重复。
  汇编程序内容

.section .data
data_items:
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
.section .text
.globl _start
_start:
movl $0, %edi                             #索引寄存器的初始值为0
movl data_items(,%edi,4), %eax            #加载数据的第一个字节
movl %eax, %ebx                           #因为这是第一项,所以%eax是最大的
start_loop:                               #标记循环位置(单次循环结束后应该跳转的位置)
cmpl $0, %eax                             #比较两个值:0和eax寄存器中的数字,将结果保存到状态寄存器中
je loop_exit							  #若结果为两个值相等则跳到循环结束的标志处。
incl %edi                                 #加载下一个数值,将%edi的数值+1
movl data_items(,%edi,4), %eax            #与之前介绍的作用相同,不过%edi的数值变了,%eax为下一个要测试的数值
cmpl %ebx, %eax                           #比较数值
jle start_loop                            #若新的不是更大的话,跳到循环开始
movl %eax, %ebx                           #否则表示该数值比之前的大,则将值传到%ebx为最大值
jmp start_loop                            #无条件跳转到循环开始,进行读取下一个数值
loop_exit:                                #%ebx是退出系统调用的状态码,并且它已经具有最大的数字
movl $1, %eax                             #1exit()系统调用
int $0x80

  汇编程序解析
  结合第一个程序所学的知识,
  由.section伪指令进行分段,
  ①数据段(.data):
  1️⃣data_items::符号/标记:记录数据列表的位置。
    由此,程序中任何想引用该地址,都可使用data_items符号,汇编程序将用汇编过程中的数字的开始地址替换掉。
    若程序中有:movl data_items,%eax,则数字3会传入寄存器eax中。
    注意:这边并没data_items.globl声明,这是因为我们只在程序中引用这些位置。其他文件或程序不需要知道它们的位置,故没有必要进行.globl声明,当然也可添加,即:.globl data_items
  2️⃣.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0:表示保留了14个.long类型的数据大小内存空间,即整个数字列表占用56Byte。
    注意
      1.最后一个数值为0,这边用数字0表示列表结尾,故0必须在最后,否则0后数字无效。当然可用其他方法来表示列表结尾。
      2.虽long的范围为0~4294967295,但也不可超过255,任何超过255的数字会产生奇怪的结果,这是因为255是允许的最大退出状态。
  ②代码段(.text)
  3️⃣.globl _start:为全局的标记,为何这边一定要加.globl,因为Linux需要知道它在哪里,以便知道程序从哪开始执行。
  4️⃣movl data_items(,%edi,4), %eax ==》movl BEGINNINGADDRESS(,%INDEXREGISTER,WORDSIZE) ==》此为索引寻址模式指令方法。
    1.data_items表示数字列表的开始位置地址.
    2.%edi:索引寄存器。0则为数字31则为数字67.
    3.4表示存储单元大小,这边.long故为4.
  5️⃣cmpl $0, %eax 比较两个值即:比较0与eax寄存器中的数字,将比较的结果存在状态寄存器(%eflags)中,这边并未提及,先简单认识。
  6️⃣je loop_exit若比较的结果相等则跳转到loop_exit循环结束的标志处,此为流控制指令。【还有其他的跳跃指令】
  7️⃣incl %edi 加载下一个数值,将%edi的数值+1
  简单描述一下代码段思路:先取得第一个值,该值一定为最大值,存入最大值寄存器中,之后每次先判断当前数值为不为0(是不是最后一个数字),若是则直接跳到结束。若不是,则取数字列表的下一个值进行比较,若小于当前最大值,则继续循环,若大于则替换为最大值,再继续循环。最后在利用第一个程序学到的调用退出程序的系统调用结束。
  实操结果
在这里插入图片描述
数据类型
  .byte:表示每个数字占用1Byte,大小范围:0~255.
  .int:表示每个数字占用2Byte,大小范围:0~65535.
  .long:表示每个数字占用4Byte,大小范围:0~4294967295.
  .ascii:表示将字符存入内存中,每个字符1Byte。如:ascii "Hello there\0"汇编器会保留12个存储位置(字节),\0为终止字符(永远不会显示,只是告诉程序其他部分这是字符的结束),以\(反斜杠)开头的字母和数字表示不能在键盘上输入或在屏幕上容易看到的字符,如,\n表示换行,\t表示“制表符”

条件跳转与无条件跳转(jump)
  条件跳转:基于前面比较或计算的结果更改路径.
  无条件跳转:直接进入不同的路径
  跳转指令
    je-jump equality:如果值相等,则跳转。
    jg-jump greater:如果第二个值大于第一个值,则跳转。
    jge-jump greater equality:如果第二个值大于或等于第一个值,则跳转。
    jl-jump less:如果第二个值小于第一个值,则跳转。
    jle-jump less equality:如果第二个值小于或等于第一个值,则跳转。
    jmp-无条件转移指令:无论如何都要跳。并不需要进行比较。
  PS:可用来实现选择结构与循环结构。

寻址模式
  内存地址引用:
  一般形式ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)
    所有字段可选。
  计算地址FINAL ADDRESS = ADDRESS_OR_OFFSET + %BASE_OR_OFFSET + MULTIPLIER * %INDEX
    ADDRESS_OR_OFFSETMULTIPLIER必须为常数,其他两个必须为寄存器,若任何部分被漏掉则会在方程中替换为0.
  ①直接寻址模式
  只通过使用ADDRESS_OR_OFFSET部分来实现,如:
    movl ADDRESS, %eax:这将加载%eax,其值位于内存地址ADDRESS.
  ②索引寻址模式
  通过使用ADDRESS_OR_OFFSET%INDEX部分完成,可使用任何通用寄存器作为索引寄存器,还可为索引寄存器使用1、2或4的常数乘法器,以便更容易地按字节、双字节和单词进行索引,如:
    假设我们有一个字节字符串string_start,并希望访问第三个字节(索引为2,因为我们开始从0开始计算索引),而%ecx的值为2。若你想将它加载到%eax中,则:movl string_start(,%ecx,1), %eax它从string_start开始,并向该地址添加1 * %ecx,并将值加载到%eax中.
  ③间接寻址模式
  间接寻址模式从寄存器指定的地址加载一个值,如:
    若%eax包含一个地址,可通过如下操作将该地址的值移动到%ebx:movl (%eax), %ebx
  ④基指针寻址方式
  类似于间接寻址,除了它向寄存器中的地址添加一个常量,如,
    若你有一条记录,其中的年龄值是4个字节,并且你在%eax中有记录的地址,你可以通过发出以下指令来检索年龄到%ebx中:movl 4(%eax), %ebx
  ⑤直接的方式(立即数寻址方式)
  即时模式非常简单。它不遵循我们一直使用的一般形式。立即模式用于将直接值加载到寄存器或内存位置。例如,如果您想将数字12加载到%eax中,您只需执行以下操作:movl $12, %eax
  ⑥寄存器寻址模式
  寄存器模式只是将数据移进或移出寄存器。在我们所有的例子中,寄存器寻址模式被用于其他操作数
    PS:除了立即模式外,所有模式都可以用作源或目标操作数。立即模式只能是源操作数。
  除了这些模式外,还有不同大小的值的移动指令

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值