说明:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
QQ 群 号:513683159 【相互学习】
内容来源:
《Computer Systems A Programmer’s Perspective》
上下文链接
上篇:汇编语言学习篇4——寄存器总结
下篇:汇编语言学习篇5——GAS汇编实践篇(2)- helloworld.s
前言:
GAS汇编实践篇开始,每篇将以一个程序进行讲解。
先看一下程序实现什么功能,然后将程序写入源文件中运行实现一下,实现好在来仔细看看查看一下代码逻辑,以及对应的知识点。
第一个程序:exit.s
功能:什么都不做,直接退出,返回状态代码到Linux内核。
在运行后可输入指令:echo $?
,可查看程序状态码。
寄存器作用:
%eax
: 保存系统调用号。
%ebx
: 保存返回状态。
详细过程:
Step 1:①输入指令:vim exit.s
, 创建文件后,②输入指令i
进入编辑模式,③将以下内容复制进去。:④按下ESC
键,退出编辑模式,⑤输入指令::wq
,保存退出
.section .data #数据段,这边可省略
.section .text #代码段
.globl _start #定义标记
_start: #标记的具体位置
movl $1,%eax #用于退出程序的Linux内核命令号(系统调用)
movl $0,%ebx #将返回到操作系统的状态号。修改0为其他数值,它会返回对应数值echo $?
int $0x80 #这将唤醒内核以运行exit命令
Step 2:输入指令as exit.s -o exit.o
,将exit.s
(汇编文件)经过as
(汇编程序)输出到exit.o
(目标文件)
此时得到的目标文件为机器语言,但还未完全组合在一起(绝大多数程序都将会有多个源文件),且还缺少一些信息,故无法让内核加载并执行。
Step 3:输入指令ld exit.o -o exit
,将exit.o
(目标文件)经过ld
(链接程序)输出到exit
(可执行文件)中(无后缀名,若不使用-o,则默认为a.out)
利用ld
对多个目标文件组合一起并向其添加信息的程序,以便内核知道如何加载和运行它。而这边仅有一个目标文件,故只需使用链接器添加信息以使它能够运行。
Step 4:输入指令./exit
,表示在运行当前目录(./)下的exit
文件。
运行后,将会发现没有任何变化(因为该程序除了退出什么都不会做)。
Step 5:输入指令echo $?
,将会输出数字0
.
因为每个程序退出时都会给Linux一个退出状态码,若正常则输出0,若为其他数字则表示各种错误提示(与程序定义有关)。【若这边将movl $0,%ebx
中改成其他数字则会输出其他数字】
程序分析:
(1)注释:用#
表示,写给人看的,程序并不会识别。
(2)伪指令:以句点开头的任何内容,不会直接转换为机器指令。是交由汇编程序处理(并不是计算机实际运行的指令)。【assembler directives /pseudo-operations】
①分段(section):.section
用于表示将程序分解为几个段(部分)【breaks your program up into sections.】
1️⃣.section .data
:启动data(数据)段,该段表示存储数据所在的位置。【这边并没数据的使用,但为了代码完整所以还是写出来,几乎每个程序都会有数据】
2️⃣.section .text
:启动text(文本)段,该段表示程序指令所在的位置。
②全局(global):.global
用于表示进行汇编后不要丢弃该符号(标记)。【链接时还需该标记】
(3)符号/标记::用于标记程序或数据的位置,只需根据名称而不是位置编号即可跟踪地址。(想象一下,若要想引用某一内存位置的地址,则需记住对应的地址,而且一旦在中间插入数据或代码则会改变地址,故使用符号进行标记显得十分重要)【symbol / label】
①_start
:为特殊的标记,标记程序开始的位置。(若不以此方式进行标记,则加载程序时不知该从哪个位置开始运行)【一般会与.global
搭配】
3️⃣.global _start
: 进行汇编时不要丢弃符号_start
,符号_start
用来标记程序的开始位置。
②_start:
:表示形式:标签+冒号。用来定义符号的值,当汇编程序正在组装程序时,必须为每个数据值分配地址,告诉符号的值为下一个指令或数据元素所在的位置。
4️⃣_start:
给符号_start
所在位置的地址进行定义,若上面添加数据改变位置则会更新为新地址。
(4)汇编指令:
movl
指令—两个操作数
用法:movl source destination
=将source
传送到destination
中,并不修改source
内容,如:
5️⃣movl $1,%eax
:将数字1
传送到 寄存器eax
。,这一条系统调用,且1
表示退出程序的系统调用。【正常程序不能做所有的事情,许多操作如调用其他程序、处理文件和退出必须有操作系统通过系统调用来处理】
6️⃣movl $0,%ebx
:将数字0
传送到 寄存器ebx
。 在退出程序的系统调用下,操作系统需要在寄存器ebx中加载状态代码,并将此值返回给系统。
类似的有:addl, subl, imull
==>加、减、乘
idivl
==>除 (跟前面会有点区别)
7️⃣int $0x80
:int
=interrupt
即表示中断,0x80
表示要使用的中断号,该语句表示:中断正常的程序流,并将控制从我们程序转移到Linux,这样它就可执行系统调用。【若没有该句,则没有发出中断信号,那么就不会执行系统调用】
shell中特殊变量
编号 | 特殊变量 | 含义 |
---|---|---|
1 | $# | 参数的个数 |
2 | $0 | 脚本本身的名字 |
3 | $1 | 传递给该shell脚本的第一个参数 |
4 | $2 | 传递给该shell脚本的第二个参数 |
5 | $@ | 所有参数,并且所有参数都是独立的 |
6 | $$ | 脚本运行的当前进程ID号 |
7 | $? | 显示最后命令的退出状态,0表示没有错误,其他表示有错误 |
8 | $* | 以一对双引号给出参数列表 |
9 | $! | 代表最后执行的后台命令的PID |
10 | $_ | 代表上一个命令的最后一个参数 |