汇编学习(1),汇编之helloworld

2022-11-28 15:47:31 浏览数 (2)

本篇介绍

本篇作为汇编系列的开篇,就先研究下汇编如何写helloworld。

内容介绍

首先新建一个asm,写入内容如下:

代码语言:javascript复制
    ; hello.asm
    section .data
    msg db "hello, world",0
    section .bss
    section .text
    global main
main:
    mov rax,1
    mov rdi,1
    mov rsi, msg
    mov rdx,12
    syscall
    mov rax,60
    mov rdi,0
    syscall

代码的含义稍后介绍。 再新建一个makefile文件,内容如下:

代码语言:javascript复制
hello: hello.o
    gcc -o hello hello.o -no-pie
hello.o: hello.asm
    nasm -f elf64 -g -F dwarf hello.asm -l hello.lst

makefile可以这样看,目标hello依赖hello.o, 而hello.o又依赖hello.asm, 如果hello.asm的修改时间大于hello.o,那么hello.o下一行的命令就需要执行。

nasm就是汇编器,如果系统没有的话,需要安装一下:

代码语言:javascript复制
sudo apt install build-essential nasm

-f elf64用来指定输出文件的格式是elf64,-g表示需要包含debug信息,-F dwarf用来指定debug信息格式是dwarf,-l用来生成机器码和汇编的对应文件。 这时候执行make,就会看到生成了hello程序。

代码语言:javascript复制
-rwxrwxr-x 1 shanks shanks 16192 11月 15 00:38 hello*
-rw-rw-r-- 1 shanks shanks   190 11月 15 00:38 hello.asm
-rw-rw-r-- 1 shanks shanks   862 11月 15 00:38 hello.lst
-rw-rw-r-- 1 shanks shanks  2240 11月 15 00:38 hello.o
-rw-rw-r-- 1 shanks shanks   139 11月 15 00:36 makefile

直接执行hello, 就会看到如下输出:

代码语言:javascript复制
shanks@shanks-ThinkPad-T460s:~/Documents/04workspace/02asm/ch01$ ./hello
hello, world

接下来看下代码的含义吧。 汇编程序一般由data,bss,text 3个段构成, 前面加section就是定义这是某个段。 在section .data段用来定义变量,格式如下

代码语言:javascript复制
<variable name> <type> <value>

类型如下:

type

length

name

db

8 bits

Byte

dw

16 bits

Word

dd

32 bits

Double word

dq

64 bits

Quaword

名字用来引用对应内存的首地址,这样实际上可以分配的空间就可以是多个。比如代码中的msg,指向的是h地址,而h又是整个字符串的首地址,这样用msg就可以访问整个字符串了。可能已经注意到了在代码中,后面还加了一个0,整个主要是为了表示字符串结束了,并无其他含义。

text段也可以定义常量,格式如下:

代码语言:javascript复制
<constant name> equ <value>

比如
pi equ 3.14

section .bss用来定义没初始化的变量,格式如下:

代码语言:javascript复制
<variable name> <type> <name>

比如下面是定义了一个 20字的数组
dArray resd 20

类型如下:

type

length

names

resb

8 bits

Byte mov rax,1

代码语言:javascript复制
mov rdi,1
mov rsi, msg
mov rdx,12

resw|16 bits|Word resd|32 bits|Double word resq|64 bits|Quaword

section .txt就是代码段了,名字后加冒号就是定义了一个label,这样在代码中就可以作为跳转目标了。 再继续看显示代码:

代码语言:javascript复制
    mov rax,1
    mov rdi,1
    mov rsi, msg
    mov rdx,12
    syscall

rax 是系统调用编号,1对应的正好是write,rdi是write的第一个参数,也就是显示的目的,1对应的是标准输出,rsi是需要显示的字符串,对应write的第二个参数,rdx是write的第三个参数,也就是显示的数量。 syscall就是触发系统调用。

代码语言:javascript复制
    mov rax,60
    mov rdi,0
    syscall

接下来就是程序退出了,60对应的是exit,rdi是返回值。 这儿就能发现,系统调用的传参顺序是rdi,rsi,rdx,对应的系统调用编号查询网址。 最后再看下生成的lst文件:

代码语言:javascript复制
     1                                      ; hello.asm
     2                                      section .data
     3 00000000 68656C6C6F2C20776F-         msg db "hello, world",0
     3 00000009 726C6400           
     4                                      section .bss
     5                                      section .text
     6                                      global main
     7                                  main:
     8 00000000 B801000000                  mov rax,1
     9 00000005 BF01000000                  mov rdi,1
    10 0000000A 48BE-                       mov rsi, msg
    10 0000000C [0000000000000000] 
    11 00000014 BA0C000000                  mov rdx,12
    12 00000019 0F05                        syscall
    13 0000001B B83C000000                  mov rax,60
    14 00000020 BF00000000                  mov rdi,0
    15 00000025 0F05                        syscall

最左边是地址,中间是机器码,右边是汇编指令。

这样就完成了汇编helloworld的学习了。

0 人点赞