汇编
汇编
1.编辑、汇编、链接和运行(或调试)
在我的汇编学习过程中,采用Netwide汇编器(NASM)编写代码。
使用的文本编辑器:vim
Linux默认编译器链接器:GCC
GCC代表GNU编译器集合,是Linux上的标准编译器和链接器工具。
安装GCC:sudo apt install gcc
安装NASM:sudo apt install build-essential nasm
在命令行中输入nasm -v如果安装成功则会返回版本号相应
- 代码中,使用制表符,空格,换行符使代码更具有可读性
 - 每行一条指令
 - ; 后的文字使注释,计算机会忽略注释
 
(1)编辑代码
例:hello.asm的makefile
;hello.asm
section .data	;data段
	msg db 		"hello,world",10,0;data段声明变量msg
	msglen equ $-msg-1;msg长度,使用equ来计算,$表示当前地址,该表达式意思是当前地址减去msg的最后减一是减去结尾的0
section .bss	;bss段
section .text
	global main	;声明主函数
main:
	;push rbp
	;mov rbp,rsp
	;这段是函数序言,在这种简单的程序中不需要使用
	mov rax,1;1表示写入
	mov rdi,1;1表示标准输出
	mov rsi,msg;将变量msg加入rsi
	mov rdx,msglen;msg的长度
	syscall;执行系统调用,则在rsi中的msg将会标准输出到终端
	mov rax,60;60表示退出
	mov rdi,0;成功退出代码0放入rdi
	syscall;执行系统调用,终止进程
上述是一个简单的汇编程序,用于在终端上输出”hello,world“,接下来将结合这个程序了解汇编的基本结构。
- .data段在section .data中,使用以下格式声明和定义初始化数据:
 
<变量名称> <类型> <值>
如果data段中包含变量,则源代码被汇编并链接到可执行文件是,将为该变量分配内存。变量名称是符号名称,对内存位置和变量的引用可以占用一个或多个内存位置。变量名称是指变量在内存中的起始地址。
- .bss段(Block Start by Symbol),用来存放未初始化的变量。未初始化变量的空间在此段中声明,格式如下:
 
<变量名称> <类型> <数字>
.bss段的变量不包括任何值;这些值将在稍后的执行中分配。内存位置不是在编译时保留的,而是在执行中保留的。当程序开始执行时,程序会从操作系统中请求所需的内存,分配给.bss段的变量并初始化为0.如果执行时没有足够的内存可用于.bss的变量,程序将崩溃。
- .text段是所有操作所在的位置;
- 
在上面的代码中,main:被称为标签
 - 
系统调用代码1被放入寄存器rax中,表示”写入“。
 - 
在Intel的汇编风格中,对于指令mov,
mov destination,source表示将source的内容复制到destination中(注意,是复制) - 
在代码中,用于写入的输出目标存储在寄存器rdi中,1表示标准输出(在本例中,是输出在屏幕上)
 - 
要显示的字符串的地址被放入寄存器rsi中
 - 
rdx中放置字符串的长度,(注意不能计算字符串结尾的0,它表示NULL,无意义)
 - 
执行系统调用syscall,(个人理解)将执行前面处理好的寄存器状态和变量。syscall是对操作系统的函数调用
 - 
为避免程序完成时出现错误消息,需要清除程序出口,首先要将60写入rax,表示退出,接下来吧表示成功的退出代码0放入rdi,然后执行系统调用。这样就能正常退出而不报错
mov指令的一些用法:
mov 寄存器 内存
mov 寄存器 即时值
mov 内存 寄存器
不合法:mov 内存 内存
 
 - 
 
(2)编译
将前面提到的代码编辑入文件hello.asm中:
vim hello.asm
复制粘贴或者自己写都可以
然后创建makefile文件:
vim makefile
写入以下内容:
#hello.asm的makefile
hello:hello.o	;hello依赖于hello.o
	gcc -o hello hello.o -no-pie
hello.o:hello.asm	;hello.o依赖于hello.asm
	nasm -f elf64 -g -F dwarf hello.asm -l hello.lst
Makefile是一种用于自动化编译和构建项目的工具,它会依据文件之间的依赖关系和规则来决定执行哪些命令。在这个Makefile中,存在两个规则,分别用于生成目标文件hello.o和可执行文件hello。
hello.o是目标文件(Object File)目标文件在整个软件开发和程序构建过程中扮演着重要角色,主要用途如下:
1. 模块化编译
在大型项目中,源代码通常会被分割成多个源文件,每个源文件可以独立进行编译。例如,一个项目可能包含多个
.c或.asm文件,通过分别编译这些文件,可以生成对应的目标文件。这样做的好处是,当某个源文件发生修改时,只需重新编译该文件对应的目标文件,而不需要重新编译整个项目,从而大大提高了编译效率。2. 代码复用
目标文件可以被其他程序重复使用。例如,你编写了一个通用的数学库,将其编译成目标文件后,其他项目在需要使用该数学库的功能时,只需将这个目标文件与自己的目标文件链接在一起即可,无需重新编写数学库的代码。
3. 链接成可执行文件
目标文件本身不能直接运行,需要通过链接器(如
gcc、ld等)将一个或多个目标文件以及必要的库文件链接在一起,生成最终的可执行文件。在Makefile中,gcc -o hello hello.o -no-pie这一命令就是将hello.o目标文件链接成可执行文件hello。4. 调试信息存储
目标文件可以包含调试信息,如上述
Makefile中使用的-g -F dwarf选项,会让nasm汇编器在生成目标文件时,将调试信息以 DWARF(Debugging With Attributed Record Formats)格式存储在目标文件中。这些调试信息可以帮助调试器(如gdb)在调试程序时,将机器码映射回源代码,方便开发者定位和解决问题。
在命令行中输入:
makefile
这样系统会自动生成hello hello.o hello.lst
查看hello.lst:
     1                                  ;hello.asm
     2                                  section .data	;data段
     3 00000000 68656C6C6F2C776F72-     	msg db 		"hello,world",10,0;data段声明变量msg
     3 00000009 6C640A00           
     4                                  	msglen equ $-msg-1;msg长度,使用equ来计算,$表示当前地址,该表达式意思是当前地址减去msg的最后减一是减去结尾的0
     5                                  section .bss	;bss段
     6                                  section .text
     7                                  	global main	;声明主函数
     8                                  main:
     9                                  	;push rbp
    10                                  	;mov rbp,rsp
    11                                  	;这段是函数序言,在这种简单的程序中不需要使用
    12 00000000 B801000000              	mov rax,1;1表示写入
    13 00000005 BF01000000              	mov rdi,1;1表示标准输出
    14 0000000A 48BE-                   	mov rsi,msg;将变量msg加入rsi
    14 0000000C [0000000000000000] 
    15 00000014 BA0C000000              	mov rdx,msglen;msg的长度
    16 00000019 0F05                    	syscall;执行系统调用,则在rsi中的msg将会标准输出到终端
    17 0000001B B83C000000              	mov rax,60;60表示退出
    18 00000020 BF00000000              	mov rdi,0;成功退出代码0放入rdi
    19 00000025 0F05                    	syscall;执行系统调用,终止进程
第一列是行号,第二列是分配的内存地址(八位,并且从0开始),第三列是将汇编指令转换为机器码的十六进制表示在这其中的一些0是用于填充和内存对齐的,用于优化代码功能,以获得尽可能小的可执行文件和最快的代码。值得一提的是,机器码是第一代编程语言,而汇编则是第二代。

                
            
        
浙公网安备 33010602011771号