|
在汇编的最后,经常会看到:
movl $1, %eax
movl $0, %ebx
int $0x80
这实际上是调用了 Linux 的第 1 号系统调用 exit 函数。movl $1, %eax 中的 1 表示 1 号系统调用;0 表示传递给 exit 的参数。int $0x80 是调用中断 0x80 。
系统调用号可以在 /usr/include/asm/unistd.h 中找到。在较新的 Linux 发行版中,32 位系统和 64 位系统的调用号文件可能还会分别放在 /usr/include/asm/unistd_32.h 和 /usr/include/asm/unistd_64.h 中。这个文件的前几行为:
[C++] 纯文本查看 复制代码 #ifndef _ASM_X86_UNISTD_32_H
#define _ASM_X86_UNISTD_32_H
/*
* This file contains the system call numbers.
*/
#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
常用内存访问内核系统调用:
系统调用
| 描述
| brk
| 改变数据段长度
| mlock
| 禁止对内存部分进行分页
| mlockall
| 禁止对调用进程进行分页
| mmap
| 把文件或者设备映射到内存中
| mprotect
| 控制对内存区域的许可访问
| mremap
| 重新映射虚拟内存地址
| msync
| 同步文件和内存映射
| munlock
| 允许对内存部分进行分页
| munlockall
| 允许对调用进程进行分页
| munmap
| 取消文件或者设备在内存中的映射
|
常用设备访问内核系统调用:
系统调用
| 描述
| access
| 检查设备权限
| chmod
| 改变设备的权限
| chown
| 改变设备的所有关系
| close
| 关闭设备文件描述符
| dup
| 复制设备文件描述符
| fcntl
| 操作设备描述符
| fstat
| 获得设备的状态
| ioctl
| 控制设备的参数
| link
| 把新的名称分配给设备描述符
| lseek
| 重新定位读取/写入文件偏移量
| mknod
| 为设备创建新的文件描述符
| open
| 为设备或文件打开/创建文件描述符
| read
| 读取设备文件描述符
| write
| 写入设备文件描述符
|
常用文件系统系统调用:
系统调用
| 描述
| chdir
| 改变工作目录
| chroot
| 改变根目录
| flock
| 在打开的文件上应用或者删除建议锁(advisory lock)
| statfs
| 获得文件系统的统计数据
| getcwd
| 获得当前工作目录
| mkdir
| 创建目录
| rmdir
| 删除目录
| symlink
| 生成文件的新名称
| umask
| 设置文件创建掩码
| mount
| 挂载和卸载文件系统
| swapon
| 开始内存和文件系统的交换
| swapoff
| 停止内存和文件系统的交换
|
常用进程系统调用:
系统调用
| 描述
| acct
| 打开或者关闭进程计数
| capget
| 获得进程功能
| capset
| 设置进程功能
| clone
| 创建子进程
| execve
| 执行程序
| exit
| 终止当前进程
| fork
| 创建子进程
| getgid
| 获得组标识
| getgrp
| 获得/设置进程组
| getppid
| 获得进程标识
| getpriority
| 获得程序调度优先权
| getuid
| 获得用户标识
| kill
| 发送信号杀死进程
| nice
| 改变进程优先级
| vfork
| 创建子进程并且阻塞父进程
|
给系统调用传递参数:
如果只使用寄存器来传递参数,那么系统调用期望的输入参数顺序如下:
需要超过 6 个输入参数的系统调用使用不同的方法把参数传递给系统调用。EBX 寄存器用于保存指向输入参数的内存位置的指针,输入参数按照连续的顺序存储。系统调用使用这个指针访问内存位置以便读取参数。
测试程序: .section .data
output:
.ascii "This is a test message.\n"
output_end:
.equ len, output_end - output
.section .text
.global _start
_start:
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $len, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
运行与输出: $ ./syscall
This is a test message.
说明:
1. .equ 伪指令用来为符号赋值,这个值可以是绝对值也可以是相对值。它可以对一个符号使用一次到多次,使用一次则改变一次符号值。上面程序中,没有给字符串指定一个长度,而是利用 .equ 动态获得。在 .ascii 命令后面马上使用另外一个标签 output_end ,这个位置中什么都没有存储,它实际指向字符串末尾,通过两个标签的相减,从而获得了字符串的长度。
2. 程序中,我们调用的是 write() 这个系统调用,其原型是:
write (int fd, const void *buf, size_t count);
从左到右,它的 3 个参数依次放入上面所述的寄存器(EBX, ECX, EDX)中。
EBX : 文件描述符。这里是标准输出 STDOUT ,值为 1。
ECX : 指向要写入的字符串的指针。
EDX : 要写入的字符串长度。
系统调用返回值:
系统的返回值存放在 EAX 寄存器中。一定要了解返回值的类型,一些系统调用会返回怪异的数据类型。如上面的 write(),返回 ssize_t 。实际上,ssize_t 不是标准汇编语言数据类型,它本身由 typedef 定义,实际上是个整型数据。
下面程序分别获取 getpid, getuid, getgid 这 3 个系统调用的返回值,这 3 个系统调用所对应的系统调用号分别为20,24,47。下面时测试代码: .section .bss
.lcomm pid, 4
.lcomm uid, 4
.lcomm gid, 4
.section .text
.global _start
_start:
movl $20, %eax
int $0x80
movl %eax, pid
movl $24, %eax
int $0x80
movl %eax, uid
movl $47, %eax
int $0x80
movl %eax, gid
end:
movl $1, %eax
movl $0, %ebx
int $0x80
在调试器中观察: (gdb) x/d &pid
0x80490a4 <pid>: 3347
(gdb) x/d &uid
0x80490a8 <uid>: 1000
(gdb) x/d &gid
0x80490ac <gid>: 1000
复杂的系统调用返回值
有时候系统调用返回涉及 C 样式数据结构的复杂数据.
下面测试 sysinfo 这个系统调用的返回信息。sysinfo() 返回系统如何配置以及有什么可用资源的信息。man 一下,可以看到它的原型为: #include <sys/sysinfo.h>
int sysinfo (struct sysinfo *info);
它只有一个指向 struct sysinfo 结构体的指针。当函数成功返回时,它会将系统的相关值返回到结构体的特定成员中。所以,我们在汇编里也要相应的创建这个结构。这个结构定义如下:
[C++] 纯文本查看 复制代码 struct sysinfo {
long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* swap space still available */
unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding for libc5 */
};
测试程序: .section .data
result:
uptime:
.int 0
loads1:
.int 0
loads2:
.int 0
loads3:
.int 0
totalram:
.int 0
freeram:
.int 0
sharedram:
.int 0
bufferram:
.int 0
totalswap:
.int 0
freeswap:
.int 0
procs:
.byte 0x00, 0x00
totalhigh:
.int 0
freehigh:
.int 0
memunit:
.int 0
charf:
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
retu:
.int 0
.section .text
.global _start
_start:
nop
movl $result, %ebx
movl $116, %eax
int $0x80
movl $0, %ebx
movl $1, %eax
int $0x80
|
|