首页 > 系统相关 >如何在Linux下写汇编

如何在Linux下写汇编

时间:2023-05-06 12:32:32浏览次数:59  
标签:汇编 调用 寄存器 参数 Linux DOS 下写 hello


http://docs.cs.up.ac.za/programming/asm/derick_tut/

1.NASM编译器

目前Linux下的汇编器主要有:as、as86和gas,但是本文使用的是NASM(The Netwide Assembler)。它使用Intel形式的汇编格式,和Intel形式相对的是AT&T形式的汇编格式。

2.Linux下汇编介绍

2.1DOS和Linux下汇编的主要不同

(1)DOS下的汇编,主要通过 int 21h 中断来实现各种DOS功能调用,而BIOS调用则是主要通过 int 10h 和 int 16h 中断来实现。但是在Linux中, 所有以上的功能调用都是通过内核来实现的。因此所有的功能都是通过“系统调用”来实现,而我们可以通过使用 int 80h 中断来实现系统调用。其中,Linux大约有190个左右的系统调用,比DOS下的要少。

(2)Linux是一个真正32位保护模式的操作系统,因此我们使用的是32为的汇编程序。32位汇编程序运行我们使用全部的内存(4G),这意味着我们不用在考虑段基址了,也不用在修改和操作段寄存器了,从某种程度上来说,变的更容易了。

(3)在32为汇编程序中,我们可以使用32位的寄存器 EAX、EBX、ECX等代替传统的16位寄存器 AX、BX、CX等寄存器。

2.2Linux下汇编的编写

(1)数据段 (.data section)

数据段主要用来“声明初始化数据”,换句话说,是用来定义常“变量”的,这个“变量”主要是指在程序中不会一直变化,定义后就会保持不变。通常数据段都是用来定义常用的标号,比如:文件名、缓存大小等等,当然,你也可以使用 EQU 这个指令来实现。定义常“变量”可以使用的指令有:DB、DW、DD、DQ和DT,例如:


section    .data
    message:        db    'Hello World!'    ;声明一个字节类型(byte)的字符数组
    msglength:    equ    12            ;声明字节数组的长度
    buffersiz:        dw    1024            ;声明一个1024大小(字)的缓存


(2)变量段(.bss section)

该段主要是用来定义变量的,这里可以使用的指令有:RESB、RESW、EWSD、EWSQ和REST等,这些指令可以用来预留一些内存空间给定义的变量。例如:


section    .bss
    filename:        resb    255    ;定义255个字节的内存空间
    number:        resb    1    
    bignum:        resw    1    ;定义1个字的内存空间(1字=2字节)
    realarray:        resq    10    ;定义10个reals大小的数组

(3)代码段(.text section)

这部分主要是用来写汇编代码的,通常,代码段必须以 global _start(_start为标号,自定义)开头,他的主要含义是告诉内核程序是从这里开始的,内核在看到这部分变编译后的信息,就会将相关的CS:IP指向这里,然后开始执行程序。就和C函数中的main()函数类似。例如:



section    .text
    global    _start

    _start:
        pop    ebx    ;这里是程序开始执行的入口
        .
        .
        .



2.3 Linux下的系统调用

Linux下的系统调用和DOS下的系统调用类似,主要通过以下几个步骤:

(1)将你的系统调用号放进EAX中(因为我们是在32位下,所以使用32位的EAX寄存器)。

(2)设置系统调用参数,并且依次将参数放进EBX、ECX、EDX、ESX、EDI和EBP。

(3)调用相关中断(对应Linux来说是 80h;对于DO来说是 21h)。

(4)最后的调用结果会返回到EAX中保存。

说明:第二步中的参数是按照顺序放置的,比如第一个参数放在EBX中,第二个参数放在ECX中,…第5个参数放在EDI中。但是只有Linux2.4以后的版本才至此第6个参数EBP,以上的版本只支持前5个参数。如果有多于6个参数,则EBX用来存放参数列表在内存中的位置,但是通常情况下是不会多于6个参数的。

例如:


mov    eax,1    ;exit系统调用
    mov    ebx,0    ;返回参数是0
    int    80h    ;使用80h中断,然后系统内核便开始调用函数


从上述例子我们可以看出,exit()函数的系统调用号是1,但是我们怎么知道其他的系统调用号呢?并且他们的参数是如何?首先,所有的系统调用都位于 /usr/inlucde/(asm/asm-generic)/unistd.h中,其中也包含了他们的系统调用号(比如exit对应的是1)。但是为了方便,我们可以在下面的Linxu系统调用表中查看系统调用所对应的编号。当然,我们可以通过man 2 系统调用函数(man 2 exit)来查看该系统调用的具体情况。

2.4 “Hello Word!”

还是经典的“Hello Word!”,为了将其打印出来,我们使用标准输出(STDOUT),其文件描述符为1,以下是完整的程序:



section    .data
    hello:    db    'Hello World!'    ;字符
    helloLen    equ    $-hello            ;字符的长度

section    .text
    global    _start

_start:
    mov eax,4    ;sys_write的系统调用
    mov ebx,1    ;参数1,文件描述符,stdout是1
    mov ecx,hello    ;字符的起始地址
    mov edx,helloLen    ;字符的长度

    int 80h        ;系统调用

    mov eax,1    ;sys_exit的系统调用
    mov ebx,0    ;sys_exit的返回参数0,表示无错误
    int 80h



我们在vim中书写上述代码,然后将其保存为 hello.asm。

2.5 编译与连接

(1)打开控制终端

(2)将当前目录设置成 hello.asm同一目录

(3)使用NASM编译 hello.asm程序: nasm –f elf hello.asm

(4)使用 ld –s –o hello hello.o 指令连接程序

(5)运行程序 ./hello

程序将会输出:“Hello World!”

3 进阶

3.1 命令行参数和栈

从DOS程序中获取命令行参数是一件痛苦的经理,因为这要考虑到PSP和段寄存器。但是,在Linux中,这一切都显示那么简单,但程序开始运行时,所有的参数都会被放到栈中,如果我们想要获取他们,只需pop即可。

假设现在有一个program程序,他有三个参数:


./program foo bar 42


 

则现在程序的栈是如下形式:

如何在Linux下写汇编_linux

现在,我们可以写一个获取其三个参数的程序出来:


section .text
    global _start

_start:
    pop eax    ;获取参数个数:3
    pop ebx    ;获取程序名称:program
    pop ebx    ;获取第一个参数:foo
    pop ecx    ;获取第二个参数:bar
    pop edx    ;获取第三个参数:42

    mov eax,1
    mov ebx,0
    
    int 80h    ;退出


3.2 “过程”和跳转

NASM中没有TASM中的过程定义,但是可以使用标号来代替。例如:

如何在Linux下写汇编_汇编_02

其中有一点需要注意:

你可以 jump 到一个标号,但是你必须 call 一个 过程。

假设现在有如下代码:


if(AX == 'w') {
 writeFile();
} else {
 doSomethingElse();
}


那么其对应的汇编将是如下形式:



cmp    AX,'w'        ;
jne    skipWrite        ;
call    writeFile        ;
jmp    outOfThisMess    ;

skipWrite:
    call doSomethingElse
outOfThisMess:
    ...        ;


3.3 Linux和DOS汇编程序对比

3.3.1 “Hello World”程序输出对比

如何在Linux下写汇编_代码段_03

对比说明:

(1)DOS下的前三行,在Linux中是不需要的,因为Linux是一个32位的保护模式的操作系统,因此所有的寄存器和分页都已经是32位的,无需特殊处理,因此就不需要段寄存器,并且也不需要设置栈的大小。

(2)Linux下的NASM和DOS下的TASM/MASM的语法区别:

1) NASM使用SECTION .DATA而不是MASM中的.DATA。

2) NASM运行我们直接使用EQU定义常量,例如:bufferlen : equ 400,那么在程序中bufferlen就等于400,这意味着我们不必使用括号来去该地址的内容。

3) NASM使用$表示当前行偏移SECTION的地址,如:hello: db 'Hello world!',10 helloLen: equ $-hello 中的$就表示当前行的偏移地址,$-hello表示当前行和上一行相差的距离,即字符的长度。

4) Linux下可以直接使用字符长度打印出字符,不必像DOS那样采用$-terminated的形式。

5) 为了打印出字符后换行,在Linux中需要加一个linefeed character(10),但是在DOS下,必须使用一个linefeed character(10)和一个carriage return(13)。

6) Linux下的代码段叫.TEXT,而DOS下的叫.CODE

7) Linux下的代码段,必须以GLOBAL XXX开始,这样做的目的是告诉系统内核程序开始执行的地址。

8) 由于Linux下无需考虑段寄存器,所以Linux下的汇编代码没有ASSUME关键字。

9) Linux下代码段(.text section)的结束不需要想DOS那样 END XXX。

(3) DOS下汇编程序中,START标签的前两句主要表示:DS寄存器指向 data segment;CS寄存器指向code segment。Linux直接使用32位寄存器,所以不需要这么设置。

(4) 在16位的DOS汇编程序中,我们使用16位的寄存器 AX、BX、CX、DX等。但是在32位的Linux中,我们使用扩展寄存器 EAX、EBX、ECX、EDX等。其中 AX 是 EAX 的低16位,AH 是 AX的高8位,AL 是 AX 的底8位,没有EAL这种寄存器。

(5) 在DOS中,如果我们想将变量的地址放进寄存器中,我们必须使用offset关键字来将其放进正确的段寄存器中。但是在Linux中不需要如此。

(6) 在DOS中,我们使用 int 21h 中断来调用 DOS 服务来打印字符。但是在Linux中,我们使用 int 80h 中断来调用 系统调用 来打印字符。并且其参数放置位置不同(参见3.1)。

(7) 退出调用的不同之处和(6)类似。

3.3.2 命令参数及文件写入对比

如何在Linux下写汇编_寄存器_04

如何在Linux下写汇编_代码段_05

如何在Linux下写汇编_汇编_06

标签:汇编,调用,寄存器,参数,Linux,DOS,下写,hello
From: https://blog.51cto.com/u_14011026/6249468

相关文章

  • 查看Linux系统版本内核命令大全
    目录命令一:查看当前系统发行版本详细信息命令二:查看当前系统内核信息命令三:查看当前系统版本信息命令四:查看CPU相关信息命令五:查看系统位数Linux系统内核、发行版本有很多,那么如何查看当前Linux系统的内核信息、Linux系统发行版本等信息呢?Linux百科网分享查询Linux系统详细信息的方......
  • linux局域网通信软件都有哪些?要如何选择?
    出于安全性考虑和上级单位要求,不少原本使用Windows系统电脑的单位都在逐渐把单位内的电脑替代为linux系统电脑,但由于原先使用的局域网通信软件没有做linux适配,无法使用,只能替换为能在linux系统上使用的局域网通信软件。那么linux局域网通信软件如何选择?可以参考以下几点:功能不同的l......
  • linux中查看哪个端口是否被占用
    1.netstat-anp|grep端口号如下,我以3306为例,netstat-anp|grep3306(此处备注下,我是以普通用户操作,故加上了sudo,如果是以root用户操作,不用加sudo即可查看),如下图1: 图1中主要看监控状态为LISTEN表示已经被占用,最后一列显示被服务mysqld占用,查看具体端口号,只要有如图这一行就表......
  • linux 通过命令行(包括ssh)关闭屏幕
    题外话:不得不说现在百度的搜索真的烂,除了广告,有用的信息一点也搜不到,bing倒是广告少,照样也搜不到有用信息,谷歌虽然作恶不少,某些技术还是可以的,但是国内不通过特殊方法又使用不了,解决方法:1.找谷歌的镜像站,但是不好找,就算找到了,可能过几天就失效了;2.找一些小众的搜索......
  • Linux下搭建Python2.7环境
    Python(英语发音:/ˈpaɪθən/),是一种面向对象、解释型计算机程序设计语言,由1989年底发明。python具有简单、易学、免费、开源、可移植性、解释性、可嵌入性等特点,是一种不受局限、跨平台的开源编程语言,它功能强大且简单易学,因而得到了广泛应用和支持。1.Python下载Pyt......
  • Linux安装rabbitMQ常用命令
    1.拉取最新的rabbitMQdockerpullrabbitmq:management2.容器启动rabbitMQdockerrun-d--hostnamemy-rabbit--namerabbit-p15672:15672-p5672:5672rabbitmq:management其中:     --hostname:指定容器主机名称     --name:        指定容器名称  ......
  • Linux-基础题
    Linux-基础题Linux命令格式是什么样?Linux命令 可选的参数 你要操作的对象#显示根目录下的文件内容ls/#显示根目录下文件内容的详细信息,以及文件大小ls-l-h/#显示当前目录下的文件大小ls其实这个命令后面跟了一个文件夹ls.Linux命令必须添加参数才能执......
  • linux设备树-LCD触摸屏设备驱动
    ----------------------------------------------------------------------------------------------------------------------------内核版本:linux5.2.8根文件系统:busybox1.25.0u-boot:2016.05-------------------------------------------------------------------------------......
  • LINUX
    LINUX开始整整学过的东西,忘太多了。。。。。。。。。。修改日期命令使用date命令修正系统时间,改为当前日期时间date-s"2022-09-2717:00:00"shutdown+各种关机重启命令使用shutdown命令发出警告信息,查看其他控制台上的用户是否收到信息。shutdown-r+2"shutDownNow......
  • Linux 将另一服务器上的文件或文件夹复制到当前服务器
    1.文件复制1.1 将本地文件拷贝到远程  scp文件名用户名@计算机IP或者计算机名称:远程路径例如:scp/root/install.*[email protected]:/usr/local/src1.2 从远程将文件拷回本地scp用户名@计算机IP或者计算机名称:文件名本地路径例如:[email protected]......