[0x02] NASM汇编 [输出hello world!]

nasm官方文档:https://www.nasm.us/xdoc/2.14.03rc2/nasmdoc.pdf

当遇到问题时,可以在文档中查询,文档是英文的,需要一定的英语阅读能力。

下面是一个输出的例子。

; hello.asm
section .data
    msg db 'hello, world!',0xa
    len equ $-msg

section .text
global _start
_start:
    mov rax, 4
    mov rbx, 1
    mov rcx, msg
    mov rdx, len
    int 0x80

    mov rax, 1
    int 0x80

在ubuntu 64位的机器上编译运行:

nasm -f elf64 -o hello.o hello.asm
ld -o hello hello.o
./hello

这个时候会在控制台中看到输出结果hello, world!

程序分析:

section是程序段的意思,首先定义了.data数据段,在data数据段中,定义了2个变量msg和len。

.text段中,_start作为程序的入口点,当然可以换成其他的名字。

之后,使用了mov指令,对寄存器rax,rbx,rcx,rdx等赋值,最后执行int 0x80,进行系统调用。

我们可以使用系统调用,就是系统函数。rax保存系统调用号,4是System_write的系统调用号,可以在文件/usr/include/x86_64-linux-gnu/asm/unistd_32.h查看系统调用号。不同的系统位置可能不同。

使用man 2 write查看write的用法,找到write函数的原型:

ssize_t write(int fd, const void *buf, size_t count);

fd是文件描述符,buf是指向要输出内容的指针,而count是输出的数量,按字节计数。

mov rbx, 1
mov rcx, msg
mov rdx, len

rbx,rcx,rdx保存系统调用的参数,即fd=1,buf=msg,count=len

当参数更多时,使用下面的寄存器保存系统调用的参数:rbx,rcx,rdx,rsi,rdi,rbp

int 0x80指令进行系统调用。

 

不过,现在可以使用syscall指令来替换int 0x80,这时候,规则有了变化,rax依然保存系统调用号,而系统调用的参数使用下面的寄存器,用户模式的系统调用依次传递的寄存器为:rdi,rsi,rdx,rcx,r8和r9;而内核接口的系统调用依次传递的寄存器为:rdi,rsi,rdx,r10,r8和r9。这里只有第4个参数不同。我们使用的是用户模式的系统调用,因此,上面的hello.asm代码可以修改为下面这样:

; hello2.asm
seciont .data
    msg db 'hello, world',0xa
    len equ $-msg

section .text
global _start
_start:
    mov rax, 1
    mov rdi, 1
    mov rsi, msg
    mov rdx, len
    syscall

    mov rax, 60
    syscall

这里发生了一些变化,当使用syscall进行系统调用时,需要使用64位的系统调用号,在文件/usr/include/x86_64-linux-gnu/asm/unistd_64.h查看64位的系统调用号。

write的系统调用号是1,而exit的系统调用号是60.

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值