HNU计算机系统·汇编初阶

本篇是上课随笔欢迎大家补充指正


汇编语言的引入

机器指令是二进制表达的机器操作,汇编语言是这些机器操作的符号化表达
各种操作和资源的符号化实现了对机器物理资源的直接引用
汇编实现代码对底层硬件的直接控制

 特点:

  • 直观,可读性强,与机器指令一一对应
  • 寄存器,内存单元

优点:

        编写出来的程序执行效率高,CPU严格按照程序员的要求去做,没有多余的额外操作。

缺点:

        用机器语言编写程序有很高的要求和许多不便。


如何分别图示代码是可执行文件 or 目标文件:

区别:目标文件地址从0开始,而可执行文件在代码段中,不从0开始


         为了改善机器指令的可读性,选用了一些能反映机器指令功能的单词或词组来代表该机器指令:MOV, ADD, SUB等等。

        不再关心机器指令的具体二进制编码。与此同时,也把CPU内部的各种资源符号化,使用该符号名也等于引用了该具体的物理资源,如EAX, ESP等等。


 CPU内部寄存器

如图所示,eax,ebx,ecx,edx是数据寄存器,剩下的分别为指针寄存器和索引寄存器。这四个 32 位数据寄存器用于算术、逻辑和其他运算。

这些 32 位寄存器可以通过三种方式使用方式:

  • 作为完整的32位数据寄存器:EAX、EBX、ECX、EDX
  • 32 位寄存器的下半部分可用作四个 16 位数据寄存器:AX、BX、CX 和 DX
  • 上述4个16位寄存器的下半部分和上半部分可以用作8个8位数据寄存器:AH、AL、BH、BL、CH、CL、DH和DL

不同部分功能:

  • AX 为主累加器:它用于输入/输出和大多数算术指令。 例如,在乘法运算中,根据操作数的大小将一个操作数存储在EAX或AX或AL寄存器中
  • BX 被称为基址寄存器:因为它可用于索引寻址
  • CX 被称为计数寄存器:与 ECX 一样,CX 寄存器存储迭代操作中的循环计数
  • DX被称为数据寄存器: 它还用于输入/输出操作。 它还与 AX 寄存器和 DX 一起使用,用于涉及大值的乘法和除法运算


内存按字节编制,每个地址的存储单元可以存放1字节(8 bits)数据


存储数据:

大端法与小端法

  • 小端法:低位字节放在低地址
  • 大端法:低位字节放在高地址

以小端法为例:

        存储数据 0x87654321,一共四字节,占用四个内存地址,一个int是4bits,一个字节是8bits,所以一个内存单元存储两个int

小端法:低位字节放在低地址        

大端法与此类似


读取数据

取数据过程:

  • 小端法:低位字节放在首地址上
  • 大端法:高位字节放在首地址上

以读取用小端法存储的数据为例:

        从低位地址开始读取数据,类似于一个栈,先进后出

注意:内存地址是连续的 


 AT&T风格汇编代码

格式:

movl   $8     ,  %eax;   
操作数 源寄存器,目的寄存器

AT&T 汇编中:

  • 寄存器前被冠以“%”
  • 立即数前被冠以“$”
  • 十六进制数前被冠以“0x”

指令后缀:

  • q :8B
  • l   :  4B
  • w :2B
  • b :1B

操作数:

  • 立即数(immediate)
  • 寄存器(register)
  • 存储器(memory)

操作数方向:

        源操作数在前,目的操作数在后,这一点和intel汇编语法正好相反。


上课实验:

程序源码的生成目标文件和可执行文件:

链接: https://pan.baidu.com/s/1cjTe2ldipxNWryHW32w2tQ?pwd=4y2a 提取码: 4y2a 

命令:xxx为文件名

as -g xxx.s -o xxx.o 
ld xxx.o -o xxx

如图所示 

 使用命令:xxx为可执行文件名

objdump -d xxx

来查看文件内容,如图所示


汇编中的mov:

能实现以下操作:

  •         CPU内部寄存器之间数据的任意传送(除了码段寄存器CS和指令指针IP以外)。
  •         立即数传送至CPU内部的通用寄存器组(即AX、BX、CX、DX、BP、SP、SI、DI),给这些寄存器赋初值。
  •         CPU内部寄存器(除了CS和IP以外)与存储器(所有寻址方式)之间的数据传送,可以实现一个字节或一个字的传送。
  •         能实现用立即数给存储单元赋初值。  

可参考博客:汇编语言||基本传送指令MOV的用法详解_汇编mov指令详解-CSDN博客

        movl: 用于传送32位的长字值
        movw: 用于传送16位的字值
        movb: 用于传送8位的字值


  gdb调试:

进入调试命令:xxx为可执行文件

gdb -q xxx

如图所示

 list命令:
list

l(list)命令用于列出源码 最多列出10行,继续l或空格键

list命令依然有很多用法,但是老师上课没有讲,此处不做补充。

break命令:

        默认情况下,程序不会进入调试模式,代码会瞬间从开头执行到末尾。设置断点后,会停止在断点处。

        break 命令(可以用 b 代替)常用的语法格式有以下 2 种。

(gdb) break location
(gdb) break ... if cond

1) 第一种格式中,location 用于指定打断点的具体位置,其表示方式有多种

location 的值含 义
linenumlinenum 是一个整数,表示要打断点处代码的行号。要知道,程序中各行代码都有对应的行号,可通过执行 l(小写的 L)命令看到。
filename:linenumfilename 表示源程序文件名;linenum 为整数,表示具体行数。整体的意思是在指令文件 filename 中的第 linenum 行打断点。
+ offset
- offset
offset 为整数(假设值为 2),+offset 表示以当前程序暂停位置(例如第 4 行)为准,向后数 offset 行处(第 6 行)打断点;-offset 表示以当前程序暂停位置为准,向前数 offset 行处(第 2 行)打断点。
functionfunction 表示程序中包含的函数的函数名,即 break 命令会在该函数内部的开头位置打断点,程序会执行到该函数第一行代码处暂停。
filename:functionfilename 表示远程文件名;function 表示程序中函数的函数名。整体的意思是在指定文件 filename 中 function 函数的开头位置打断点。

2) 第二种格式中,... 可以是表 1 中所有参数的值,用于指定打断点的具体位置;cond 为某个表达式。整体的含义为:每次程序执行到 ... 位置时都计算 cond 的值,如果为 True,则程序在该位置暂停;反之,程序继续执行。  

基本演示如图所示:

info命令:
info b

 info b 可以让我们查看当前有哪些断点

run命令:

        启动程序。GDB 调试器提供了多种方式来启动目标程序,其中最常用的就是 run 指令,其次为 start 指令。也就是说,run 和 start 指令都可以用来在 GDB 调试器中启动程序,它们之间的区别是:

  • 默认情况下,run 指令会一直执行程序,直到执行结束。如果程序中手动设置有断点,则 run 指令会执行程序至第一个断点处;
  • start 指令会执行程序至 main() 主函数的起始位置,即在 main() 函数的第一行语句处停止执行(该行代码尚未执行)。

 next命令:

        ·借助 next 命令可以控制 GDB 单步执行程序。所谓单步调试,就是通过一行一行的执行程序,观察整个程序的执行流程,进而尝试发现一些存在的异常或者 Bug。

next 命令可以缩写为 n 命令,使用方法也很简单,语法格式如下:

next count

参数 count 表示单步执行多少行代码,默认为 1 行。

如图所示:

 print命令

        以指定类型打印指定地址内容

以十六进制查看立即数

p/x num

 如图所示,查看eax中的数据

x 按十六进制格式显示变量。d 按十进制格式显示变量。
u 按十六进制格式显示无符号整型。o 按八进制格式显示变量。
t 按二进制格式显示变量。a 按十六进制格式显示变量。
c 按字符格式显示变量。f 按浮点数格式显示变量

examine命令:

        x :查看内存地址中的值

x/<n/f/u>  <addr>

<n/f/u>

  • n:是正整数,表示需要显示的内存单元的个数,即从当前地址向后显示n个内存单元的内容,一个内存单元的大小由第三个参数u定义。
  • f:表示addr指向的内存内容的输出格式,s对应输出字符串。
  • u:就是指以多少个字节作为一个内存单元-unit,默认为4。当然u还可以用被一些字符表示,如b=1 byte, h=2 bytes,w=4 bytes,g=8 bytes.

<addr>:表示内存地址。

整合这个命令的诠释:

        就是以addr为起始地址,返回n个单元的值,每个单元对应u个字节,输出格式是f。


寻址模式:

  1. 立即数寻址-1005.s
  2. 寄存器寻址 - 1006.s
  3. 绝对寻址 - 1007.s
  4. 间接寻址 - 1008.s
  5. 基址偏移量寻址
  6. 变址寻址-1009.s
  7. 变址基址寻址
  8. 比例变址寻址-1010.s
  9. 比例变址基址寻址
立即数寻址:

        示例:movl $1,%eax

将立即数1传送到eax寄存器中

寄存器寻址:

        示例:movl %ebx,%eax

将ebx中的数据传送到eax寄存器中

绝对寻址:

        示例:movl 0x08048054,%eax

将地址为0x8048054的内存单元中的数据传送到eax寄存器中

间接寻址:

       示例: movl (%ebx),%eax

将ebx中的数据作为基址,找到地址为基址的内存单元,将其数据送到eax寄存器中

基址偏移量寻址:

        示例:movl 0x8(%ebx),%eax

将ebx中的数据作为基址,再找到地址为基址+8的内存单元,将其数据送到eax寄存器中

变址寻址:

        示例:movl (%ebx,%edx),%eax

新地址=ebx中的数据+edx中的数据

变址基址寻址:

        示例:movl 0x8(%ebx,%edx),%eax

新地址=8+ebx中的数据+edx中的数据

比例变址寻址:

        示例:movl (%ebx,%ecx,0x2),%eax

新地址=ebx中的数据+ecx中的数据*2

比例变址基址寻址:

        示例:movl 0x8(%ebx,%ecx,0x2),%eax

新地址=8+ebx中的数据+ecx中的数据*2


总结一下,这节课讲的东西挺多,但是不难,欢迎大家指正

  • 23
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值