汇编语言入门
Posted Dontla
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了汇编语言入门相关的知识,希望对你有一定的参考价值。
文章目录
汇编语言入门一:环境准备
执行:
sudo apt-get update
执行:
sudo apt-get install nasm
检查:
新建文件:vi t.c
int main() {
return 0;
}
新建文件:first.asm
global main
main:
mov eax, 0
ret
编译生成first文件
(32位系统):
$ nasm -f elf first.asm -o first.o
$ gcc -m32 first.o -o first
64位系统:
$ nasm -f elf64 first.asm -o first.o
$ gcc -m64 first.o -o first
结果:
运行:
$ ./first ; echo $?
结果:
汇编语言入门二:环境有了先过把瘾
新建文件:vi test.asm
global main
main:
mov eax, 1
mov ebx, 2
add eax, ebx
ret
编译运行:
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test.o -o test
dontla@dontla-virtual-machine:~/桌面/test$ ./test ; echo $?
3
dontla@dontla-virtual-machine:~/桌面/test$
练习1:
global main
main:
mov eax, 1
add eax, 2
add eax, 3
add eax, 4
add eax, 5
ret
结果:
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test.o -o test
dontla@dontla-virtual-machine:~/桌面/test$ ./test ; echo $?
15
练习2:
global main
main:
mov eax, 1
mov ebx, 2
mov ecx, 3
mov edx, 4
add eax, ebx
add eax, ecx
add eax, edx
ret
结果:
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test.o -o test
dontla@dontla-virtual-machine:~/桌面/test$ ./test ; echo $?
10
简单指令介绍
mov
数据传送指令,我们可以像下面这样用mov指令,达到数据传送的目的。
mov eax, 1 ; 让eax的值为1(eax = 1)
mov ebx, 2 ; 让ebx的值为2(ebx = 2)
mov ecx, eax ; 把eax的值传送给ecx(ecx = eax)
add
加法指令
add eax, 2 ; eax = eax + 2
add ebx, eax ; ebx = ebx + eax
ret
返回指令,类似于C语言中的return,用于函数调用后的返回(后面细说)。
sub
减法指令(用法和加法指令类似)
sub eax, 1 ; eax = eax - 1
sub eax, ecx ; eax = eax - ecx
更多寄存器
除了前面列举的eax、ebx、ecx、edx之外,还有一些寄存器:
esi
edi
ebp
其中eax、ebx、ecx、edx
这四个寄存器是通用寄存器,可以随便存放数据,也能参与到大多数的运算。而余下的三个多见于一些访问内存的场景下,不过,目前,你还是可以随便抓住一个就拿来用的。
汇编语言入门三:是时候上内存了
cpu、寄存器、内存的关系
指针与内存
寄存器与内存
内存在cpu外,寄存器在cpu内,只有有限个,做多了cpu贵
将寄存器的值赋值给内存
mov [0x0699], eax
mov [0x0998], ebx
mov [0x1299], ecx
mov [0x1499], edx
mov [0x1999], esi
将内存的值赋值给寄存器
mov eax, [0x0699]
mov ebx, [0x0998]
mov ecx, [0x1299]
mov edx, [0x1499]
mov esi, [0x1999]
动手编程
global main
main:
mov ebx, 1
mov ecx, 2
add ebx, ecx
mov [sui_bian_xie], ebx
mov eax, [sui_bian_xie]
ret
section .data
sui_bian_xie dw 0
结果:
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test.o -o test -no-pie
dontla@dontla-virtual-machine:~/桌面/test$ ./test ; echo $?
3
dontla@dontla-virtual-machine:~/桌面/test$ ls -lh
总用量 24K
-rwxrwxr-x 1 dontla dontla 16K 6月 3 22:32 test
-rw-rw-r-- 1 dontla dontla 151 6月 3 22:08 test.asm
-rw-rw-r-- 1 dontla dontla 848 6月 3 22:32 test.o
dontla@dontla-virtual-machine:~/桌面/test$
relocation R_X86_64_32S against `.data‘ can not be used when making a PIE object; recompile with -fP
解析:
mov ebx, 1 ; 将ebx赋值为1
mov ecx, 2 ; 将ecx赋值为2
add ebx, ecx ; ebx = ebx + ecx
mov [sui_bian_xie], ebx ; 将ebx的值保存起来
mov eax, [sui_bian_xie] ; 将刚才保存的值重新读取出来,放到eax中
ret ; 返回,整个程序最后的返回值,就是eax中的值
注意:程序返回时eax寄存器的值,便是整个程序退出后的返回值,这是当下我们使用的这个环境里的一个约定,我们遵守便是
这两行代码:
section .data
sui_bian_xie dw 0
第一行是表示接下来的内容经过编译后,会放到可执行文件的数据区域,同时也会随着程序启动的时候,分配对应的内存。(如果寄存器不够用,就要开辟内存作为临时存储数据的空间)
第二行就是描述真实的数据的关键所在里,这一行的意思是开辟一块4字节的空间,并且里面用0填充。这里的dw(double word)就表示4个字节(一个word类型两个char,一个char一个字节,两个char就是两个字节),前面那个sui_bian_xie的意思就是这里可以随便写,也就是起个名字而已,方便自己写代码的时候区分,这个sui_bian_xie会在编译时被编译器处理成一个具体的地址,我们无需理会地址具体时多少,反正知道前后的sui_bian_xie指代的是同一个东西就行了。
疯狂的写代码
global main
main:
mov ebx, [number_1]
mov ecx, [number_2]
add ebx, ecx
mov [result], ebx
mov eax, [result]
ret
section .data
number_1 dw 10
number_2 dw 20
result dw 0
结果:
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test.o -o test -no-pie
dontla@dontla-virtual-machine:~/桌面/test$ ./test ; echo $?
30
dontla@dontla-virtual-machine:~/桌面/test$
反汇编
先检查安装了反汇编工具没有,
dontla@dontla-virtual-machine:~/桌面/test$ which gdb
/usr/bin/gdb
dontla@dontla-virtual-machine:~/桌面/test$
否则:
$ sudo apt-get install gdb -y
新建test.asm
global main
main:
mov eax, 1
mov ebx, 2
add eax, ebx
ret
编译:
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test.o -o test
运行:
dontla@dontla-virtual-machine:~/桌面/test$ ./test ; echo $?
3
使用gdb对test文件进行反汇编(将机器语言反汇编成汇编语言):
dontla@dontla-virtual-machine:~/桌面/test$ gdb ./test
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...
(No debugging symbols found in ./test)
(gdb)
把反汇编的格式调整称为intel的格式:
(gdb) set disassembly-flavor intel
(gdb)
继续:
(gdb) disas main
Dump of assembler code for function main:
0x0000000000001130 <+0>: mov eax,0x1
0x0000000000001135 <+5>: mov ebx,0x2
0x000000000000113a <+10>: add eax,ebx
0x000000000000113c <+12>: ret
0x000000000000113d <+13>: nop DWORD PTR [rax]
End of assembler dump.
(gdb)
动态调试
打断点:
(gdb) break *0x0000000000001135
Breakpoint 1 at 0x1135
运行:发现报错了
(gdb) run
Starting program: /home/dontla/桌面/test/test
Warning:
Cannot insert breakpoint 1.
Cannot access memory at address 0x1135
(gdb)
查看eax寄存器的值:
(gdb) info registers eax
eax 0x1 1
查看ebx寄存器的值:
(gdb) info registers ebx
ebx 0x55555140 1431654720
执行下一句程序,再看看ebx的值:
(gdb) stepi
0x000055555555513a in main ()
(gdb) info registers ebx
ebx 0x2 2
继续单步执行并查看值,输入指令disas能查看程序执行到哪一句代码:
(gdb) stepi
0x000055555555513c in main ()
(gdb) info registers eax
eax 0x3 3
(gdb) disas
Dump of assembler code for function main:
0x0000555555555130 <+0>: mov $0x1,%eax
0x0000555555555135 <+5>: mov $0x2,%ebx
0x000055555555513a <+10>: add %ebx,%eax
=> 0x000055555555513c <+12>: retq
0x000055555555513d <+13>: nopl (%rax)
End of assembler dump.
(gdb)
想让程序直接运行到结束,就输入指令continue:
(gdb) continue
Continuing.
[Inferior 1 (process 32774) exited with code 03]
(gdb)
汇编语言入门四:打通C和汇编语言
插曲:C语言与汇编语言的关系
新建程序 test.c
int x, y, z;
int main() {
x = 2;
y = 3;
z = x + y;
return z;
}
编译执行输出:
dontla@dontla-virtual-machine:~/桌面/test1$ gcc test.c -o test
dontla@dontla-virtual-machine:~/桌面/test1$ ./test ; echo $?
5
dontla@dontla-virtual-machine:~/桌面/test1$
上面c代码等价的汇编代码如下:
global main
main:
mov eax, 2
mov [x], eax
mov eax, 3
mov [y], eax
mov eax, [x]
mov ebx, [y]
add eax, ebx
mov [z], eax
mov eax, [z]
ret
section .data
x dw 0
y dw 0
z dw 0
为什么要存进去又取出来,又存进去,太麻烦了吧!
干啥不直接这样?
global main
main:
mov [x], 2
mov [y], 3
add [x], [y]
mov [z], [x]
ret
section .data
x dw 0
y dw 0
z dw 0
直接就报错:
dontla@dontla-virtual-machine:~/桌面/test1$ nasm -f elf64 test.asm -o test.o
test.asm:4: error: operation size not specified
test.asm:5: error: operation size not specified
test.asm:6: error: invalid combination of opcode and operands
test.asm:7: error: invalid combination of opcode and operands
也不知道是啥原因。。。难道不能直接操作内存,必须要通过寄存器操作内存?
改一下:
global main
main:
mov eax, 2
mov [x], eax
mov eax, [x]
mov ebx, 3
mov [y], ebx
mov ebx, [y]
add eax, ebx
mov [z], eax
ret
section .data
x dw 0
y dw 0
z dw 0
运行结果:
dontla@dontla-virtual-machine:~/桌面/test1$ nasm -f elf64 test.asm -o test.o
dontla@dontla-virtual-machine:~/桌面/test1$ gcc -m64 test.o -o test -no-pie
dontla@dontla-virtual-machine:~/桌面/test1$ ./test ; echo $?
5
注意:ret最后是以eax的值作为返回值的,不是最后一句代码
注意vi全选删除代码的快捷键是 ESC–> ggVG
揭开C程序的庐山真面目(分别查看C语言程序和汇编语言写的程序编译生成可执行文件后,用gdb反汇编后的代码)
准备两份代码:
test1.c
int x, y, z;
int main() {
x = 2;
y = 3;
z = x + y;
return z;
}
test2.asm
global main
main:
mov eax, 2
mov [x], eax
mov eax, 3
mov [y], eax
mov eax, [x]
mov ebx, [y]
add eax, ebx
mov [z], eax
mov eax, [z]
ret
section .data
x dw 0
y dw 0
z dw 0
分别编译生成可执行文件test1和test2:
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 test1.c -o test1
dontla@dontla-virtual-machine:~/桌面/test$ nasm -f elf64 test2.asm -o test2.o
dontla@dontla-virtual-machine:~/桌面/test$ gcc -m64 -fno-lto test2.o -o test2 -no-pie
dontla@dontla-virtual-machine:~/桌面/test$ ls
test1 test1.c test2 test2.asm test2.o
dontla@dontla-virtual-machine:~/桌面/test$
1、用gdb查看test1文件的反汇编代码:
dontla@dontla-virtual-machine:~/桌面/test$ gdb ./test1
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test1...
(No debugging symbols found in ./test1)
(gdb) set disassembly-flavor intel
(gdb) disas main
Dump of assembler code for function main:
0x0000000000001129 <+0>: endbr64
0x000000000000112d <+4>: push rbp
0x000000000000112e <+5>: mov rbp,rsp
0x0000000000001131 <+8>: mov DWORD PTR [rip+0x2edd],0x2 # 0x4018 <x>
0x000000000000113b <+18>: mov DWORD PTR [rip+0x2ed7],0x3 # 0x401c <y>
0x0000000000001145 <+28>: mov edx,DWORD PTR [rip+0x2ecd] # 0x4018 <x>
0x000000000000114b <+34>: mov eax,DWORD PTR [rip+0x2ecb] # 0x401c <y>
0x0000000000001151 <+40>: add eax,edx
0x0000000000001153 <+42>: mov DWORD PTR [rip+0x2ebb以上是关于汇编语言入门的主要内容,如果未能解决你的问题,请参考以下文章