汇编语言入门

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 63 22:32 test
-rw-rw-r-- 1 dontla dontla 151 63 22:08 test.asm
-rw-rw-r-- 1 dontla dontla 848 63 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) 

参考解决办法:汇编报错:Warning: Cannot insert breakpoint 1. Cannot access memory at address 0x1135 解决办法(先不打断点run一遍)

查看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以上是关于汇编语言入门的主要内容,如果未能解决你的问题,请参考以下文章

c语言入门到入门,hello world篇

反射机制入门

反射机制入门

C语言代码片段

使用 Pygments 检测代码片段的编程语言

反射机制入门