professional assembly langage 读书笔记

本文介绍了一段简单的汇编程序,用于获取CPU厂商ID。该程序利用cpuid指令读取CPU信息,并通过系统调用将结果显示出来。此外,还详细讲解了汇编语言中的关键指令及调试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单的汇编程序:

 

.section命令定义了数据段。output生命了一个标签为output的字符串。.ascii命令表示使用ascii字符声明字符串。
如果使用.bss段,则可以在.data段后定义。
接着定义了文本段(代码段)。.globl
命令指明后面的标签是外部程序的入口(本例是_start),接着_start是本程序的入口点(GNU汇编器默认的)。
nop是一个空指令,什么也做。(在调试时,有用)

本程序演示的是使用cpuid指令获取cpu厂商。
cpuid指令的要求是:
eax的值决定cpuid获取cpu的什么信息。本例中是eax=0,声称cpu厂商ID。获取后的值
依次放在ebx,edx,ecx,以小尾数(little endian)的形式。

$在上下文中有 三种意思:
1.用在立即数前面。
2.用在内存标记前面,表示标记的地址。
3.在gdb调试时,是用在寄存器前面,

再接着程序看看, movl $output, %edi
,把output标记的地址放在edi寄存器中,edi寄存器是处理字符串的寄存器(destination)。
然后分别把ebx,edx,ecx,的指放在output所标记的字符串的占位符中(xxxxxxxxxxxx)。
括号()表示,edi寄存器存储的是内存地址,此时是对edi寄存器所存储的地址所在的内存空间
进行处理(间接寻址)。

既然都把结果放在了output所标记的字符串里,下面就要显示信息了。本例使用的是
int $0x80系统(软)中断。0x80的要求是:
eax包含系统调用指,本例是4号系统调用。
ebx表示文件描述符,1是标准输出。
ecx是所要显示字符串的首地址。
edx是要输出的字符串的长度。

最后要退出程序,返回os。还是使用int $0x80软中断。
系统调用是1号。
ebx存储退出码,程序执行后可以在shell中,使用echo $?命令查看退出码。

程序看完了,开始汇编(动词),连接。

 

我们来搞一下,把退出码改为100

 

确实如此。还是改过来吧,0通常表示程序正常退出。

上面我们使用的是gnu,binutils软件包里的东西,
如果我们想使用gcc来编译呢?
只需把程序入口地址改为main即可,如下

 

下面开始调试,使用gdb。
使用gas在汇编阶段,要指定选项-gstabs,才能把源码的很多信息汇编进可执行代码,这样才能调试。
然后再ld。
**************当然如果使用gcc编译的话,也可以在编译阶段用-g选项。 但我调试时,出现了错误:

 

本例以-gstabs调试为例:

 

我们使用list列举了十行源码,list是用来查看函数的源码的(man gdb)。

再然后,我们设置断点,对汇编程序进行设置断点,有几个地方可以进行设置:
1.某个标记
2.某行
3.数值到达指定值
4.函数执行了指定次数
本例,我们就在_start标签处设置断点,上面已经给出了nop这个空指令,在调试时,如果
把断点设置成break *_start,就根本不能在断点处停下来。

 

进行单步调试,并且再次查看所有寄存器的值。

 

恢复正常执行(接着执行)continue。

 在上面的过程中,我们使用info register来查看寄存器的值,还可以通过print来查看指定寄存器的值(print也可以查看变量的值无须取地址print i):
 print/d  以十进制显示
 print/t 以二进制显示
 print/x 以十六进制显示

 

在指定寄存器的时候要使用$符。

如果要查看内存(变量)的内容,也可以使用x命令,格式为:
x/nyz
n为要显示大的字段数,
y为输出格式:
c  -->字符
d  -->十进制
x  -->十六进制

z为显示字段的长度(每隔xx显示):
b -->一个字节
h -->两个字节(十六位)
w -->四个字节(32位)

 

 

在查看内存内容的时候,需在内存标记前加&符号,表示内存地址。

最后,在汇编中连接C库函数,本例连接动态连接库。

 

 

命令.asciz在字符串后面自动添加空字符(c风格的字符串),因为printf函数需要这样的字符串。
.bss段中,使用.lcomm命令,定义了12个字节的数据缓冲区。为了把参数传递给printf函数,
必须把参数压到栈里,使用pushl命令完成,call指令调用printf函数,addl指令把esp(栈顶指针)加8
也即清空了刚刚压入栈的内容。最后把0放入栈中,供exit函数调用。

下面开始汇编,连接:
wolf@debian:~/programming/assembly$ as -o cpuid2.o cpuid2.s
wolf@debian:~/programming/assembly$ ld -dynamic-linker /lib/ld-linux.so.2 -o cpuid2 /
> -lc cpuid.o
wolf@debian:~/programming/assembly$ ./cpuid2
the processor vender ID is 'GenuineIntel'
c语言的动态连接库是libc.so,在命令行中可以通过-lc来指定,(这是ld的规则,去掉lib和.so,剩下c)
,
    指定了动态库,那如何在运行时动态加载动态库?这就需要ld-linux.so.2的帮忙了,通过
使用-dynamic-linker选项指定加载动态连接库的程序ld-linux.so.2 。

当然也可以使用gcc来编译,只需要把_start标签改为main即可。gcc自动连接c函数库。


更正:

1.上面红色部分1,设置断点时,因为gcc是从main标签开始,所以设置的断点是break *main+1 ,这样就没有错误了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值