locate unistd_64
less /usr/include/x86_64-linux-gnu/asm/unistd_64.h
sys_write
在32位下是4,在64位下是1。int 80H
中断进行系统调用,而64位下需要用syscall
指令进行系统调用。eax
,调用参数按照ebx
,ecx
,edx
的顺序写入寄存器,系统调用返回值写入eax
寄存器。而64位程序,系统调用号传入rax
,而各个参数按照rdi
,rsi
,rdx
的顺序写入寄存器,系统调用返回值写入rax
。我们的目的是在屏幕上输出HelloWorld,在标准输出上写入该字符串即可。
使用sys_write
系统调用,我们可以man 2 write
,查看write
的传参。
也可以直接查看内核syscall头文件:
root@wilcohuang:/usr/src# cat linux-headers-4.4.0-91/include/linux/syscalls.h | grep -C 1 'sys_write'
unsigned long vlen);
asmlinkage long sys_write(unsigned int fd, const char __user *buf,
size_t count);
第一个参数是文件描述符,第二个参数数字符串地址,第三个参数是字符串长度。
有了这些,下面通过两个例子来展示32位和64位系统调用
在64位环境下运行32位汇编,需要搞一些事情:
使用如下命令才能汇编:
root@wilcohuang:/data/home/wilcohuang/test-asm# as -32 -gstabs -o syscall_32.o syscall_32.asm
root@wilcohuang:/data/home/wilcohuang/test-asm# ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -o syscall_32 syscall_32.o
如果你使用了上面了命令汇编完成后,执行程序报:-bash: ./syscall: cannot execute binary file: Exec format error
呵呵,我猜你肯定用了坑爹的WSL:)
root@wilcohuang:/data/home/wilcohuang/test-asm# c
;.code32 (这句可加可不加)
.section .data
message:
.ascii "Hello, World!\n"
length = . - message
.section .text
.global _start
_start:
mov $4, %eax
mov $1, %ebx
mov $message, %ecx
mov $length, %edx
int $0x80
mov $1, %eax
xor %ebx, %ebx
int $0x80
.section .data
message:•
.ascii "Hello, World!\n"
length = . - message
.section .text
.global _start
_start:
nop
mov $0x1, %rax
mov $0x1, %rdi
mov $message, %rsi
movq $length, %rdx
syscall
mov $0x3c, %rax
xor %rdi, %rdi
syscall
在x86-64模式下,新增了rip相对寻址的功能,这是为了更方便的产生地址无关的代码。
所以,取message的地址也可以像下面这样:
.section .data
message:•
.ascii "Hello, World!\n"
length = . - message
.section .text
.global _start
_start:
nop
mov $0x1, %rax
mov $0x1, %rdi
lea message(%rip), %rsi
movq $length, %rdx
syscall
mov $0x3c, %rax
xor %rdi, %rdi
syscall
ok,今天到此位置,回家睡觉。