X86处理器汇编技术系列6
第44部分-Linux x86 64位汇编SIMD整数
单指令多数据(SIMD, Single Instruction Multiple Data)。
MMX整数
提供3种新的整数类型。
64位打包字节整数。
64位打包字整数。
64位打包双字节整数。
8个字节整数,4个字整数或2个双字整数都可以打包到单一的64位MMX寄存器中。
MMX寄存器被映射到FPU寄存器。
SSE整数
流化SIMD扩展(SSE,Streaming SIMD Extension)技术提供用于处理打包数据的8个128位XMM寄存器(名为XMM0到XMM7)
SSE2技术提供4个额外的打包带符号整数数据类型:
128位打包字节整数
128位打包字整数
128位打包双字整数
128位打包四字整数
MOVDQA和MOVDQU指令用于把128位数据传送到XMM寄存器中。
第45部分-Linux x86 64位汇编 BCD
二进制编码的十进制(BCD, Binary Coded Decimal), 用于简化对使用十进制数字的设备。
每个BCD值都是一个无符号8位整数,值的范围是0到9.
在BCD中,大于9的8位值被认为是非法的。8位有些浪费,出现了打包的BCD,使用4位表示一个值。
二进制编码的十进制(BCD,Binary Coded Decimal)格式是用于处理人可读的数字常见方法,处理器中可以快速处理这种格式。
很多高级的BCD处理操作位于FPU中,但是处理器会包含一些简化的指令。我们来看下基本的BCD运算指令。
不打包BCD运算
不打包的BCD值:是一个字节中包含单个十进制位(0到9).
应用程序要对不打包的BCD值执行数学操作时,应用程序假设结果也应该按照不打包BCD格式存储。
X86处理器提供了专门的指令用于从一般数学操作生成不打包BCD值。
把二进制运算结果转换为不打包BCD格式的指令有4条:
AAA:调整加法操作的结果
AAS:调整减法操作的结果
AAM:调整乘法操作的结果
AAD:准备除法操作的被除数
这些指令必须和一般无符号整数指令ADD,ADC,SUB,MUL和DIV组合一起使用。
AAA,AAS,AAM指令在各自的操作之后,把二进制结果转换为不打包BCD格式,AAD指令有些不同,在DIV指令之前使用它,用于准备被除数以便生成不打包BCD结果。
这个指令都使用一个隐含的操作数——AL寄存器。AAA,AAS,AAM指令假设前一个操作的结果存放在AL寄存器,并且把这个值转换为不打包BCD格式。
不过,坏消息是由于这些指令不是经常使用,所以在64位处理器中已经不支持了。
`aaa' is not supported in 64-bit mode
打包BCD运算
打包BCD是一个字节中包含两个十进制数字。
在64位处理器中叶已经不支持了。
第46部分-Linux x86 64位汇编 斐波那契
斐波那契数列
斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波那契数列以如下被以递推的方法定义:F(1)=1,F(2)=1, F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从 1963 年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。
C语言版本
-
#include "stdio.h"
-
unsigned long Fibon1(int n)
-
{
-
if (n == 1 || n == 2)
-
{
-
return 1;
-
}
-
else
-
{
-
return Fibon1(n - 1) + Fibon1(n - 2);
-
}
-
}
-
int main()
-
{
-
int n = 0;
-
unsigned long ret = 0;
-
//scanf("%d", &n);
-
n=50;
-
ret = Fibon1(n);
-
printf("ret=%lu\n", ret);
-
return 0;
-
}
可以直接编译运行。
#gcc -o fibo-c fibo.c
# time ./fibo-c
ret=12586269025
real 1m9.897s
user 1m9.931s
sys 0m0.020s
Nasm版本
-
extern printf ;//调用外部的printf函数
-
section .data
-
fmt db "result is: %lu ", 0xa
-
-
global _start
-
-
fibo:
-
-
push rbx
-
push rdx
-
cmp rax, 1
-
je _get_out
-
cmp rax, 2
-
je _get_out;//相当于if(n == 1 || n == 2) return 1;
-
-
mov rdx, rax;//相当于if(n!=1&&n!=2),先保存rax
-
sub rax, 1
-
call fibo;//相当于fibo(n-1)
-
mov rbx, rax;//保存fibo(n-1)结果到rbx
-
-
mov rax, rdx;//获取rax值。
-
sub rax, 2
-
call fibo;//相当于fibo(n-2)
-
mov rcx, rax;//保存fibo(n-2)到rbx
-
-
mov rax, rbx
-
add rax, rcx;//fibo(n-1)+fibo(n-2)
-
-
pop rdx
-
pop rbx
-
ret
-
-
_get_out:
-
pop rdx
-
pop rbx
-
mov rax, 1
-
ret;//直接返回fibo函数
-
-
_start:
-
mov rax, 50 ;//求数列中第七个数
-
call fibo
-
mov rdi,fmt
-
mov rsi,rax
-
call printf
-
-
mov rax,60
-
syscall
nasm -f elf64 -o fibo.o fibo.asm
ld -o fibo fibo.o -lc -I /lib64/ld-linux-x86-64.so.2
# time ./fibo
result is: 12586269025
real 0m41.641s
user 0m41.639s
sys 0m0.000s
Gas版本
-
.extern printf ;//调用外部的printf函数
-
.section .data
-
fmt: .ascii "result is: %lu \n"
-
-
.global _start
-
-
fibo:
-
-
push %rbx
-
push %rdx
-
cmp $1,%rax
-
je _get_out
-
cmp $2,%rax
-
je _get_out;//相当于if(n == 1 || n == 2) return 1;
-
-
mov %rax, %rdx;//相当于if(n!=1&&n!=2),先保存rax
-
sub $1,%rax
-
call fibo;//相当于fibo(n-1)
-
mov %rax, %rbx;//保存fibo(n-1)结果到rbx
-
-
mov %rdx, %rax;//获取rax值。
-
sub $2,%rax
-
call fibo;//相当于fibo(n-2)
-
mov %rax, %rcx;//保存fibo(n-2)到rbx
-
-
mov %rbx, %rax
-
add %rcx, %rax;//fibo(n-1)+fibo(n-2)
-
-
pop %rdx
-
pop %rbx
-
ret
-
-
_get_out:
-
pop %rdx
-
pop %rbx
-
mov $1,%rax
-
ret;//直接返回fibo函数
-
-
_start:
-
mov $50,%rax ;//求数列中第七个数
-
call fibo
-
mov $fmt,%rdi
-
mov %rax,%rsi
-
call printf
-
-
mov $60,%rax
-
syscall
编译连接:
as -g -o fibo_att.o fibo_att.s
ld -o fibo_att fibo_att.o -lc -I /lib64/ld-linux-x86-64.so.2
# time ./fibo_att
result is: 12586269025
real 0m41.625s
user 0m41.623s
sys 0m0.000s
性能差异
|
Nasm汇编 |
Gas汇编 |
C语言 |
C语言-O1 编译优化 |
C语言-O2 编译优化 |
执行时间 |
41.6s |
41.6s |
1m0.876s |
NA,异常 |
NA,异常 |
可以看到汇编程序编译后的明显性能优势。性能提升31.5%。
使用GCC的-O参数优化后会影响程序本身的功能。
第47部分- Linux x86 64位汇编 C调用汇编
这个部分我们直接以例子来展示。
示例
定义casm.c文件如下:
-
-
-
int main() {
-
char* str = "Hello World\n";
-
int len = strlen(str);
-
printHelloWorld(str, len);
-
return 0;
-
}
调用printHelloWorld函数,我们知道在X86处理中调用函数的前6个参数位于寄存器rdi, rsi, rdx, rcx, r8 and r9中,其他通过栈来实现。这样printHelloWorld函数可以通过rdi,rsi来获取前两个参数。
Nasm汇编器语法
再来看汇编文件,定义汇编文件printHelloWorld.s如下:
-
global printHelloWorld
-
section .text
-
printHelloWorld:
-
;; 参数一
-
mov r10, rdi
-
;; 参数二
-
mov r11, rsi
-
;; 调用write系统调用
-
mov rax, 1
-
mov rdi, 1
-
mov rsi, r10
-
mov rdx, r11
-
syscall
-
ret
nasm -f elf64 -o printHelloWorld.o printHelloWorld.asm
gcc printHelloWorld.o casm.c -o casm
然后执行我们可以得到如下:
#./casm
Hello World
Gas汇编器语法
修改成gas的AT&T语法
printHelloWorld.s如下:
-
.global printHelloWorld
-
.section .text
-
printHelloWorld:
-
mov %rdi, %r10
-
mov %rsi, %r11
-
mov $1,%rax
-
mov $1,%rdi
-
mov %r10,%rsi
-
mov %r11,%rdx
-
syscall
-
ret
as -o printHelloWorld.o printHelloWorld.s
gcc printHelloWorld.o casm.c -o casm
得到的结果是一样的。
示例二求平方
先定义个求平方的汇编函数在文件square.s中如下:
-
.type square, @function
-
.globl square
-
square:
-
movq %rdi,%rax
-
imul %rax, %rax
-
ret
然后C语言去调用
-
#include <stdio.h>
-
-
int main()
-
{
-
int i = 2;
-
int j = square(i);
-
printf("The square of %d is %d\n", i, j);
-
-
j = square(10);
-
printf("The square of 10 is %d\n", j);
-
return 0;
-
}
编译
gcc -o inttest inttest.c square.s
我们看到第一次使用了C变量i,第二次使用了立即数10。返回值被赋值给C变量j。这里我们要知道的是函数传递的时候前面六个寄存器是:
rdi,rsi,rdx,rcx,r8,r9.
示例三返回字符串
字符串比较长,只能通过返回字符串指针的方式来进行了。
这里需要提醒的事C/C++程序中处理器字符串时候,字符串必须使用空字符结尾。
默认情况下,C程序假设函数返回值是整数值。需要通知编译器这个函数范湖字符串指针,通过创建函数调用的原型来完成这个任务。
原型在使用函数之间定义。
以获取CPUID字符串为例子。
定义cpuidfunc.s汇编文件如下:
-
.section .bss
-
.comm output, 13
-
.section .text
-
.type cpuidfunc, @function
-
.globl cpuidfunc
-
cpuidfunc:
-
movq $0, %rax
-
cpuid
-
movq $output, %rdi
-
movq %rbx, (%rdi)
-
movq %rdx, 4(%rdi)
-
movq %rcx, 8(%rdi)
-
movq $output, %rax
-
ret
这里定义了一个缓冲区,将被主C程序访问。
定义C文件stringtest.c如下:
-
#include <stdio.h>
-
-
char *cpuidfunc(void);
-
-
int main()
-
{
-
char *spValue;
-
spValue = cpuidfunc();
-
printf("The CPUID is: '%s'\n", spValue);
-
return 0;
-
}
编译:
gcc -o stringtest stringtest.c cpuidfunc.s -no-pie
示例三返回浮点值
浮点返回值是特殊情况。
整数和字符串返回值都是使用EAX寄存器把值从汇编语言函数返回到发出调用的C程序。
C样式使用xmm0寄存器在函数之间交换浮点值。函数把返回值存放到FPU堆栈中,然后调用程序负责把返回值弹出堆栈并且把它赋值给变量。
定义汇编函数areafunc.s如下:
-
.section .text
-
.type areafunc, @function
-
.globl areafunc
-
areafunc:
-
fldpi
-
push %rdi
-
fild (%rsp)
-
fmul %st(0), %st(0)
-
fmul %st(1), %st(0)
-
fstps (%rsp)
-
movq (%rsp),%xmm0
-
popq %rdi
-
ret
先加载π到fpu堆栈中。然后加载半径到st0,然后半径自己相乘,最后与π相乘。最后要把结果放到xmm0中才可以。
定义C文件floattest.c如下:
-
#include <stdio.h>
-
-
float areafunc(int);//声明函数
-
-
int main()
-
{
-
int radius = 10;
-
float result;
-
result = areafunc(radius);
-
printf("The result is %f\n", result);
-
-
result = areafunc(2);
-
printf("The result is %f\n", result);
-
return 0;
-
}
编译:
gcc -o floattest floattest.c areafunc.s
输出结果如下:
# ./floattest
The result is 314.159271
The result is 12.566371
示例四混合数据类型输入值
以一个双精度浮点输入值和一个整数输入值的汇编语言函数为例子。
汇编文件testfunc.s如下:
-
.section .text
-
.type testfunc, @function
-
.globl testfunc
-
testfunc:
-
pushq %rdi;//第一个整型参数位于rdi寄存器中
-
filds (%rsp)
-
movq %xmm0, %rsi;//浮点参数位于xmm0寄存器中
-
pushq %rsi
-
fldl (%rsp)
-
fmul %st(1),%st(0)
-
fstpl (%rsp)
-
movq (%rsp),%xmm0
-
popq %rsi
-
popq %rdi
-
-
ret
第一个参数是双精度浮点值,第二个参数是整数。
定义C语言文件prog.c如下:
-
#include <stdio.h>
-
-
double testfunc(double, int);
-
-
int main()
-
{
-
double data1 = 3.14159;
-
int data2 = 10;
-
double result;
-
-
result = testfunc(data1, data2);
-
printf("The proper result is %f\n", result);
-
return 0;
-
}
编译文件如下:
gcc -g -o prog prog.c testfunc.s
示例五超6个参数输入
这里共8个参数。计算表达式:((43.65/22+(76.34*3.1))/((12.43*6)-(140.2/94.21))
定义汇编文件fpmathfunc.s
-
.section .text
-
.type fpmathfunc, @function
-
.globl fpmathfunc
-
fpmathfunc:
-
-
push %rdi;//第一个整数参数value2, 56(%rsp)
-
push %rsi;//第二个整数参数value6, 48(%rsp)
-
movq %xmm0, %rsi
-
push %rsi;// 第一个浮点参数value1, 40(%rsp)
-
movq %xmm1, %rsi
-
push %rsi;// 第二个浮点参数value3, 32(%rsp)
-
movq %xmm2, %rsi
-
push %rsi;// 第三个浮点参数value4, 24(%rsp)
-
movq %xmm3, %rsi
-
push %rsi ;// 第四个浮点参数value5, 16(%rsp)
-
movq %xmm4, %rsi
-
push %rsi ;// 第五个浮点参数value7,8(%rsp)
-
movq %xmm5, %rsi
-
push %rsi ;// 第六个浮点参数value8,(%rsp)
-
flds 40(%rsp)
-
fidiv 56(%rsp)
-
flds 32(%rsp)
-
flds 24(%rsp)
-
fmul %st(1), %st(0)
-
fadd %st(2), %st(0)
-
flds 16(%rsp)
-
fimul 48(%rsp)
-
flds 8(%rsp)
-
flds (%rsp)
-
fdivrp
-
fsubr %st(1), %st(0)
-
fdivr %st(2), %st(0)
-
fsts (%rsp)
-
movq (%rsp),%xmm0
-
//恢复栈,压栈几次出栈几次,都可以丢给rdi寄存器,反正用不到了,或者直接操作rsp寄存器。
-
addq $64,%rsp
-
ret
-
# fpmathfunc.s - An example of reading multiple input values
定义C文件mathtest.c程序如下:
-
#include <stdio.h>
-
-
float fpmathfunc(float, int, float, float, float, int, float, float);
-
-
int main()
-
{
-
float value1 = 43.65;//浮点参数
-
int value2 = 22; //第一个整型参数
-
float value3 = 76.34; //浮点参数
-
float value4 = 3.1; //浮点参数
-
float value5 = 12.43; //浮点参数
-
int value6 = 6; //整型参数
-
float value7 = 140.2; //浮点参数
-
float value8 = 94.21; //浮点参数
-
float result;
-
result = fpmathfunc(value1, value2, value3, value4,
-
value5, value6, value7, value8);
-
printf("The final result is %f\n", result);
-
return 0;
-
}
编译gcc -o -g mathtest mathtest.c fpmathfunc.s
# ./mathtest
The final result is 3.264907
第48部分- Linux x86 64位汇编 C++调用汇编
C++程序中使用所有函数都使用C++样式的命名和调用约定。
但是使用汇编函数也是使用C语言的调用约定。
但是要通知编译器使用哪些函数是C函数,通过extern语句来完成。
示例
定义C++文件externtest.cpp如下:
-
#include <iostream>
-
-
extern "C" {
-
int square(int);
-
float areafunc(int);
-
char *cpuidfunc(void);
-
}
-
-
-
int main()
-
{
-
int radius = 10;
-
int radsquare = square(radius);
-
char* cpuid = cpuidfunc();
-
std::cout << "The radius squared is " << radsquare << std::endl;
-
float result;
-
result = areafunc(radius);
-
std::cout << "The area is " << result << std::endl;
-
std::cout << "The CPUID is " << cpuid << std::endl;
-
return 0;
-
}
需要包含之前的3个汇编语言文件:
square.s,areafunc.s,cpuidfunc.s
编译命令:
g++ -o externtest externtest.cpp square.s areafunc.s cpuidfunc.s -no-pie
# ./externtest
The radius squared is 100
The area is 314.159
The CPUID is GenuineIntel
第49部分- Linux x86 64位汇编 创建静态库和动态库
如果为每个汇编语言函数创建单独的目标文件,会导致文件数量剧增。
可以通过使用库来简化汇编函数的目标文件问题。
GNC的C编译器可以不在命令行中独立的包含每个单独的函数目标文件,允许把所有目标文件组合在单一存档文件中。当编译C主程序时,要做的所有工作就是包含单一的目标存档文件。
存档文件可以用于编译任何使用存档文件中包含的任何函数的程序,这种存档文件就是库文件library file.
经常按照应用程序类型或者函数类型把函数分组在一起,单一应用程序项目中可以使用多个库文件。
库文件中包含的目标代码被编译器编译到了主程序中,这类库文件成为静态文件。函数的目标代码被编译到可执行代码中之后,可执行程序的运行就不需要库文件了。这样每个程序都包含了函数的代码。
在linux中使用ar命令创建静态文件。
Ar的命令行选项如下:
可以用一个或多个修饰符修改基本选项:
创建静态库
Linux操作系统中的静态库命名为libx.a
其中x是库的名称。
我们将C调用汇编中的几个文件汇编成一个静态文件。
先生成目标文件:
as -o square.o square.s
as -o areafunc.o areafunc.s
as -o cpuidfunc.o cpuidfunc.s
生成库文件:
ar -r liblearn.a square.o areafunc.o cpuidfunc.o
通过tv参数可以查看
ar -tv liblearn.a
创建库文件后,可以创建库的索引来帮助必须和库连接的其他程序的编译速度。
ranlib liblearn.a
可以通过nm命令来查看库文件中的函数的符号
nm liblearn.a
使用静态库
然后我们重新编译之前的函数:
gcc -o inttest inttest.c square.s
现在使用静态编译库编译命令如下:
gcc -o intest inttest.c liblearn.a
两者编译出来的大小是一样的。
创建动态库
我们知道windows中的动态库是DLL文件。
在Linux里面就是.so文件。
在说明动态库之前,我们来看下为什么要用动态库。
静态文件的优缺点
- 库文件已修改,所有依赖此函数的应用程序都要重新编译。强耦合。
- 程序要包含使用到的每个函数代码,程序会变大。浪费空间。
- 多个程序使用相同的函数,都需要将该函数 加载到内存,浪费内存。
共享库就是解决这些问题的,它包含函数目标代码的单独文件,被加载到操作系统的通用区域中。当应用程序需要访问共享库中的函数时,操作系统自动把函数代码加载到内存中,并且允许应用程序访问它。
创建共享库
Linux对共享库的命名约定是libx.so
X是库名称,扩展名.so是表示共享库。
根据上面的3个汇编文件我们创建一个共享库
gcc -shared -o liblearn.so square.o areafunc.o
gcc -shared -fPIC -o liblearn.so square.o areafunc.o
这里去掉了cpuidfunc函数,因为该汇编文件不符合动态库要求。
也可以使用nm进行查看。
nm -D liblearn.so
使用共享库
还是以之前的inttest.c文件为例,之前的编译命令为:
gcc -o inttest inttest.c square.s
动态库的编译方式如下:
gcc -o inttest -L. -llearn inttest.c
或者如下:
gcc inttest.c liblearn.so -o inttest
我们要知道动态库不会编译到C程序中,但是编译器需要知道如何访问函数,使用-l选项加上共享库的名称(减去lib部分和.so扩展名)。使用-L选项通知编译器在哪里查找它。如果共享库位于和程序文件相同的目录中,可以使用本地的目录。
反汇编后,我们可以发现可执行文件中不包含函数代码。
另外可以使用ldd命令来查看可执行文件依赖什么共享库。
# ldd inttest
linux-vdso.so.1 (0x00007ffcafbe0000)
liblearn.so => /root/liblearn.so (0x00007fcb5c89b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcb5c4aa000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcb5cc9f000)
共享库的程序的变量
动态加载器访问动态库的方法有两种:
- LD_LIBRARY_PATH
- /etc/ld.so.conf文件
例如 export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:."
/etc/ld.so.conf文件保存动态加载器在哪些目录中查找库的目录清单,主要是系统动态库。
修改后需要执行ldconfig进行加载。
第50部分- Linux x86 64位汇编 汇编调用C
汇编文件可以直接调用C函数。
定义print.c文件如下:
-
-
-
extern int print();
-
int print() {
-
printf("Hello World\n");
-
return 0;
-
}
然后定义汇编文件
Nasm语法
-
global _start
-
extern print
-
section .text
-
_start:
-
call print
-
-
mov rax, 60
-
mov rdi, 0
-
syscall
gcc -c print.c -o c.o
nasm -f elf64 print.asm -o print.o
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc print.o c.o -o print
Gas语法
-
.global _start
-
.extern print
-
.section .text
-
_start:
-
call print
-
-
movq $60,%rax
-
movq $0,%rdi
-
syscall
gcc -c print.c -o c.o
as -o print.o print.s
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc print.o c.o -o print
第51部分- Linux x86 64位汇编内嵌汇编
用汇编编写的程序运行速度快,但开发效率很低。如果只是想对关键代码段进行优化,更好的办法是将汇编指令嵌入到 C 语言程序中。但在 C 代码中嵌入汇编语句要比"纯粹"的汇编语言代码复杂,因为需要解决如何分配寄存器,以及如何与C代码中的变量相结合等问题。
GCC 提供了很好的内联汇编支持,最基本的格式是:
__asm__("asm statements");
Instruction List是汇编指令序列,可以是空的,比如: __asm__ ("");只不过这条语句没有什么意义。
__volatile__是GCC关键字volatile的宏定义,如果用了它,则是向GCC声明“不要动我所写的Instruction List,需要原封不动的保留每一条指令”,否则当使用了优化选项(-O)进行编译时,GCC将会根据自己的判断决定是否将这个内联汇编表达式中的指令优化掉。
示例
-
#include "stdio.h"
-
-
int main()
-
{
-
int a = 10, b = 0;
-
__asm__ __volatile__("movl %1,%%eax \n\t"
-
"movl %%eax,%0 \n\t"
-
:"=g"(b) /* 输出 */
-
:"g"(a) /* 输入 */
-
); /* 不受影响的寄存器 */
-
printf("Result: %d, %d \n", a, b);
-
return 0;
-
}
程序完成将变量a的值赋予变量b。
%%是寄存器前缀符号。
实例二
-
#include <string.h>
-
int main() {
-
char* str = "Hello World\n";
-
long len = strlen(str);
-
int ret = 0;
-
__asm__("movq $1, %%rax \n\t"
-
"movq $1, %%rdi \n\t"
-
"movq %1, %%rsi \n\t"
-
"movl %2, %%edx \n\t"
-
"syscall"
-
: "=g"(ret)
-
: "g"(str), "g" (len));
-
-
return 0;
-
}
gcc inlineasm.c -o inlineasm
这里涉及到输出修饰符。
第52部分- Linux x86 64位汇编基本内嵌汇编
用汇编语言去实现函数有如下3种选择。
- 从头开始编写汇编语言代码来实现函数,然后C程序来调用
- 使用-S创建C代码的汇编版本,然后修改汇编语言代码,然后连接汇编语言代码生成可执行文件
- 在原始的C代码内创建函数的湖边语言代码,然后使用标准C编译器编译
第二种是优化使用。
第三种就是内联汇编。
仅仅实现汇编语言代码不能说并不能完成很多任务,需要把数据进行传递进出。
基本的内联汇编代码可以利用应用程序中定义的全局变量。这里是管局的变量。
基本内联汇编
基本内联汇编格式比较直观,可以直接这样写:
asm("assembly code");
例如:
asm("movl %rcx, %rax"); /* 把 rcx 内容移动到 rax */
__asm__("movb %bh , (%eax)"); /* 把bh中一个字节的内容移动到eax指向的内存 */
两个不同的关键字 asm 和__asm__。这两个关键字都可以使用。不过当遇到asm关键字与程序其他变量有冲突的时候就必须用__asm__了
内联汇编有多条指令,则每行要加上双引号,并且该行要以\n\t结尾。因为GCC会将每行指令作为一个字符串传给as(GAS),使用换行和TAB可以将正确且格式良好的代码行传递给汇编器。
如果在内联代码中操作了一些寄存器,比如修改了寄存器内容(而之后也没有进行还原操作),程序很可能会产生一些难以预料的情况。因为GCC并不知道已经将寄存器内容修改了。尤其是在编译器对代码进行了一些优化的情况下而导致问题。编译器注意不到寄存器内容已经被改掉,程序将当作它没有被修改过而继续执行。所以尽量不要使用这些会产生附加影响的操作,或者当退出的时候还原这些操作。否则很可能会造成程序崩溃。
第53部分- Linux x86 64位汇编内联汇编扩展ASM
基本asm汇编时候,汇编代码通过C全局变量名称整合输入和输出值。
基本内联汇编只涉及到嵌入汇编指令,而在扩展形式中,还可以指定操作数,并且可以选择输入输出寄存器,以及指明要修改的寄存器列表。对于要访问的寄存器,并不一定要要显式指明,也可以留给GCC自己去选择,这可能让GCC更好去优化代码。扩展内联汇编格式如下:
asm ( assembler template
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);
使用扩展ASM格式,可以使用局部和全局变量。
如果没有输出操作数但有输入操作数,必须放两个连续冒号。
扩展ASM格式中,寄存器必须使用两个百分号符号。
指定输入和输出约束
扩展格式中,可以从寄存器和内存位置给输入值和输出值复制。
输入值和输出值列表的格式是:
“constraint” (varialbe)
其中variable是程序中声明的C变量。
约束是单一字符的代码,其中约束代码如下:
除了这些约束外,输出值还包含一个约束修饰符,只是编译器如何处理输出值。
输出值的约束修饰符如下:
使用寄存器示例
gcc -o regtest regtest.c
# ./regtest
The result is 200
进行汇编:
gcc -o regtest.s -S regtest.c
可以看到代码片段:
movl $10, -12(%rbp);//变量1放到堆栈中
movl $20, -8(%rbp) ;//变量2放到堆栈中
movl -12(%rbp), %eax;//根据内联汇编,将10放入到eax
movl -8(%rbp), %ecx;//根据内联汇编,将20放入到ecx
movl %eax, %edx;// 根据内联汇编最后将10放入到edx
#APP
# 8 "regtest.c" 1
imul %rdx, %rcx;// 内联汇编内容,相乘
movq %rcx, %rax// 内联汇编内容,结果放到eax
# 0 "" 2
#NO_APP
movl %eax, -4(%rbp) ;//将结果保存到堆栈中内联汇编内容
movl -4(%rbp), %eax//将结果根据内联汇编存放到eax寄存器中
不指定输出值示例
gcc -o regtest regtest2.c
要复制的字符串放在esi寄存器中,目标位置放在edi寄存器中,要复制的字符串长度存放在ecx寄存器中。
没有定义专门的输出值。
第54部分- Linux x86 64位汇编内联汇编使用占位符
使用寄存器可以处理只有几个输入值的情况,如果有很多输入值的函数,需要占位符。可以在内联汇编代码中引用输入值和输出值,方便编译器在任何寄存器和内存位置中声明输入和输出值。
占位符是前面加上百分号符号的数字。每个值被赋予一个从零开始的数字。
将前面使用寄存器示例使用占位符示例
示例
-
#include <stdio.h>
-
-
int main()
-
{
-
int data1 = 10;
-
int data2 = 20;
-
int result;
-
-
asm ("imull %1, %2\n\t"
-
"movl %2, %0"
-
: "=r"(result)
-
: "r"(data1), "r"(data2));
-
-
printf("The result is %d\n", result);
-
return 0;
-
}
gcc -o regtest regtest3.c
使用约束r。表示使用寄存器满足所有数据需求。
这里%0将表示result,%1表示data1,%2表示data2。
占位符提供在内联汇编代码中利用寄存器和内存位置的方法。
进行反汇编
#gcc -o regtest.s -S regtest3.c查看:
有片段如下:
movl $10, -8(%rbp)
movl $20, -4(%rbp)
movl -8(%rbp), %edx;//使用edx保存10
movl -4(%rbp), %eax;//使用eax保存20
#APP
# 9 "regtest3.c" 1
imull %edx, %eax;//eax和edx相乘,结果直接到eax中。没有在需要使用ecx寄存器了,还优化了一点。
# 0 "" 2
#NO_APP
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
相比直接使用寄存器还优化了一点。
第55部分- Linux x86 64位汇编内联汇编引用占位符
有时候使用相同的变量作为输入值和输出值是有好处的。必须在扩展asm段中区别定义输入值和输出值。
如果内联汇编代码中的输入值和输出值共享程序中相同的C变量,可以指定占位符作为约束值。可以减少代码中需要的寄存器。
#include <stdio.h>
int main()
{
int data1 = 10;
int data2 = 20;
asm ("imull %1, %0"
: "=r"(data2)
: "r"(data1), "0"(data2));
printf("The result is %d\n", data2);
return 0;
}
gcc -o regtest regtest3.c
得到的效果是一样的。
第56部分- Linux x86 64位汇编内联汇编替换占位符
处理很多输入值和输出值,数字型的占位符很快会变得混乱。GNU编译器允许声明替换的名称作为占位符。
替换的名称在声明输入值和输出值的段中定义。
格式如下:
%[name] “constraint” (variable)
定义name成为内联汇编代码中变量的新的占位符标识符。
示例
#include <stdio.h>
int main()
{
int data1 = 10;
int data2 = 20;
asm ("imull %[value1], %[value2]"
: [value2] "=r"(data2);//定义替换符号value2
: [value1] "r"(data1), "0"(data2)); //定义替换符号value1
printf("The result is %d\n", data2);
return 0;
}
gcc -o alttest alttest.c
第57部分- Linux x86 64位汇编改动寄存器列表
编译器假设输入值和输出值使用的寄存器会被改动,并相应的做出处理。
程序员不需要在改动的寄存器列表中包含这些值。
示例
-
#include <stdio.h>
-
-
int main()
-
{
-
int data1 = 10;
-
int result = 20;
-
-
asm ("movl %1, %%eax\n\t"
-
"addl %%eax, %0"
-
: "=r"(result)
-
: "r"(data1), "0"(result)
-
: "%eax");
-
-
printf("The result is %d\n", result);
-
return 0;
-
}
gcc -o changedtest changedtest.c
这里内联汇编代码中使用eax寄存器作为存储数据的中间位置,这个寄存器没有被声明为输入值或输出值,所以必须在改动的寄存器列表中包含。然后编译器会知道EAX寄存器不可用会使用其他寄存器。
第58部分- Linux x86 64位汇编内联汇编使用内存位置
内联汇编中使用寄存器比使用内存要快,但是也可以直接使用C变量的内存位置的。约束为m.
示例
-
#include <stdio.h>
-
-
int main()
-
{
-
int dividend = 20;
-
int divisor = 5;
-
int result;
-
-
asm("divb %2\n\t"
-
"movl %%eax, %0"
-
: "=m"(result)
-
: "a"(dividend), "m"(divisor));
-
-
printf("The result is %d\n", result);
-
return 0;
-
}
gcc -o memtest memtest.c
asm代码段中将被除数放到了eax寄存器中,除数放到内存位置中,值被加载到内存位置中。
第59部分- Linux x86 64位汇编内联汇编使用浮点值
FPU堆栈方式使用寄存器在内联汇编中有一点区别。
内联汇编中:
- f引用任何可用的浮点寄存器
- t引用顶部的浮点寄存器
- u引用第二个浮点寄存器
在获取输出值的时候不能使用约束f,必须声明约束t或者u来指定输出值所在的fpu寄存器。
示例
-
#include <stdio.h>
-
-
int main()
-
{
-
float angle = 90;
-
float radian, cosine, sine;
-
-
radian = angle / 180 * 3.14159;
-
-
asm("fsincos";//求解sin和cos值,此时st0是radian值,结果存放于st0和st1
-
:"=t"(cosine), "=u"(sine);//输出是st0和st1
-
:"0"(radian));
-
-
printf("The cosine is %f, and the sine is %f\n", cosine, sine);
-
return 0;
-
}
gcc -o sincostest sincostest.c
反汇编:
gcc -o sincostest.s -S sincostest.c
有代码片段:
flds -20(%rbp)
#APP
# 11 "sincostest.c" 1
fsincos
# 0 "" 2
#NO_APP
fxch %st(1)
fstps -20(%rbp)
fstps -8(%rbp)
先使用了flds加载,最后将st0和st1都通过fstps进行了弹出操作。保持了fpu寄存器的干净。
示例二
如果FPU堆栈执行的操作没有被清除,就必须在改动的寄存器列表中指定适当的FPU寄存。
-
#include <stdio.h>
-
-
int main()
-
{
-
int radius = 10;
-
float area;
-
-
asm("fild %1\n\t"
-
"fimul %1\n\t"
-
"fldpi\n\t"
-
"fmul %%st(1), %%st(0)"
-
: "=t"(area)
-
:"m"(radius)
-
: "%st(1)");
-
-
printf("The result is %f\n", area);
-
return 0;
-
}
gcc -o areatest areatest.c
把半径值放在一个内存radius位置中,通过fild加载radius中到st0中。
然后将内存radius位置和st0相乘,存在st0中。加载π到st0中,原半径相乘值移动到st1中。将st0和st1相乘。将st0结果复制给area变量。这里我们看到st0作为了输出寄存器使用,但是st1没有在输入和输出中标记出来,所以需要在改动的寄存器列表中列出它。
第60部分- Linux x86 64位汇编内联汇编处理跳转
内联汇编语言代码也可以包含定义其中位置的标签。
内联汇编代码中使用标签时有两个限制,第一个限制是只能跳转到相同的asm段内的标签,不能从一个asm段跳转到另一个asm段中的标签。
第二个限制是汇编后的代码清单不能使用相同的标签。
跳转示例
-
#include <stdio.h>
-
-
int main()
-
{
-
int a = 10;
-
int b = 20;
-
int result;
-
-
asm("cmp %1, %2\n\t"
-
"jge greater\n\t"
-
"movl %1, %0\n\t"
-
"jmp end\n"
-
"greater:\n\t"
-
"movl %2, %0\n"
-
"end:"
-
:"=r"(result)
-
:"r"(a), "r"(b));
-
-
printf("The larger value is %d\n", result);
-
return 0;
-
}
gcc -o jmptest jmptest.c
数字标签示例
条件分支和无条件分支都允许指定一个数字加上方向标志作为标签,方向标志指出处理器应该向哪个方向查找数字型标签。
-
#include <stdio.h>
-
-
int main()
-
{
-
int a = 10;
-
int b = 20;
-
int result;
-
-
asm("cmp %1, %2\n\t"
-
"jge 0f\n\t"
-
"movl %1, %0\n\t"
-
"jmp 1f\n"
-
"0:\n\t"
-
"movl %2, %0\n"
-
"1:"
-
:"=r"(result)
-
:"r"(a), "r"(b));
-
-
printf("The larger value is %d\n", result);
-
return 0;
-
}
gcc -o jmptest jmptest2.c
第61部分- Linux x86 64位汇编内联汇编宏函数
C程序中的任何位置都可以防止内联汇编代码,但是大多数程序员把内联汇编代码用作宏函数。
C宏函数
先回顾下C宏函数示例
-
#include <stdio.h>
-
-
#define SUM(a, b, result) \
-
((result) = (a) + (b))
-
-
int main()
-
{
-
int data1 = 5, data2 = 10;
-
int result;
-
float fdata1 = 5.0, fdata2 = 10.0;
-
float fresult;
-
-
SUM(data1, data2, result);
-
printf("The result is %d\n", result);
-
SUM(1, 1, result);
-
printf("The result is %d\n", result);
-
SUM(fdata1, fdata2, fresult);
-
printf("The floating result is %f\n", fresult);
-
SUM(fdata1, fdata2, result);
-
printf("The mixed result is %d\n", result);
-
return 0;
-
}
gcc -o mactest1 mactest1.c
宏函数中定义的变量完全独立于程序中定义的结果变量。
之类的宏函数SUM()可以处理整数输入值、数字型输入值、浮点输入值,甚至还可以处理混合的输入值和输出值。
汇编宏函数
也可以声明包含内联汇编代码的宏函数。必须使用扩展asm格式,以便定义正确的输入值和输出值。
Asm语句必须括在一对花括号中,以便指出语句的开头和结尾。如果没有花括号,每次在C代码中使用宏时,编译器都会生成错误消息。
示例
-
#include <stdio.h>
-
-
#define GREATER(a, b, result) ({ \
-
asm("cmp %1, %2\n\t" \
-
"jge 0f\n\t" \
-
"movl %1, %0\n\t" \
-
"jmp 1f\n\t" \
-
"0:\n\t" \
-
"movl %2, %0\n\t" \
-
"1:" \
-
:"=r"(result) \
-
:"r"(a), "r"(b)); })
-
-
int main()
-
{
-
int data1 = 10;
-
int data2 = 20;
-
int result;
-
-
GREATER(data1, data2, result);
-
printf("a = %d, b = %d result: %d\n", data1, data2, result);
-
-
data1 = 30;
-
GREATER(data1, data2, result);
-
printf("a = %d, b = %d result: %d\n", data1, data2, result);
-
return 0;
-
}
gcc -o mactest2 mactest2.c
可以成功运行。
输入变量a和b被赋值给寄存器,可以在CMP指令中使用它们。
JGE/JMP指令使用数字型的标签,以便可以在程序中多次使用宏函数而不会出现重复的汇编标签。
第62部分- Linux x86 64位汇编 浮点数
单精度是这样的格式,1位符号,8位指数,23位小数。
指数是从-128到127的8位有符号整数,或者是从0到255的8位无符号整数。指数部分采用的偏置码(biased)的形式来表示正负指数,若小于127则为负的指数,否则为非负的指数。所以0到126代表-127到-1,127代表零,128-255代表1-128。
另外补码,一个数字的补码就是将该数字作比特反相运算(即反码),再将结果加1。在补码系统中,一个负数就是用其对应正数的补码来表示。
补码系统的最大优点是可以在加法或减法处理中,不需数字的正负而使用不同的计算方式。只要一种加法电路就可以处理各种有号数加法,而且减法可以用一个数加上另一个数的补码来表示,因此只要有加法电路及补码电路即可完成各种有号数加法及减法,在电路设计上相当方便。
单精度公式:(-1)^S*(1.M)*2^(E-127)
S是符号。
M是尾数。
E是指数。
双精度是1位符号,11位指数,52位小数。
双精度公式: (-1)^S*(1.M)*2^(E-1023)
扩展双精度是80位的,1位符号,15位指数,112位小数。
f、j、e 和 s 四个字段中的位模式值将决定整个位模式所表示的值。
计算模式相对复杂一点,大家可以忽略之。
双精度扩展位模式 (x86) |
值 |
j = 0, 0 < e <32767 |
不支持 |
j = 1, 0 < e < 32767 |
|
j = 0, e = 0; f ≠ 0(f 中至少有一位不为零) |
|
j = 1, e = 0 |
(–1)s × 2–16382 × 1.f(伪非正规数) |
j = 0, e = 0, f = 0(f 中的所有位均为零) |
(–1)s × 0.0(有符号的零) |
j = 1; s = 0; e = 32767; f = 0(f 中的所有位均为零) |
|
j = 1; s = 1; e = 32767; f = 0(f 中的所有位均为零) |
–INF(负无穷大) |
j = 1; s = u; e = 32767; f = .1uuu — uu |
QNaN(quiet NaN,静态 NaN) |
j = 1; s = u; e = 32767; f = .0uuu — uu ≠ 0 (f 中至少一个 u 不为零) |
SNaN(signaling NaN,信号 NaN) |
SSE浮点数据类型
除了3种标准浮点数据类型之外,SSE技术的INTEL处理器还包含两种高级浮点数据类型。8个128位XMM寄存器可以保存打包浮点数。类似打包BCD概念。
数据移动如下:
SSE2数据传送指令如下:
数据类型转换
PS是打包单精度FP
PD是打包双精度FP
PI是打包双字整数,使用MMX
DQ是打包双字整数
示例
转换数据类型如下:
-
.section .data
-
value1:
-
.float 1.25, 124.79, 200.0, -312.5
-
value2:
-
.int 1, -435, 0, -25
-
.section .bss
-
data:
-
.lcomm datas, 16
-
.section .text
-
.globl _start
-
_start:
-
nop
-
cvtps2dq value1, %xmm0;//打包单精度到打包双字整型
-
cvttps2dq value1, %xmm1;//打包单精度到打包双字整型,会截断
-
cvtdq2ps value2, %xmm2;//打包双字整型到打包单精度,会截断
-
movdqu %xmm0, datas;//保存到datas变量中。
-
-
movl $1, %eax
-
movl $0, %ebx
-
int $0x80
在value1中定义了一个打包单精度浮点值。
value2中定义了打包双字整数值。
使用gdb进行调试,可以看到如下xmm寄存器。
(gdb) print $xmm0
$8 = {v4_float = {1.40129846e-45, 1.75162308e-43, 2.80259693e-43, -nan(0x7ffec8)}, v2_double = {2.6524947387115311e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0, 125, 0,
0, 0, -56, 0, 0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 125, 0, 200, 0, -312, -1}, v4_int32 = {1, 125, 200, -312}, v2_int64 = {536870912001, -1340029796152},
uint128 = 340282342201751762702250093524836941825}
(gdb) print $xmm1
$9 = {v4_float = {1.40129846e-45, 1.7376101e-43, 2.80259693e-43, -nan(0x7ffec8)}, v2_double = {2.6312747808018783e-312, -nan(0xffec8000000c8)}, v16_int8 = {1, 0, 0, 0, 124, 0,
0, 0, -56, 0, 0, 0, -56, -2, -1, -1}, v8_int16 = {1, 0, 124, 0, 200, 0, -312, -1}, v4_int32 = {1, 124, 200, -312}, v2_int64 = {532575944705, -1340029796152},
uint128 = 340282342201751762702250093520541974529}
(gdb) print $xmm2
$10 = {v4_float = {1, -435, 0, -25}, v2_double = {-7.3498756827903427e+18, -805306368}, v16_int8 = {0, 0, -128, 63, 0, -128, -39, -61, 0, 0, 0, 0, 0, 0, -56, -63}, v8_int16 = {
0, 16256, -32768, -15399, 0, 0, 0, -15928}, v4_int32 = {1065353216, -1009156096, 0, -1043857408}, v2_int64 = {-4334292427813683200, -4483333429047328768},
uint128 = 257579462558195729010253313545846390784}
可以看到cvttps2dq指令会进行截断。
而cvtps2dq指令会进行舍入。
另外,最后在调试的时候大家会发现,xmm寄存器已经被扩展了,已经变成了256位的zmm了。
第63部分- Linux x86 64位汇编 FPU之概要
X87浮点单元FPU,提供高性能浮点处理。从80486就开始支持了。
Intel x87 FPU专门用于执行标量浮点计算,对单精度浮点(32位)、双精度浮点(64位)以及扩展双精度浮点(80位)进行计算,并顺从IEEE754标准。
FPU的数据寄存器的个数都一样,只有8个。对x87 FPU的数据寄存器的访问方式与一般的寄存器有所不同,是栈式访问。通过FLD指令把外部数据搬到x87 FPU的数据寄存器中时,那么x87 FPU会根据所搬数据的长度(32位、64位、80位)将输入数据分别对待为单精度浮点、双精度浮点和扩展双精度浮点方式,然后统一转为双精度扩展模式放到数据栈顶。因此x87 FPU的数据寄存器长度为80位,并且后续的浮点计算都是基于扩展双精度进行的。
在栈顶的数据寄存器索引为0,那么它下面一个就是1, 然后是2, 以此类推,到栈底则为7。
数据输出到存储器时使用FST或FSTP指令,前者仅仅是根据目标存储器的长度(32位、64位、80位)将扩展双精度类型分别转为单精度、双精度、扩展双精度类型,然后输出到指定的存储器位置中。FSTP指令,除了将数据搬到外部外,还会执行推出堆栈的操作。
FLD和FST以及FSTP还能搬移FPU内部寄存器的数据,FLD的作用是将指定的FPU数据寄存器位置的数据搬移到栈顶寄存器中,而FST则是将栈顶寄存器的数据搬移到指定的FPU数据寄存器的位置。
由于80位(10个字节)并不是32位(4个字节)的整数倍,因此数据加载或存储双精度扩展浮点往往是用96位(12个字节)为单位进行,所以“tbyte”所指的就是“twelve bytes”
Intel汇编格式的字节、字宽指定修饰词:byte(字节,8位),word(字,16位),dword(双字,32位),qword(四字,64位),tbyte(十二字节,96位),mmword(64位,但只能用于MMX指令集中),xmmword(128位,用于SSE指令集),ymmword(256位,用于最新的AVX指令集)。
FPU有以环形堆栈组织的八个10字节寄存器。 堆栈顶部-寄存器ST(0),其他寄存器为ST(1),ST(2)…ST(7)。 在处理浮点数据时,通常会使用它。
数据传输指令
FDL-加载浮点。
FST-存储浮点(在ST(0)寄存器中)。
FSTP-存储浮点数(在ST(0)寄存器中)并弹出。
FLD类似于PUSH指令
FSTP类似于POP指令
FADD类似于ADD指令
算术指令:
FADD-浮点加法;// ST(0)与 ST(1)相加,结果暂存在 ST(1)。然后 ST(0) 弹出堆栈,把加法结果保留在栈顶。
FIADD-将整数添加到浮点
FSUB-减去浮点
FISUB-从浮点数减去整数
FABS-获得绝对值
FIMUL-整数和浮点数相乘
FIDIV-设备整数和浮点
示例
定义printResult.c文件如下:
-
-
-
extern int printResult(double result);
-
-
int printResult(double result) {
-
printf("Circle radius is - %f\n", result);
-
return 0;
-
}
定义实现的汇编文件printResult.asm如下:
-
extern printResult
-
section .data
-
radius dq 1.7
-
result dq 0
-
-
SYS_EXIT equ 60
-
EXIT_CODE equ 0
-
-
global _start
-
section .text
-
_start:
-
fld qword [radius];//保存到st(0)
-
fld qword [radius] ;//保存到st(1)
-
fmul;//将 ST(O) 与 ST(1) 相乘,乘积暂存于ST(1)。然后 ST(0) 弹出堆栈,将乘积则继续留在栈顶。
-
fldpi;//装入浮点的pi,就是装入st(1)
-
fmul;//将ST(O) 与 ST(1) 相乘,保存到st(0)
-
fstp qword [result];//将结果保存到[result]
-
-
mov rax, 0;// 表示xmmN寄存器的数量放入rax寄存器
-
movq xmm0, [result];//将参数也就是结果放到xmm0.
-
call printResult
-
-
mov rax, SYS_EXIT;退出系统调用的号
-
mov rdi, EXIT_CODE
-
syscall
其中DQ作为汇编语言中的伪操作命令,用来定义操作数占用的字节数,占有4个字,即8个字节(64位),可用来存放双精度浮点数。
浮点参数的传参有特殊的寄存器:sse提供的xmm0-xmm15(而不是通常的rdi,rsi……)。需要将xmmN寄存器的数量放入rax寄存器(本例中为0),然后将结果放入xmm0寄存器。
编译如下:
gcc -g -c printResult.c -o c.o
nasm -f elf64 printResult.asm -o printResult.o
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc printResult.o c.o -o printResult
gas语法
定义实现的汇编文件如下:
printResult.s
-
.extern printResult
-
-
.section .data
-
radius: .double 1.7
-
result: .double 0
-
-
.equ SYS_EXIT , 60
-
.equ EXIT_CODE, 0
-
-
.global _start
-
.section .text
-
_start:
-
leaq radius,%rbx
-
fldl (%rbx)
-
fldl (%rbx)
-
fmulp
-
-
fldpi
-
fmulp
-
fstl result
-
-
movq $0,%rax
-
movq result, %xmm0
-
call printResult
-
-
movq $SYS_EXIT,%rax
-
movq $EXIT_CODE,%rdi
-
syscall
编译如下:
gcc -g -c printResult.c -o c.o
as -g -o printResult.o printResult.s
ld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc printResult.o c.o -o printResult
tips:在gdb中可以时候用print $st0来打印寄存器中 值。
第64部分- Linux x86 64位汇编 FPU之一介绍
FPU是一个自持单元,使用与标准处理器寄存器分离的一组寄存器处理浮点操作。包括8个80位数据寄存器和3个16位寄存器(用于状态,控制和标记)。
FPU数据寄存器称为R0到R7,它们连接在一起形成一个堆栈(R7是顶端就是st0寄存器)。
状态寄存器
FPU有自己的状态寄存器,包含在一个16位寄存器中。可以通过fstsw指令来读取。
控制寄存器
控制FPU内的浮点功能,用于计算浮点值的精度以及用于舍入浮点结果的方法。可以通过fstcw把控制寄存器进行加载。
精度控制可以设置为四位
00 单精度
01 未使用
10 双精度
11 扩展双精度(默认为扩展双精度)
舍入控制
00 舍入到最近值(默认舍入到最近值)
01 向下舍入
10 向上舍入
11 向零舍入
示例
-
.section .data
-
newvalue:
-
.byte 0x7f, 0x00
-
.section .bss
-
.lcomm control, 2
-
.section .text
-
.globl _start
-
_start:
-
nop
-
fstcw control
-
fldcw newvalue
-
fstcw control
-
-
movl $1, %eax
-
movl $0, %ebx
-
int $0x80
执行过中,查看获取到的寄存器的值。
(gdb) x /x &control
0x6000d6 <control>: 0x00000000
(gdb) s
(gdb) x /x &control
0x6000d6 <control>: 0x0000037f
(gdb) s
(gdb) s
(gdb) x /x &control
0x6000d6 <control>: 0x0000007f
标记寄存器
标记寄存器用于标识8个80位FPU数据寄存器中的值。
每个标记值对应一个物理的FPU寄存器。每个寄存器对应2位值可以表明寄存器内容的4个特殊代码之一。
00 一个合法的扩展双精度
01 零值
10 特殊的浮点值
11 无内容
FPU基本使用例子
-
.section .data;//定义数据段
-
value1:
-
.int 40
-
value2:
-
.float 92.4405
-
value3:
-
.double 221.440321
-
.section .bss
-
.lcomm int1, 4
-
.lcomm control, 2
-
.lcomm status, 2
-
.lcomm result, 4
-
.section .text
-
.globl _start
-
_start:
-
nop
-
finit;//初始化FPU
-
fstcw control;//控制器寄存器
-
fstsw status;//状态寄存器
-
filds value1;//把一个双字整数值加载到FPU寄存器堆栈中,st0。
-
fists int1;//获取寄存器堆栈顶部的值,并存放到目标位置
-
flds value2;//加载values2的单精度浮点值到FPU寄存器堆栈中
-
fldl value3;// 加载values3的双精度浮点值到FPU寄存器堆栈中
-
fst %st(4) ;//将st0寄存器传送到st4
-
fxch %st(1) ;//交换st0和st1
-
fstps result;//将st0加载到result,并弹出st0.
-
movl $1, %eax
-
movl $0, %ebx
-
int $0x80
as -o stacktest.o stacktest.s
ld -o stacktest stacktest.o
执行后如下:
(gdb) i r st0
st0 221.440321000000011509 (raw 0x4006dd70b8e086bdf800)
(gdb) i r st1
st1 92.44049835205078125 (raw 0x4005b8e1890000000000)
(gdb) i r st2
st2 40 (raw 0x4004a000000000000000)
第65部分- Linux x86 64位汇编 FPU之二浮点基本运算
FPU提供对浮点值执行基本数学功能的指令。
例如:
FADD source: 内存中32位或64位和ST0寄存器相加。
FADD %st(x),%st(0): st(x)和st(0)相加,结果存于st(0)
FADD %st(0),%st(x): st(x)和st(0)相加,结果存于st(x)
FADDP %st(0),%st(x): st(x)和st(0)相加,结果存于st(x),并弹出st(0)
在GNU汇编器中,指定内存中的值的指令的助记符要包含长度(s用于32位单精度浮点值,l用于双精度浮点值)
示例
我们来计算一个表达式:
((43.65/22+(76.34*3.1))/((12.43*6)-(140.2/94.21))
具体思路如下:
- 把43.65加载到st0
- st0除以22,结果保存到st0
- 把76.34加载st0(步骤2结果移动到st1)
- 把3.1记载到st0(76.34移动到st1,步骤2结果移动到st2)
- St0和st1相乘,存放于st0
- St0和st2相加,存放于st0。表达式的分子部分完成结果。
- 把12.43加载到st0,步骤六结果移动到st1
- St0乘以6,存放在st0
- 把140.2加载到st0,步骤8移动到st1,步骤6移动到st2
- 把94.21加载到st0,步骤8移动到st2,步骤6移动到st3
- St1/st0,弹出堆栈并把结果保存到st0(步骤8答案移到st1,步骤6移动到st2)
- St1-st0,保存到st0. 表达式的分目部分完成结果。
- St2除以st0,结果保存到st0中。完成。
-
.extern printf ;//调用外部的printf函数
-
.section .data
-
fmt: .ascii "result is: %f \n"
-
value1:
-
.float 43.65
-
value2:
-
.int 22
-
value3:
-
.float 76.34
-
value4:
-
.float 3.1
-
value5:
-
.float 12.43
-
value6:
-
.int 6
-
value7:
-
.float 140.2
-
value8:
-
.float 94.21
-
result: .double 0.0
-
-
.section .text
-
.globl _start
-
_start:
-
nop
-
finit;//初始化fpu
-
flds value1;//1.加载value1 43.65到st0
-
fidiv value2;// 2.st0除以22,结果保存到st0
-
flds value3;//3.把76.34加载st0(步骤2结果移动到st1)
-
flds value4;// 4.把3.1记载到st0(76.34移动到st1,步骤2结果移动到st2)
-
fmul %st(1), %st(0) ;//5. St0和st1相乘,存放于st0
-
fadd %st(2), %st(0) ;//6. St0和st2相加,存放于st0。表达式的分子部分完成结果。
-
flds value5;// 7.把12.43加载到st0,步骤六结果移动到st1
-
fimul value6;//8. St0乘以6,存放在st0
-
flds value7;//9. 把140.2加载到st0,步骤8移动到st1,步骤6移动到st2
-
flds value8;//10. 把94.21加载到st0,步骤8移动到st2,步骤6移动到st3
-
fdivrp;//11. 反向除法,St1/st0,弹出堆栈并把结果保存到st0(步骤8答案移到st1,步骤6移动到st2)
-
fsubr %st(1), %st(0) ;//12. 反向减法,St1-st0,保存到st0. 表达式的分目部分完成结果。
-
fdivr %st(2), %st(0) ;//13.反向触发,St2除以st0,结果保存到st0中。完成。
-
fstpl result ;//st0加载到result目标中
-
-
mov $fmt,%rdi
-
movq result,%xmm0
-
call printf
-
-
mov $60,%rax
-
syscall
FIDIV指令在执行除法之前将整数源操作数转换为双精度扩展浮点数格式。
FDIVR是反向除法。
编译连接:
as -g -o fpmath1.o fpmath1.s
ld -o fpmath1 fpmath1.o -lc -I /lib64/ld-linux-x86-64.so.2
对应的图示结果如下:
第66部分- Linux x86 64位汇编 FPU之三高级浮点运算
除了简单的加减乘除外,还有许多浮点运算。
浮点除法例子
-
.section .data
-
fmt: .ascii "result is: %f \n"
-
-
value1:
-
.float 20.65
-
value2:
-
.float 3.97
-
-
.section .bss
-
.lcomm result, 8
-
.section .text
-
.globl _start
-
_start:
-
nop
-
finit;//初始化fpu
-
flds value2;//加载单精度值value2到st0
-
flds value1;//加载单精度值value1到st0,value2移到st1
-
loop:
-
fprem1;//执行简单的浮点除法
-
fstsw %ax;//加载fpu状态寄存器
-
testb $4, %ah;//检测条件代码位2(第10位),如果被设置了test会生产非零值,需要迭代时设置C2位,当迭代完成时,就清空C2位。
-
jnz loop
-
-
mov $60,%rax
-
syscall
as -g -o premtest.o premtest_att.s
ld -o premtest premtest.o
第67部分- Linux x86 64位汇编 FPU之三角函数
一般的三角函数,比如正弦,余弦和正切等都可以轻松的通过FPU来计算得到。
正弦的指令是fsin,余弦是fcos.同时获得正弦值和余弦值可以使用FSINCOS.
正切和反正切的指令是FPTAN和FPATAN。
FPATAN指令使用两个隐含的源操作数,计算角值ST1/ST0的反正切值。把值保存在ST1,然后弹出ST0,值移动到ST0位置。
不过就是在使用三角函数之前,需要把值转换为弧度。
弧度=(角度*pi)/180
正弦示例
.extern printf ;//调用外部的printf函数
.section .data
fmt: .ascii "result is: %f \n"
degree1:
.float 30.0
val180:
.int 180
.section .bss
.lcomm radian1, 4
.lcomm result1, 8
.lcomm result2, 8
.section .text
.globl _start
_start:
nop
finit;//初始化fpu
flds degree1;//加载角度90
fidivs val180;//除以180,保存在st0
fldpi;//加载π到st1
fmul %st(1), %st(0) ;//乘以π得到弧度,在st0中。
fsts radian1;//保存弧度到radian1中
fsin;//求正弦,保存在st0
fstl result1;//正弦结果保存到result1中。
movq $fmt,%rdi;//调用printf函数
movq result1,%xmm0
call printf
flds radian1;//加载弧度到st0
fcos;//计算余弦,
fstl result2;//
movq $fmt,%rdi
movq result2,%xmm0
call printf
movq $60,%rax
syscall
as -g -o trigtest.o trigtest_att.s
ld -o trigtest trigtest.o -lc -I /lib64/ld-linux-x86-64.so.2
正弦余弦示例
.extern printf ;//调用外部的printf函数
.section .data
fmt: .ascii "result is: %f \n"
degree1:
.float 30.0
val180:
.int 180
.section .bss
.lcomm sinresult, 8
.lcomm cosresult, 8
.section .text
.globl _start
_start:
nop
finit
flds degree1
fidivs val180
fldpi
fmul %st(1), %st(0)
fsincos
fstpl cosresult
movq $fmt,%rdi
movq cosresult,%xmm0
call printf
fstl sinresult
movq $fmt,%rdi
movq sinresult,%xmm0
call printf
movq $60,%rax
syscall
as -g -o sincostest.o sincostest.s
ld -o sincostest sincostest.o -lc -I /lib64/ld-linux-x86-64.so.2
第68部分- Linux x86 64位汇编 FPU之对数函数
对数函数提供用于底数为2的对数计算。
FYL2X
执行如下:
ST(1)*log2(st(0))
FYL2X1
执行如下:
ST(1)*log2(st(0)+1.0)
FSCALE指令计算ST(0)乘以ST(1)次乘方
示例-fscale
计算:
10*22和10*2-2
.extern printf ;//调用外部的printf函数
.section .data
fmt: .ascii "result is: %f \n"
value:
.float 10.0
scale1:
.float 2.0
scale2:
.float -2.0
.section .bss
.lcomm result1, 8
.lcomm result2, 8
.section .text
.globl _start
_start:
nop
finit;//初始化fpu
flds scale1;//加载scale1值到st0
flds value;//加载10值到st0,scale1移动到st1
fscale;//执行fscale,10*22
fstl result1;//将结果报错到result1中
movq $fmt,%rdi
movq result1,%xmm0
call printf
flds scale2;//加载sacle2到st0
flds value;//记载value到st0,scale2移动到st1
fscale;//执行fscale,10*2-2
fstl result2;//将结果报错到result2中
movq $fmt,%rdi
movq result2,%xmm0
call printf
movq $60,%rax
syscall
as -g -o fscaletest.o fscaletest.s
ld -o fscaletest fscaletest.o -lc -I /lib64/ld-linux-x86-64.so.2
示例—求对数
计算log (base b) X=(1/log(base 2) b) * log ( base 2) X
即log1012= log212/log210
.extern printf ;//调用外部的printf函数
.section .data
fmt: .ascii "result is: %f \n"
value:
.float 12.0
base:
.float 10.0
.section .bss
.lcomm result, 8
.section .text
.globl _start
_start:
nop
finit;//初始化fpu
fld1;//fld1加载1.0到st0
flds base;//加载base到st0,1.0移动到st1
fyl2x;//执行 ST(1)*log2(st(0)),即1*log2(10)
fld1;// 加载1到st0中,刚才的结果移动到st1
fdivp;// 执行st0/st1,即1/log2(10)
flds value;//加载12到st0,上步结果1/log2(10)保存到st1
fyl2x;// ST(1)*log2(st(0)),即1/log2(10)*log2(12)=log10(12)
fstl result;//加载结果到result
movq $fmt,%rdi
movq result,%xmm0
call printf
movq $60,%rax
syscall
as -g -o logtest.o logtest_att.s
ld -o logtest logtest.o -lc -I /lib64/ld-linux-x86-64.so.2
第69部分- Linux x86 64位汇编 FPU之浮点条件分支
浮点的比较不像整数那么容易,在处理整数时候,容易使用CMP指令并且评估EFLAGS寄存器中的值来确定是否大于,等于还是小于。
浮点数,不能使用CMP指令,FPU提供了一些自己的指令来比较浮点值。
FCOM比较指令
比较的结果设置在状态寄存器的C0,C2和C3条件代码位中。
需要使用FSTSW指令把状态寄存器的值复制到AX寄存器,然后使用test指令判断比较结果。
示例
-
.extern printf ;//调用外部的printf函数
-
.section .data
-
fmtg: .asciz "greate \n"
-
fmtb: .asciz " less \n"
-
-
value1:
-
.float 100.923
-
value2:
-
.float 400.5532
-
.section .text
-
.globl _start
-
_start:
-
nop
-
flds value1;//加载value1 10.923到st0
-
fcoms value2;// st0和value2 4.5532对比。
-
fstsw;//加载状态寄存器到AX
-
sahf;//加载AH寄存器到EFLAGS中。
-
ja greater;//大于则跳转到greater
-
jb lessthan;//小于则跳转到lessthan
-
greater:
-
movq $fmtg,%rdi
-
call printf
-
jmp exit
-
-
lessthan:
-
movq $fmtb,%rdi
-
call printf
-
exit:
-
movq $60,%rax
-
syscall
as -g -o fcomtest.o fcomtest_att.s
ld -o fcomtest fcomtest.o -lc -I /lib64/ld-linux-x86-64.so.2
这里有指令:
LAHF(加载状态标志位到 AH)指令将 EFLAGS 寄存器的低字节复制到 AH。
被复制的标志位包括:符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位。
SAHF(保存 AH 内容到状态标志位)指令将 AH 内容复制到 EFLAGS(或 RFLAGS)寄存器低字节。将AH寄存器的第0,2,4,6,7分别传送到进位、奇偶校验、对准、零和符号标志、不影响EFLAGS寄存器的其他位。
FSTSW和SAHF指令组合传送如下:
- C0位传送到EFLAGS的进位标志
- C2位传送到EFLAGS的奇偶校验标志
- C3位传送到EFLAGS的零标志
为后续的JA,JB,JZ指令提供了很好的工作。
FCOMI指令
此外,还可以使用FSTSW和SAHF指令组合效果的指令,就是FCOMI。
只能比较FPU寄存器中的值,不能比较FPU寄存器和内存中的值。
FUCOMI和FUCOMP是确保被比较的值是合法的浮点数。
示例
-
.extern printf ;//调用外部的printf函数
-
.section .data
-
fmtg: .asciz "greate \n"
-
fmtb: .asciz " less \n"
-
value1:
-
.float 10.923
-
value2:
-
.float 4.5532
-
.section .text
-
.globl _start
-
_start:
-
nop
-
flds value2;//加载value2 4.5532到st0
-
flds value1;//加载value1 10.923到st0
-
fcomi %st(1), %st(0);//比较st1,st0
-
ja greater
-
jb lessthan
-
-
greater:
-
movq $fmtg,%rdi
-
call printf
-
jmp exit
-
-
lessthan:
-
movq $fmtb,%rdi
-
call printf
-
exit:
-
movq $60,%rax
-
syscall
as -g -o fcomitest.o fcomitest_att.s
ld -o fcomitest fcomitest.o -lc -I /lib64/ld-linux-x86-64.so.2
FCMOV指令
类似整数的CMOV指令,FCMOV指令可以编写浮点值的条件传送。根据EFLAGS寄存器中的值,FCMOV系列的指令把FPU寄存器ST(x)中的源操作数传送到FPU寄存器ST(0)中目标操作数。如果条件为true,就把ST(x)寄存器中值传送到ST(0)寄存器。
常用的方法是在FCMOV之前使用FCOMI
格式是:
Fcmovx source, destination
其中source是ST(x)寄存器,destination是ST(0)寄存器。
示例
-
.extern printf ;//调用外部的printf函数
-
.section .data
-
fmt: .ascii "result is: %f \n"
-
value1:
-
.float 20.5
-
value2:
-
.float 10.90
-
.section .text
-
.globl _start
-
_start:
-
nop
-
finit
-
flds value1;//加载value1 20.5到st0
-
flds value2;//加载value2 10.90到st0,20.5移动到st1
-
fcomi %st(1), %st(0);//如果st0小于st1,设置eflags,然后fcmovb会将st1值复制到st0.
-
fcmovb %st(1), %st(0)
-
-
fstl result;//加载结果到result
-
movq $fmtb,%rdi
-
movq result,%xmm0
-
call printf
-
exit:
-
movq $60,%rax
-
syscall
as -g -o fcmovtest.o fcmovtest_att.s
ld -o fcmovtest fcmovtest.o -lc -I /lib64/ld-linux-x86-64.so.2
第70部分- Linux x86 64位汇编 FPU之保存和恢复
FPU数据寄存器用于自己的FPU计算完,还用于MMX技术的计算。
所以涉及到FPU状态的保存和恢复。
FSTENV指令用于把FPU环境存储到一个内存块中。
会保存如下寄存器:
控制寄存器/状态寄存器/标记寄存器/FPU指令指针偏移量/FPU数据指针/FPU最后执行的操作码,并没有保存数据,如果要保存数据,则必须要使用FSAVE指令。
FLDENV指令用于把内存块的值加载会FPU环境中。
FSTENV示例
-
.section .data
-
value1:
-
.float 12.34
-
value2:
-
.float 56.789
-
rup:
-
.byte 0x7f, 0x0b
-
.section .bss
-
.lcomm buffer, 28
-
.section .text
-
.globl _start
-
_start:
-
nop
-
finit;//初始化FPU,所有stx设置为0
-
flds value1;//加载value1到st0
-
flds value2;// 加载value2到st0,value1到st1中。
-
fldcw rup;//加载控制器内容为0x7f,0x0b
-
fstenv buffer;//加载FPU环境到buffer
-
finit;//初始化FPU
-
flds value2;//重新加载value2到st0
-
flds value1;// 重新加载value1到st0,value2到st1中。
-
fldenv buffer;//从buffer中恢复FPU环境
-
-
movq $60,%rax
-
syscall
as -g -o fpuenv.o fpuenv.s
ld -o fpuenv fpuenv.o
这里例子通过gdb来进行反汇编查看。
通过(gdb) x /28b &buffer来查看buffer中内容。保存之后内容如下:
(gdb) x /28b &buffer
0x600100 <buffer>: 0x7f 0x0b 0xff 0xff 0x00 0x30 0xff 0xff
0x600108 <buffer+8>: 0xff 0x0f 0xff 0xff 0xbb 0x00 0x40 0x00
0x600110 <buffer+16>: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x600118 <buffer+24>: 0x00 0x00 0xff 0xff
通过info all查看fpu的寄存器。
FSAVE示例
-
.section .data
-
value1:
-
.float 12.34
-
value2:
-
.float 56.789
-
rup:
-
.byte 0x7f, 0x0b
-
.section .bss
-
.lcomm buffer, 108
-
.section .text
-
.globl _start
-
_start:
-
nop
-
finit
-
flds value1
-
flds value2
-
fldcw rup
-
fsave buffer;//此处设置断点进行寄存器观察
-
-
flds value2
-
flds value1
-
-
frstor buffer
-
-
movq $60,%rax ;//此处设置断点进行寄存器观察恢复后
-
syscall
as -g -o fpusave.o fpusave.s
ld -o fpusave fpusave.o
在fsave之前如下:
st0 56.78900146484375 (raw 0x4004e327f00000000000)
st1 12.340000152587890625 (raw 0x4002c570a40000000000)
st2 0 (raw 0x00000000000000000000)
st3 0 (raw 0x00000000000000000000)
st4 0 (raw 0x00000000000000000000)
st5 0 (raw 0x00000000000000000000)
st6 0 (raw 0x00000000000000000000)
st7 0 (raw 0x00000000000000000000)
fctrl 0xb7f 2943
fstat 0x3000 12288
ftag 0xfff 4095
在fsave之后如下,堆栈顶部值移动了:
st0 0 (raw 0x00000000000000000000)
st1 0 (raw 0x00000000000000000000)
st2 0 (raw 0x00000000000000000000)
st3 0 (raw 0x00000000000000000000)
st4 0 (raw 0x00000000000000000000)
st5 0 (raw 0x00000000000000000000)
st6 56.78900146484375 (raw 0x4004e327f00000000000)
st7 12.340000152587890625 (raw 0x4002c570a40000000000)
fctrl 0x37f 895
第71部分- Linux x86 64位汇编 FPU之等待和非等待指令
浮点指令可能生成6种浮点异常。表明运算过程中出现了某些错误,例如零为除数。
大多出浮点指令在执行之前必须等待以便确保前面的指令没有跑出异常。如果出现异常,在执行下一条指令之前必须先处理异常。
还有一种方式,不等待浮点异常的检查,允许程序保存或者复位当前的FPU状态,不处理悬而未决的异常。
FPU之优化浮点运算
如何优化浮点代码:
- 确保浮点值不会上溢和下溢
- 精度控制设置为单精度
- 使用查找表实现三角函数
- 断开依赖链,例如不计算Z=A+b+c+d,而是计算x=a+b,y=c+d
- 在FPU寄存器中尽可能多保留方程式的值
- 尽可能使用FCOMI,而不是FCOM。
- 涉及整数和浮点,将整数加载到FPU寄存器中,比对整数使用浮点指令要快。
第72部分- Linux x86 64位汇编调用汇编库
如果希望汇编语言函数和C以及C++程序一起工作,必须显式的遵守C样式的函数格式。
汇编语言函数的源代码文件包含在编译器命令行中。
例如:
gcc -o exe xx.c xx.s xx2.s xx3.s
创建汇编语言函数的目标文件时,不必使用ld命令连接代码,因为本身可能缺少_start标签。使用as进行汇编即可。
一起编译C文件和汇编文件
汇编文件asmfunc.s如下:
-
.section .data
-
testdata:
-
.ascii "This is a test message from the asm function\n"
-
datasize:
-
.int 45
-
.section .text
-
.type asmfunc, @function
-
.globl asmfunc
-
asmfunc:
-
-
movl $1, %rax;//write系统调用
-
movl $1, %rdi;//stdout
-
movl $testdata, %rsi;//字符串
-
movl datasize, %rdx;//字符串长度
-
syscall;//系统调用
-
-
ret
C文件mainprog.c如下:
-
#include <stdio.h>
-
-
int main()
-
{
-
printf("This is a test.\n");
-
asmfunc();
-
printf("Now for the second time.\n");
-
asmfunc();
-
printf("This completes the test.\n");
-
return 0;
-
}
进行编译连接如下:
# gcc -o mainprog mainprog.c asmfunc.s -no-pie
产生一个完整的可执行程序文件。
这里使用了参数-no-pie,因为不用会报错:
`.data' can not be used when making a PIE object;
tips:默认编译器是PIE(position independent executable)对象的,在支持它的目标上生成与位置无关的可执行文件, 生成一个可以在任意基地址处加载的可执行文件,而不是其加载地址在ld时间固定的“普通”可执行文件。PIE通常被认为是一种强化机制(允许地址随机化来影响主程序中代码和数据的地址),但它也可以具有其他用途,例如使二进制文件更适合于无MMU的系统。
这里-no-pie表示非PIE对象。
PIC和PIE
位置无关的代码(PIC)和位置无关的可执行文件(PIE)并不是什么新鲜事物,但是编译开关,可以忽略,直到我们不能使用为止。
位置无关代码(PIC)是很老的东西。 早在我们拥有MMU和分页之前,所有进程都必须共享物理地址空间,可以确保可以在任何地址加载程序。 当CPU演进并且每个进程可以将其自己的逻辑地址空间任意映射到任何物理地址时,PIC不再是必需的。
早期被教导要在构建.so文件时放置-fPIC的原因是为了确保多个进程可以使用同一代码,这些进程会将同一物理内存映射到各种虚拟地址。 实际上,它消除了所有绝对寻址,而用相对寻址或可以为每个进程分叉的小型跳转表代替它。
在2000年代初之前,PIC仅限于共享库。 可执行文件仍使用绝对寻址,不是PIC时可以依赖PIC,反之则不然。 随着地址空间布局随机化(ASLR)的出现,也使可执行文件与位置无关也变得有意义,这样攻击者就无法预测其内存映射,从而使缓冲区溢出漏洞更加复杂.
现在的操作系统将检查可执行文件是否与位置无关(PIE),如果启用,则启用ASLR。 默认情况下,编译器可能会或可能不会强制执行此操作,具体取决于您的系统。
实际上,位置独立共享库是从使用-fPIC构建的对象创建的,而位置独立可执行文件是从通过-fPIE构建的对象创建的。
这里需要注意的是如下几点:
- 可以从PIC或PIE对象(.o)和PIC或PIE静态库(.a)创建位置独立PIE的可执行文件
- 只能从PIC对象或静态库创建PIC共享库
- 可以从任何对象或静态库中创建非PIE可执行文件1
Linux下编译共享库时,必须加上-fPIC参数,否则在链接时会有错误提示。
如果-fPIE和-shared同时使用,生成的结果即可作为动态库,也可作为可执行程序。作为动态库时,必须满足:不存在main函数且模块中不存在对外输出的全局变量。这是因为-fPIE默认总是将生成的位置无关代码看作是属于程序本身。
PIC是在生成动态链接库时使用(Linux中的so),PIE是在生成可执行文件时使用。
反汇编
使用反汇编查看二进制文件
objdump -D mainprog
可以看到有一个段是main,这个段包含来实现C程序代码在系统上生成的汇编语言代码。
00000000004004e7 <main>:
4004e7: 55 push %rbp
4004e8: 48 89 e5 mov %rsp,%rbp
4004eb: 48 8d 3d e2 00 00 00 lea 0xe2(%rip),%rdi # 4005d4 <_IO_stdin_used+0x4>
4004f2: e8 f9 fe ff ff callq 4003f0 <puts@plt>
4004f7: b8 00 00 00 00 mov $0x0,%eax
4004fc: e8 29 00 00 00 callq 40052a <asmfunc>
400501: 48 8d 3d dc 00 00 00 lea 0xdc(%rip),%rdi # 4005e4 <_IO_stdin_used+0x14>
400508: e8 e3 fe ff ff callq 4003f0 <puts@plt>
40050d: b8 00 00 00 00 mov $0x0,%eax
400512: e8 13 00 00 00 callq 40052a <asmfunc>
400517: 48 8d 3d df 00 00 00 lea 0xdf(%rip),%rdi # 4005fd <_IO_stdin_used+0x2d>
40051e: e8 cd fe ff ff callq 4003f0 <puts@plt>
400523: b8 00 00 00 00 mov $0x0,%eax
400528: 5d pop %rbp
400529: c3 retq
000000000040052a <asmfunc>:
40052a: 48 c7 c0 01 00 00 00 mov $0x1,%rax
400531: 48 c7 c7 01 00 00 00 mov $0x1,%rdi
400538: 48 c7 c6 30 10 60 00 mov $0x601030,%rsi
40053f: 48 8b 14 25 5d 10 60 mov 0x60105d,%rdx
400546: 00
第一列是程序内存空间中的内存位置。第二列显示汇编语言代码生产的指令代码。
可以看到另一个段就是asmfunc。我们编译的时候是合在一起了。
第73部分- Linux x86 64位汇编 反汇编objdump
通过objdump可以进行反汇编操作。
通过objdump -d xxx可以查看二进制目标程序。
准备一个经典代码如下,我们进行编译,gcc -S disass.c -o disass.s,得到汇编代码。
#include <unistd.h>
int main(void) {
write(1, "Hello World\n", 15);
return 0;
}
得到的汇编代码如下:
.file "disass.c"
.text
.section .rodata
.LC0:
.string "Hello World\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $15, %edx
leaq .LC0(%rip), %rsi
movl $1, %edi
call write@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
.section .note.GNU-stack,"",@progbits
也可以编译成二进制文件后通过命令objdump命令进行反汇编。
第74部分- Linux x86 64位汇编hexdump
通过hexdump -C xx 可以看到二进制文件具体16进制和字符串显示情况。
例如下:
00000070 b8 01 00 00 00 cd 80 55 89 e5 83 ec 04 8b 5d 08 |.......U......].|
00000080 8b 4d 0c 89 5d fc 83 f9 01 74 0c 8b 45 fc 0f af |.M..]....t..E...|
00000090 c3 89 45 fc 49 eb ef 8b 45 fc 89 ec 5d c3 00 00 |..E.I...E...]...|
000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000b0 00 00 00 00 54 80 04 08 00 00 00 00 03 00 01 00 |....T...........|
000000c0 01 00 00 00 00 00 00 00 00 00 00 00 04 00 f1 ff |................|
000000d0 1e 00 00 00 77 80 04 08 00 00 00 00 02 00 01 00 |....w...........|
000000e0 09 00 00 00 86 80 04 08 00 00 00 00 00 00 01 00 |................|
000000f0 1a 00 00 00 97 80 04 08 00 00 00 00 00 00 01 00 |................|
00000100 13 00 00 00 54 80 04 08 00 00 00 00 10 00 01 00 |....T...........|
00000110 24 00 00 00 9e 90 04 08 00 00 00 00 10 00 01 00 |$...............|
00000120 30 00 00 00 9e 90 04 08 00 00 00 00 10 00 01 00 |0...............|
00000130 37 00 00 00 a0 90 04 08 00 00 00 00 10 00 01 00 |7...............|
00000140 00 70 6f 77 65 72 2e 6f 00 70 6f 77 65 72 5f 6c |.power.o.power_l|
00000150 6f 6f 70 5f 73 74 61 72 74 00 65 6e 64 5f 70 6f |oop_start.end_po|
00000160 77 65 72 00 5f 5f 62 73 73 5f 73 74 61 72 74 00 |wer.__bss_start.|
00000170 5f 65 64 61 74 61 00 5f 65 6e 64 00 00 2e 73 79 |_edata._end...sy|
00000180 6d 74 61 62 00 2e 73 74 72 74 61 62 00 2e 73 68 |mtab..strtab..sh|
00000190 73 74 72 74 61 62 00 2e 74 65 78 74 00 00 00 00 |strtab..text....|
000001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
第75部分- Linux x86 64位汇编 kdbg
在ubnut环境中通过apt install kdbg进行安装。
即可使用。
kdbg是一个带有图形化界面的调试器,可以在程序的任何地方暂停并观察变量值。
可以直接选择二进制文件进行debug, 文件编译的时候要加上-g参数,这样源码文件可以获取的。
F5(Run运行)使程序运行到结束或到达断点为止。 可以根据需要在程序中放置任意多个断点。
F8(Step Into)在程序中执行一行。 如果该行是函数调用,则跳至函数的第一行。
F10(Step Over)在程序中执行一行。 如果该行是函数调用,则整个函数将一步执行。
F6(Step Out)继续执行,直到返回当前函数或到达函数中的断点为止。
F7(Run to Cursor)将继续执行,直到计算机到达当前选择的源代码行或到达断点为止。 通过单击选择一条线。
编译时候加入-g参数,然后选择可执行文件进行运行。
类似的工具还有ddd图形化工具。
还有cgdb图形化工具, cgdb主要功能是在调试时进行代码的同步显示,增加了调试的方便性,提高了调试效率。
第76部分- Linux x86 64位汇编 CPUID
CPUID指令是一条汇编语言指令。
处理器把厂商字符串返回到ebx,edx和ecx寄存器中。
示例
如下:
-
#cpuid.s Sample program to extract the processor Vendor ID
-
.section .data
-
output:
-
.ascii "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
-
.section .text
-
.globl _start
-
_start:
-
movl $0, %eax;//选择功能0
-
cpuid
-
movl $output, %edi;//写地址到edi寄存器
-
movl %ebx, 28(%edi) ;//从ebx读结果出来
-
movl %edx, 32(%edi) ;//从edx读结果出来
-
movl %ecx, 36(%edi) ;//从ecx读结果出来
-
movl $4, %eax;//系统调用写到控制台上
-
movl $1, %ebx
-
movl $output, %ecx
-
movl $42, %edx
-
int $0x80
-
movl $60, %eax
-
syscall
第77部分- Linux x86 64位汇编 优化编译器代码-O1/-O2/-O3
仅仅使用汇编语言代码替换C或者C++不会必然使得程序执行的更好,因为编译器已经把所有高级语言代码都转化成了汇编语言。
这里的关键是编写比编译器生成的代码更好的汇编语言。当然也可以使用若干优化技巧来指示编译器生成汇编语言代码。我们需要了解如何从编译器生成代码,如何使用各种优化级别,以及利用了什么优化技术。
编译器的-O选项提供了GNU编译器的优化步骤。共有3个级别
-O:提供基础的级别的优化
-O2:提供更加高级的代码优化
-O3:提供最高级别的优化
O1优化
-O1支持如下的优化选项。
-fauto-inc-dec
-fbranch-count-reg
-fcombine-stack-adjustments
-fcompare-elim
-fcprop-registers
-fdce
-fdefer-pop
-fdelayed-branch
-fdse
-fforward-propagate
-fguess-branch-probability
-fif-conversion2
-fif-conversion
-finline-functions-called-once
-fipa-pure-const
-fipa-profile
-fipa-reference
-fmerge-constants
-fmove-loop-invariants
-freorder-blocks
-fshrink-wrap
-fshrink-wrap-separate
-fsplit-wide-types
-fssa-backprop
-fssa-phiopt
-ftree-bit-ccp
-ftree-ccp
-ftree-ch
-ftree-coalesce-vars
-ftree-copy-prop
-ftree-dce
-ftree-dominator-opts
-ftree-dse
-ftree-forwprop
-ftree-fre
-ftree-phiprop
-ftree-sink
-ftree-slsr
-ftree-sra
-ftree-pta
-ftree-ter
-funit-at-a-time
O2优化
-O2优化结合了第一个O1优化的所有优化技术,再加上了很多其他技术。
-fthread-jumps
-falign-functions -falign-jumps
-falign-loops -falign-labels
-fcaller-saves
-fcrossjumping
-fcse-follow-jumps -fcse-skip-blocks
-fdelete-null-pointer-checks
-fdevirtualize -fdevirtualize-speculatively
-fexpensive-optimizations
-fgcse -fgcse-lm
-fhoist-adjacent-loads
-finline-small-functions
-findirect-inlining
-fipa-cp
-fipa-bit-cp
-fipa-vrp
-fipa-sra
-fipa-icf
-fisolate-erroneous-paths-dereference
-flra-remat
-foptimize-sibling-calls
-foptimize-strlen
-fpartial-inlining
-fpeephole2
-freorder-blocks-algorithm=stc
-freorder-blocks-and-partition -freorder-functions
-frerun-cse-after-loop
-fsched-interblock -fsched-spec
-fschedule-insns -fschedule-insns2
-fstore-merging
-fstrict-aliasing -fstrict-overflow
-ftree-builtin-call-dce
-ftree-switch-conversion -ftree-tail-merge
-fcode-hoisting
-ftree-pre
-ftree-vrp
-fipa-ra
O3优化
O3选项访问编译器提供的最高级别。整合了O1和O2,还提供了非常专门的附加优化技术。
-finline-functions
-funswitch-loops
-fpredictive-commoning
-fgcse-after-reload
-ftree-loop-vectorize
-ftree-loop-distribute-patterns
-fsplit-paths
-ftree-slp-vectorize
-fvect-cost-model
-ftree-partial-pre
-fpeel-loops
-fipa-cp-clone
这些大家可以在
《Using the GNU Compiler Collection》中查看到。
第78部分- Linux x86 64位汇编 创建优化的代码
我们可以用gcc编译器从C程序创建编译器优化后的汇编代码,然后分析优化。
以tempconv.c文件为例,将华氏温度转为摄氏温度。
-
#include <stdio.h>
-
-
float convert(int deg)
-
{
-
float result;
-
result = (deg - 32.) / 1.8;
-
return result;
-
}
-
-
int main()
-
{
-
int i = 0;
-
float result;
-
printf(" Temperature Conversion Chart\n");
-
printf("Fahrenheit Celsius\n");
-
for(i = 0; i < 230; i = i + 10)
-
{
-
result = convert(i);
-
printf(" %d %5.2f\n", i, result);
-
}
-
return 0;
-
}
汇编之后得到汇编代码:
gcc -S tempconv.c
编译器产生汇编代码
汇编代码如下,我们将其进行了注释。:
-
.file "tempconv.c";//源文件名字
-
.text ;//定义代码段,是只读和可执行的,后面那些指令都属于.text段。
-
.globl convert ;//定义函数符号,.globl指示告诉汇编器,这个符号要被链接器用到,所以要在目标文件的符号表中标记它是一个全局符号
-
.type convert, @function ;//定义convert函数
-
convert:
-
.LFB0:
-
.cfi_startproc ;//函数开始符号
-
pushq %rbp;//压栈rbp保存
-
.cfi_def_cfa_offset 16;// CFA(Canonical Frame Address),CFA定义为调用站点上的前一帧的堆栈指针的值, CFA现在与当前堆栈指针的偏移量为16个字节。CFI是CFI代表调用帧信息.
-
.cfi_offset 6, -16;//CFI指令用于调试。 它允许调试器展开堆栈。寄存器的先前值保存在与CFA偏移的位置。register 6
-
movq %rsp, %rbp;//复制当前rsp到rbp中
-
.cfi_def_cfa_register 6;// .cfi_def_cfa_register修改用于计算CFA的规则。将使用寄存器而不是旧的寄存器。 偏移量保持不变。register 6
-
movl %edi, -20(%rbp) ;//复制edi到rbp中,在堆栈下方空地处,这里就是函数参数
-
cvtsi2sd -20(%rbp), %xmm0;//将参数,从 1个双字有符号整数变成1个双精度浮点数,到xmm0中。
-
movsd .LC0(%rip), %xmm1;//将双字节32传送到xmm1中。
-
subsd %xmm1, %xmm0
-
movsd .LC1(%rip), %xmm1;//将双字节1.8传送到xmm1中。
-
divsd %xmm1, %xmm0;//除以1.8
-
cvtsd2ss %xmm0, %xmm2;// 将双精度转换为单精度浮点值
-
-
movss %xmm2, -4(%rbp);//结果移动到堆栈
-
movss -4(%rbp), %xmm0;//通过xmm0返回
-
popq %rbp
-
.cfi_def_cfa 7, 8
-
ret ;//函数返回
-
.cfi_endproc ;//函数结束符号
-
.LFE0:
-
.size convert, .-convert;//函数字节数量
-
.section .rodata;//只读段
-
.align 8 ;// .align的作用在于对指令或者数据的存放地址进行对齐,有些CPU架构要求固定的指令长度并且存放地址相对于2的幂指数圆整,否则程序无法正常运行,如arm。.align的作用范围只限于紧跟它的那条指令或者数据,而接下来的指令或者数据的地址由上一条指令的地址和其长度决定。
-
.LC2:
-
.string " Temperature Conversion Chart" ;//定义字符串
-
.LC3:
-
.string "Fahrenheit Celsius" ;//定义字符串
-
.LC4:
-
.string " %d %5.2f\n"
-
.text ;//定义代码段,只读并可执行
-
.globl main
-
.type main, @function ;//定义main函数
-
main:
-
.LFB1:
-
.cfi_startproc;//函数开始符号
-
pushq %rbp;//压栈rbp保存
-
.cfi_def_cfa_offset 16;// CFA现在与当前堆栈指针的偏移量为16个字节
-
.cfi_offset 6, -16;//6号寄存器是rbp
-
movq %rsp, %rbp;//复制当前rsp到rbp中
-
.cfi_def_cfa_register 6
-
subq $16, %rsp;//腾出堆栈空地,2格。
-
movl $0, -8(%rbp) ;//复制本地变量0到堆栈中。
-
leaq .LC2(%rip), %rdi;//字符串地址赋值给rdi,调用输出函数puts,源代码中的printf
-
call puts@PLT
-
leaq .LC3(%rip), %rdi;// 字符串地址赋值给rdi,调用输出函数puts, 源代码中的printf
-
call puts@PLT
-
movl $0, -8(%rbp) ;//复制本地变量i=0到堆栈中
-
jmp .L4
-
.L5:
-
movl -8(%rbp), %eax;//复制本地变量i到eax
-
movl %eax, %edi;//复制本地变量i到edi
-
call convert;//调用函数convert。
-
movd %xmm0, %eax;//从xmm0获取结果
-
movl %eax, -4(%rbp)
-
cvtss2sd -4(%rbp), %xmm0;// 将单精度转换为双精度浮点值
-
movl -8(%rbp), %eax;//华氏摄氏度,取出->eax->esi,调用printf
-
movl %eax, %esi;//华氏设置度整型放于esi.
-
leaq .LC4(%rip), %rdi;//字符串地址。
-
movl $1, %eax
-
call printf@PLT;//调用printf函数
-
addl $10, -8(%rbp) ;//调用增加10给变量i,即是for中i+10
-
.L4:
-
cmpl $229, -8(%rbp);//对比229和-8(%rbp)的变量,就是for循环中的比较
-
jle .L5;//小于等于就调整到.L5,否则就退出程序。
-
movl $0, %eax;//移动0到eax,函数返回。
-
leave;// Leave的作用相当mov esp,ebp和pop ebp。
-
.cfi_def_cfa 7, 8;//7号寄存器是rsp。实现rsp+8。
-
ret
-
.cfi_endproc;//函数开始符号
-
.LFE1:
-
.size main, .-main;//该函数的函数字节数
-
.section .rodata;//只读段,不可执行
-
.align 8
-
.LC0:;//保存32浮点。
-
.long 0
-
.long 1077936128
-
.align 8
-
.LC1: ;//保存1.8浮点。
-
.long 3435973837
-
.long 1073532108
-
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0";//GCC注释,连接器会移除。
-
.section .note.GNU-stack,"",@progbits
这里的.section是汇编指示(Assembler Directive)或叫做伪操作(Pseudo-operation)
.section指示把代码划分成若干个段(Section),程序被操作系统加载执行时,每个段被加载到不同的地址,操作系统对不同的页面设置不同的读、写、执行权限。
这里的CFA描述如下:
: :
| whatever | <--- CFA
+----------------+
| return address |
+----------------+
| reserved space | <--- %rsp == CFA - 16
+----------------+
使用.cfi_def_cfa_offset指令在调试信息中声明了堆栈指针的更改,并且可以看到CFA现在与当前堆栈指针的偏移量为16个字节。
优化后代码分析
注释结束后,我们看下优化点分析。
#gcc -S -O3 tempconv3.s tempconv.c
-
.file "tempconv.c"
-
.text
-
.p2align 4,,15
-
.globl convert
-
.type convert, @function
-
convert:
-
.LFB23:
-
.cfi_startproc
-
pxor %xmm0, %xmm0;//异或清零
-
cvtsi2sd %edi, %xmm0;//是参数,华氏摄氏度。
-
subsd .LC0(%rip), %xmm0;//直接减去LC0中的38
-
divsd .LC1(%rip), %xmm0;//直接除去LC1中的1.8。
-
cvtsd2ss %xmm0, %xmm0;//转化为单精度。
-
ret
-
.cfi_endproc
-
.LFE23:
-
.size convert, .-convert
-
.section .rodata.str1.8,"aMS",@progbits,1
-
.align 8
-
.LC2:
-
.string " Temperature Conversion Chart"
-
.section .rodata.str1.1,"aMS",@progbits,1
-
.LC3:
-
.string "Fahrenheit Celsius"
-
.LC4:
-
.string " %d %5.2f\n"
-
.section .text.startup,"ax",@progbits
-
.p2align 4,,15
-
.globl main
-
.type main, @function
-
main:
-
.LFB24:
-
.cfi_startproc
-
pushq %rbp
-
.cfi_def_cfa_offset 16
-
.cfi_offset 6, -16
-
pushq %rbx;//保存rbx寄存器
-
.cfi_def_cfa_offset 24
-
.cfi_offset 3, -24
-
leaq .LC2(%rip), %rdi
-
leaq .LC4(%rip), %rbp
-
xorl %ebx, %ebx;//ebx清零
-
subq $8, %rsp
-
.cfi_def_cfa_offset 32
-
call puts@PLT
-
leaq .LC3(%rip), %rdi
-
call puts@PLT
-
.p2align 4,,10
-
.p2align 3
-
.L4:
-
pxor %xmm0, %xmm0
-
movl %ebx, %edx
-
movq %rbp, %rsi
-
movl $1, %edi
-
movl $1, %eax
-
cvtsi2sd %ebx, %xmm0
-
addl $10, %ebx
-
subsd .LC0(%rip), %xmm0
-
divsd .LC1(%rip), %xmm0
-
cvtsd2ss %xmm0, %xmm0
-
cvtss2sd %xmm0, %xmm0
-
call __printf_chk@PLT
-
cmpl $230, %ebx
-
jne .L4
-
addq $8, %rsp
-
.cfi_def_cfa_offset 24
-
xorl %eax, %eax
-
popq %rbx
-
.cfi_def_cfa_offset 16
-
popq %rbp
-
.cfi_def_cfa_offset 8
-
ret
-
.cfi_endproc
-
.LFE24:
-
.size main, .-main
-
.section .rodata.cst8,"aM",@progbits,8
-
.align 8
-
.LC0:
-
.long 0
-
.long 1077936128
-
.align 8
-
.LC1:
-
.long 3435973837
-
.long 1073532108
-
.ident "GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0"
-
.section .note.GNU-stack,"",@progbits
可以通过如下直接汇编执行
#as -o tempconv3.o tempconv3.s
#gcc -o tempconv3 tempconv3.o
我们发现main中其实没有调用convert函数了,被优化掉了,功能被直接嵌入到main函数中了。
而convert函数本身也是被大量精简化了。
参考
这里由于细节比较多,加入了一个参考链接,关于cfi的描述。
https://sourceware.org/binutils/docs-2.17/as/CFI-directives.html#CFI-directives
CFI directives in assembly files
第79部分- Linux x86 64位汇编 优化技巧
优化汇编主要是5中常用的方法:
优化运算/优化变量/优化循环/优化条件分支/优化通用子表达式。
减少运算过程中的局部变量的大量使用。
处理变量有3种方式:使用.data或者.bss段内存中定义变量/堆栈中定义局部变量/使用可用的寄存器。将全局变量存储在FPU中,有个好处是,在使用存储到FPU时候会有固定的延时,但是处理器可以处理其他指令。
优化循环是应用程序中最消耗时间的部分之一。分支对性能的影响可能是灾难性的。预加载到指令缓存中的指令完全失去了利用价值。优化循环,要么是消除要么简化,使用的手段是循环展开。会导致程序变化,具体要看性能提高的收益是否超过程序。
优化条件分支会破坏预加载到指令缓存中的指令,如果采用了没有预测到的分支,就会导致处理器进行额外的工作。代码可以减少实现双重if-then-else语句需要的代码数量。
通用表达式使用,可以计算一次永久收益,不用反复进行计算。
第80部分- Linux x86 64位汇编 使用文件
我们知道C或者C++进行程序设计有函数fopen/read/write。汇编中如何呢?
汇编语言程序中处理数据文件时必须使用特定的顺序。通过Linux系统调用执行。
打开
先来按下open系统调用如下:
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
通过arch/x86/entry/syscalls/syscall_64.tbl中查看:
2 common open __x64_sys_open
系统调用号是2.
打开模式如下:
例如创建文件并且打开用于读写访问:
可以使用$0102
新数据文件追加到已有的文件,可以使用:
$02002
模式可以入下:
#define S_IRWXU 00700 文件所有者可读可写可执行
#define S_IRUSR 00400 文件所有者可读
#define S_IWUSR 00200 文件所有者可写
#define S_IXUSR 00100 文件所有者可执行
#define S_IRWXG 00070 文件用户组可写可读可执行
#define S_IRGRP 00040 文件用户组可读
#define S_IWGRP 00020 文件用户组可写
#define S_IXGRP 00010 文件用户组可执行
#define S_IRWXO 00007 其他用户可写可读可执行
#define S_IROTH 00004 其他用户可读
#define S_IWOTH 00002 其他用户可写
#define S_IXOTH 00001 其他用户可执行
-
- read文件
读文件使用系统调用
ssize_t read(int fd, void *buf, size_t count);
系统调用号是0.
写入文件
写入文件使用系统调用write.
ssize_t write(int fd, const void *buf, size_t count);
系统调用号是1.
关闭文件
int close(int fd);
系统调用号是3.
我们来看下示例如下。
写示例
-
.section .data
-
-
filename:
-
.asciz "cpuid.txt"
-
output:
-
.asciz "The processor Vendor ID is 'xxxxxxxxxxxx'\n"
-
.section .bss
-
.lcomm filehandle, 4
-
.section .text
-
.globl _start
-
_start:
-
movl $0, %eax
-
cpuid;//调用cpuid指令
-
movl $output, %edi;//保存结果到字符串中
-
movl %ebx, 28(%edi)
-
movl %edx, 32(%edi)
-
movl %ecx, 36(%edi)
-
-
movl $2, %eax;//打开文件,系统调用open
-
movq $filename, %rdi;//文件名
-
movq $01101, %rsi;//打开模式,重新创建用于写。
-
movq $0644, %rdx;//权限。
-
-
syscall
-
-
test %eax, %eax;//测试返回值
-
js badfile
-
movl %eax, filehandle;//否则返回保存eax文件句柄到filehandle
-
-
movl $1, %eax;//进行写
-
movq filehandle, %rdi;//参数句柄
-
movq $output, %rsi;//参数字符串
-
movq $42, %rdx;//参数字符串数量
-
syscall
-
test %eax, %eax
-
js badfile
-
-
movq $3, %rax;//关闭
-
movq filehandle, %rdi;//对应的句柄
-
syscall
-
-
badfile:
-
movq %rax, %rbx
-
movq $60, %rax
-
syscall;//退出
as -g -o cpuidfile.o cpuidfile.s
ld -o cpuidfile cpuidfile.o
然后执行,
./cpuidfile可以发现执行成功。
读写示例
读后写入文件的示例
-
.section .bss
-
.lcomm buffer, 10
-
.lcomm filehandle, 4
-
.section .text
-
.globl _start
-
_start:
-
nop
-
movq %rsp, %rbp;//赋值rsp给rbp。
-
movl $2, %eax;//打开文件open系统调用
-
movq 16(%rbp), %rdi;//使用输入的参数为文件名字
-
movq $00, %rsi;//flag为只读
-
movq $0444, %rdx;//权限为只读
-
syscall
-
test %eax, %eax
-
js badfile
-
movl %eax, filehandle;//保存文件句柄,给read/write的系统调用使用
-
-
read_loop:
-
movl $0, %eax
-
movq filehandle, %rdi;//文件句柄
-
movq $buffer, %rsi
-
movq $10, %rdx;//每次10个
-
syscall
-
test %eax, %eax
-
jz done;//读完跳出
-
js done
-
movl %eax, %edx
-
-
movl $1, %eax;//写入系统调用
-
movq $1, %rdi;//写到stdout
-
movq $buffer, %rsi;//字符串
-
syscall
-
test %eax, %eax
-
js badfile
-
jmp read_loop
-
-
done:
-
movl $3, %eax
-
movq filehandle, %rdi
-
syscall
-
-
badfile:
-
movl %eax, %ebx
-
movl $60, %eax
-
syscall
as -g -o readwrite.o readwrite.s
ld -o readwrite readwrite.o
这里需要有个参数,就是一个文件名字。
将文件中的内容独处后放入到缓存中,然后将将缓存中写到stdout中。每次10个字节,使用更大块的长度可以减少read调用次数提高性能。
读后处理写入示例
相比上一个示例,这个示例增加数据处理的步骤。从文件读取数据,然后处理数据,最后把数据写入到另一个文件中。
-
.section .bss
-
.lcomm buffer, 10
-
.lcomm infilehandle, 8
-
.lcomm outfilehandle, 8
-
.lcomm size, 4
-
.section .text
-
.globl _start
-
_start:
-
# open input file, specified by the first command line param
-
movl $2, %eax;//open系统调用
-
movq 16(%rsp), %rdi;//第一个参数,程序运行后栈指向的分别是参数数量/程序名字
-
movq $00, %rsi;//只读
-
movq $0444, %rdx;//权限
-
syscall
-
test %rax, %rax
-
js badfile
-
movq %rax, infilehandle;//保存输入文件的句柄
-
-
movl $2, %eax;// open系统调用,打开另一个文件
-
movq 24(%rsp), %rdi;// 第二个参数
-
movq $01101, %rsi;//创建新文件,模式是写,
-
movq $0644, %rdx;//权限
-
syscall
-
test %rax, %rax;//出现负数则跳转
-
js badfile
-
movq %rax, outfilehandle;//保存输出文件句柄
-
-
# 从输入文件句柄中读取
-
read_loop:
-
movl $0, %eax;// read系统调用
-
movq infilehandle, %rdi
-
movq $buffer, %rsi
-
movq $10, %rdx;//每次读取10个字节
-
syscall
-
test %rax, %rax
-
jz done
-
js badfile
-
movl %eax, size
-
-
movq $buffer,%rdi;//字符串参数指针
-
movq size,%rsi;// 第二个参数,已读出的字节数量。
-
call convert;//调用convert函数
-
-
# 将转换后的数据存放 output file
-
movl $1, %eax ;// write系统调用
-
movq outfilehandle, %rdi
-
movq $buffer,%rsi
-
syscall
-
test %rax,%rax
-
js badfile
-
jmp read_loop
-
-
done:;//读取完毕后跳转到done处
-
movl $3,%eax
-
movq outfilehandle,%rdi
-
syscall;//关闭输出文件句柄
-
-
movl $3,%eax
-
movq infilehandle,%rdi
-
syscall;//关闭输入文件句柄
-
-
badfile:
-
movl %eax,%ebx
-
movl $60,%eax
-
syscall
-
-
.type convert,@function
-
convert:
-
movq %rsi,%rcx;//第二个参数是字符数量,赋值为rcx.
-
movq %rdi,%rsi;//第二个参数是rdi指向源字符串的内存位置,要赋值给rsi
-
-
convert_loop:
-
lodsb;//加载字符串字节到al寄存器,rsi指向源字符串的内存位置
-
cmpb $0x61,%al;//是否小于0x61,即97,小于则跳过
-
jl skip
-
cmpb $0x7a,%al;//是否大于于0x7a,即122,大于也跳过
-
jg skip
-
sub $0x20,%al;//改成小写
-
skip:
-
stosb;//重新加载al到rdi的字符串,就是源字符串地址。
-
loop convert_loop
-
ret
as -g -o readchange.o readchange.s
ld -o readchange readchange.o
可以执行如下
#readchange readchange.s out.txt
会将readchange.s文件中的内容转为大写并保存到了Out.txt文件中。
第81部分- Linux x86 64位汇编 内存映射文件
上个例子中,如果执行如下:
#readchange readchange.s readchange.s
则会发现readchange.s会空了。
因为系统不能在读取一个文件的同时把数据写入到同一个文件。
但是很多应用程序中涉及到更新文件,一种方法称为内存映射文件。
系统调用号文件:arch/x86/entry/syscalls/syscall_64.tbl
内存映射文件
内存映射文件调用mmap把部分文件映射到系统的内存中。程序可以使用标准的内存指令访问内存位置,还可以修改,可以在多个进程之间共享内存位置并同时更新。
内存映射文件是保存在内存中的,没有同步到原始文件,如果要同步到原始文件,需要调用msync/munmap系统调用。
mmap
这里涉及到的系统调用是mmap,系统调用号是9.
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr是内存中的什么位置映射文件。可以为0,系统选择位置。
length是加载到内存中的字节数量,设置为0,长度为文件长度。如果使用了offset值,则必须是系统页面长度的倍数。例如4k/8K……
prot是内存保护设置,可以是PROT_NONE/PROT_READ/PROT_WRITE/PROT_EXEC。
flags是创建的映射对象的类型,可以是MAP_SHARE/MAP_PRIVATE。
fd是要映射到内存的文件的文件句柄
offset是文件中要复制到内存的数据的起点。
msync
int msync(void *addr, size_t length, int flags);
输入值addr是内存映射文件在内存中的开始位置。调用mmap返回这个值。
Length是要写入原始文件的字节数量。
flags定义如何更新原始文件
MS_ASYNC:下次可以写入文件时安排更新,并且系统调用返回。
MS_SYNC:系统调用等待,知道做出更新,然后再返回调用程序。
内存映射文件是不能改动原始文件的长度的。
系统调用号是26.
munmap
int munmap(void *addr, size_t length);
是mmap系统调用的逆向操作。
系统调用号是11.
mmap示例
通过系统调用mmap吧整个文件映射到内存中、修改内存映射文件中的数据以及数据写回原始文件。
先通过lseek获取文件的长度。
lseek系统调用号是8.
off_t lseek(int fd, off_t offset, int whence);
整体逻辑如下:
- 使用读/写访问打开文件
- 使用函数sizefunc确定文件长度
- 使用系统调用mmap把文件映射到内存中
- 把内存映射文件的全部内容转化为大写字母
- 使用munmap把内存映射文件写入原始文件
- 关闭原始文件并且推出。
代码如下:
-
.code64;//本来没有这个伪代码,开发过程发现有个movq指令被截断成移动4个字节了,所以加上可以规避这个问题。
-
.section .bss
-
.lcomm filehandle, 8
-
.lcomm size, 8
-
.lcomm mappedfile, 8
-
.section .text
-
.globl _start
-
_start:
-
# 获取文件名字并以读写模式打开
-
movl $2, %eax;//打开系统调用
-
movq 16(%rsp), %rdi;//获取第一个参数,前两个是参数数量和程序名字
-
movq $0102, %rsi;//读写访问权限
-
movq $0644, %rdx;//644文件权限
-
syscall
-
test %eax, %eax
-
js badfile
-
movl %eax, filehandle;//保存到filehandle中
-
-
# 寻找文件的大小
-
movl filehandle,%edi
-
call sizefunc;//调用函数sizefunc
-
movl %eax,size;//通过eax返回,并赋值给size中。
-
-
# 映射文件到内存中,void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
-
-
movq $0,%rdi;//由系统分配内存空间
-
movq size,%rsi;//长度length
-
movq $3,%rdx;//prot是 PROT_READ | PROT_WRITE
-
movq $1,%r10;// flags是MAP_SHARED,函数调用的第四个参数是rcx的,但是系统调用的话就是r10。
-
movq filehandle,%r8;//句柄
-
movq $0,%r9;//offset
-
movq $9, %rax;//系统调用mmap
-
syscall
-
test %rax, %rax
-
js badfile
-
movq %rax, mappedfile;//文件句柄,这里被截断成movl指令了,加上.code64规避
-
-
# 将内存映射文件中的字符变为大写的
-
movq mappedfile,%rdi
-
movq size,%rsi
-
call convert;//调用convert函数
-
-
# 使用munmap将修改的文件同步到原来文件中。
-
movl $11, %eax
-
movq mappedfile, %rdi
-
movq size, %rsi
-
syscall
-
test %eax, %eax
-
jnz badfile
-
-
# 关闭文件句柄
-
movl $3, %eax
-
movl filehandle, %edi
-
syscall
-
-
badfile:
-
movl %eax, %ebx
-
movl $60, %eax
-
syscall
-
-
.type sizefunc, @function;//函数sizefunc
-
sizefunc:
-
movl $8, %eax;//lseek系统调用号是8
-
movq $0, %rsi;//第一个参数是rdi,第二个参数是rsi,表示offset,从0开始。
-
movq $2, %rdx;//第三个参数,到达文件结尾SEEK_END即是2.
-
syscall
-
ret
-
-
.type convert,@function;//convert函数
-
convert:
-
movq %rsi,%rcx;//第二个参数是字符数量,赋值为rcx.
-
movq %rdi,%rsi;//第二个参数是rdi指向源字符串的内存位置,要赋值给rsi
-
-
convert_loop:
-
lodsb;//加载字符串字节到al寄存器,rsi指向源字符串的内存位置
-
cmpb $0x61,%al;//是否小于0x61,即97,小于则跳过
-
jl skip
-
cmpb $0x7a,%al;//是否大于于0x7a,即122,大于也跳过
-
jg skip
-
sub $0x20,%al;//改成小写
-
skip:
-
stosb;//重新加载al到rdi的字符串,就是源字符串地址。
-
loop convert_loop
-
ret
as -g -o mmapdemo.o mmapdemo.s
ld -o mmapdemo mmapdemo.o
执行如下:
#cp mmapdemo.s mmaptest.s
#./mmapdemo mmaptest.s
在使用gdb调试前,可以使用strace ./mmapdemo mmaptest.s来看下系统调用情况。
这里要注意的是mmap的系统调用第四个参数被放到了r10寄存器了。
第82部分- Linux x86 64位汇编 参考
NASM
https://nasm.us/doc/nasmdoc4.html
ATT
《Professional Assembly Language》
处理器
编译器
GCC官方文档
函数约定
系统调用约定
1、windows 64位调用约定
windows64 位的调用很是奇怪,因为它不是通过栈来传参,而是通过寄存器来传参!
最为常见的是,当参数只有一个的时候,一般是选用rcx来传递参数!
2、Linux 32位调用约定
Linux 32位的系统调用时通过int 80h来实现的,eax寄存器中为调用的功能号,ebx、ecx、edx、esi等等寄存器则依次为参数。下面我们来看看hello world程序:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
.section .data
msg:
.ascii "Hello world!\n"
.section .text
.globl _start
_start:
movl $4, %eax
movl $1, %ebx
movl $msg, %ecx
movl $13, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
|
从 /usr/include/asm/unistd.h中可以看到exit的功能号_NR_exit为1,write(_NR_write)功能号为4,因此第一个int 0x80调用之前eax寄存器值为4,ebx为文件描述符,stdout的文件描述符为1,ecx则为buffer的内存地址,edx为buffer长度。第二个int 0x80之前eax为1表示调用exit,ebx为0表示返回0。
系统调用功能好可以参考System Call Number Definition
以及http://asm.sourceforge.net/syscall.html#2
或者 http://syscalls.kernelgrok.com/ 查找(推荐!)
2.1 系统调用及参数传递过程
这部分具体可以参考:
系统调用及参数传递过程
深入理解Linux的系统调用
我们以x86为例说明:
由于陷入指令是一条特殊指令,而且依赖与操作系统实现的平台,如在x86中,这条指令是int 0x80,这显然不是用户在编程时应该使用的语句,因为这将使得用户程序难于移植。所以在操作系统的上层需要实现一个对应的系统调用库,每个系统调用都在该库中包含了一个入口点(如我们看到的fork, open, close等等),这些函数对程序员是可见的,而这些库函数的工作是以对应系统调用号作为参数,执行陷入指令int 0x80,以陷入核心执行真正的系统调用处理函数。当一个进程调用一个特定的系统调用库的入口点,正如同它调用任何函数一样,对于库函数也要创建一个栈帧。而当进程执行陷入指令时,它将处理机状态转换到核心态,并且在核心栈执行核心代码。
这里给出一个示例(linux/include/asm/unistd.h):
1
2
3
4
5
6
7
8
9
10
|
type name(type1 arg1,type2 arg2) \
{ \
long __res; \
__asm__ volatile (
\:
(__res) \:
(__NR_##name), ((long)(arg1)), ((long)(arg2))); \. . . . . .
__syscall_return(type,__res); \
}
|
在执行一个系统调用库中定义的系统调用入口函数时,实际执行的是类似如上的一段代码。这里牵涉到一些gcc的嵌入式汇编语言,不做详细的介绍,只简单说明其意义:
其中\_\NR\##name是系统调用号,如name == ioctl,则为\_\_NR\_ioctl,它将被放在寄存器eax中作为参数传递给中断0x80的处理函数。而系统调用的其它参数arg1, arg2, …则依次被放入ebx, ecx, . . .等通用寄存器中,并作为系统调用处理函数的参数,这些参数是怎样传入核心的将会在后面介绍。
注意该调用是从左至右依次传参,与普通函数的由右往左依次传参不同
3、Linux 64位调用约定
现在,我们将要讨论的是64位的系统调用。不过在此之前,我们需要知道linux的两个有关系统调用的重要文件unistd\_32.h和unistd\_64.h,这两个文件定义了系统调用号!
3.1 每种调用号需要传递哪些参数
在linux系统中某个程序执行时进行的系统调用可以通过strace命令来查看,solaris中对应的命令为dtrace,而mac os x中可以通过类似的dtruss命令来查看。当进程已经处于 D 状态(uninterruptible sleep)时,strace 也帮不上忙。这时候可以通过:
cat /proc//syscall
来查看。(详细内容可以到http://www.jb51.net/article/50923.htm查看)
32位的系统调用表的参数可以到 http://syscalls.kernelgrok.com/ 查找;关于32位系统中使用汇编语言调用syscall table,将在另一篇博文[linux下32位汇编的系统调用]中详述。
而在64位系统中,大神说了:可以通过grep在源代码中查找:
To find the implementation of a system call, grep the kernel tree for SYSCALL_DEFINE.\?(syscall,
For example, to find the read system call:
1
2
3
4
5
|
illusion:/usr/src/linux-source-3.19$ grep -rA3 'SYSCALL_DEFINE.\?(read,' *
fs/read_write.c:SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
fs/read_write.c-{
fs/read_write.c- struct file *file;
fs/read_write.c- ssize_t ret = -EBADF;
|
也可以在以下网址中查找:
http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
3.2 调用如何传递参数以及结果如何返回
在64位linux中,一般来说系统调用的参数统统放在寄存器中,最多可以用到6个寄存器;如果多余6个参数的系统调用怎么传递参数?这个还不清楚,有的文档说64位系统调用的参数最多不会超过6个;还有的文档说超过6个参数的话,其余参数全部通过堆栈来传递。超过6个参数的系统调用,本猫没有实际碰到,也不知到底该怎么办!?就这个问题,有兴趣的童鞋可以和本猫单独切磋讨论。
具体调用规则如下:
-
用户模式的系统调用依次传递的寄存器为:
rdi,rsi,rdx,rcx,r8和r9
-
内核接口的系统调用一次传递的寄存器为:
rdi,rsi,rdx,r10,r8和r9
注意这里和用户模式的系统调用只有第4个寄存器不同,其他都相同。
-
系统调用通过syscall指令进入,不像32位下的汇编使用的是int 0x80指令;
-
系统调用号放在rax寄存器里;
-
系统调用限制最多6个参数,没有参数直接通过栈传递,原话是:
System-calls are limited to six arguments, no argument is passed directly on the stack
- 系统调用的返回结果,也就是syscall指令的返回放在rax寄存器中;
- 只有整形值和内存型的值可以传递给内核,这个也不十分明白,原话是:
Only values of class INTEGER or class MEMORY are passed to the kernel
有的童鞋可能要问了,要是浮点数怎么传递给接口!?有参数是浮点数的系统调用吗?这个还真不清楚,不过参数是浮点数的C标准库函数的调用那是大大的有,这个等到在另一篇博文[64汇编调用C标准库函数]中再详细给大家解答。
4、Linux系统调用实例
代码的功能很简单,显示一行文本,然后退出。我们使用了syscall中的write和exit调用,查一下前面的调用号和参数,我们初步总结如下:
write(即sys_write)调用号为1,需传递3个参数
1
2
3
|
unsigned int fd
const char *buf
size_t count
|
exit(sys_exit)调用号为60,只需传递一个错误码
1
|
int error_code
|
如果该值为0表示程序执行成功。
因为以上两个调用最多的也只有3个参数,所以我们依次只会用到3个寄存器rdi,rsi和rdx。
实际代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
section .text
;if use ld
global _start
;if use gcc
;global main
_start:
;main
mov rax,1 ;write NO
mov rdi,1 ;fd
mov rsi,msg ;addr of msg string
mov rdx,msg_len ;lenght of msg string
syscall
mov rax,60 ;exit NO
mov rdi,0 ;error_code
syscall
msg: db "Hello World!",0xa
msg_len:equ $-msg
|
编译连接命令如下:
1
2
|
nasm -f elf64 p.s
ld -o p p.o
|
如果是mac os x系统下命令如下:
1
2
|
nasm -f macho64 p.s
ld -o p p.o
|
如果你要生成32位的代码,在编译时把elf64改为elf32就可以了,不过我前面说过:32位和64位汇编结构变化较大,光改这个是没办法运行成功的。
不出所料代码运行输出一行:Hello World!并且程序返回后用echo $?看,应该为0.
这个例子很简单,下面看一下稍微复杂点的调用:mmap,该调用共有6个参数,我们再一次总结如下:
mmap(sys_mmap) 系统调用号为9,参数分别为:
1
2
3
4
5
6
|
unsigned long addr
unsigned long len
unsigned long prot
unsigned long flags
unsigned long fd
unsigned long offset
|
第一个参数是需要映射到的地址,我们这里传0,表示不关心映射到哪;第二个参数是映射空间的大小;第三个参数表示映射区域的保护方式,有很多种,我们这里只让它可读可写即可,所以只用到2者的组合:
PROT_WRITE|PROT_READ
第四个参数是映射区域的一些特性,有很多组合。这里只用MAP_SHARED|MAP_ANONYMOUS,后者表示建立匿名映射,会忽略参数fd,所以不设及文件。
第五个参数就是fd,前面说了可以忽略,所以我们传递-1;最后一个参数是映射的偏移量,我们也传递0.
该调用如果成功返回映射区域内存的起始地址,否则返回MAP_FAILED(-1),错误原因存于errno中,我们可以用strerror(errno)查看具体含义。不过该函数是C库中的,这里我们捎带的用一下。
提到mmap我们不得不提到munmap,用猜大家也知道该调用的含义吧:
munmap(sys_munmap) 调用号为11,需传递2个参数:
1
2
|
unsigned long start
size_t len
|
5、函数查询
例如execve的函数查询http://man7.org/linux/man-pages/man2/execve.2.html
6、附录
6.1 32系统调用表
# | Name | Registers | Definition | |||||
---|---|---|---|---|---|---|---|---|
eax | ebx | ecx | edx | esi | edi | |||
0 | sys_restart_syscall | 0x00 | - | - | - | - | - | kernel/signal.c:2058 |
1 | sys_exit | 0x01 | int error_code | - | - | - | - | kernel/exit.c:1046 |
2 | sys_fork | 0x02 | struct pt_regs * | - | - | - | - | arch/alpha/kernel/entry.S:716 |
3 | sys_read | 0x03 | unsigned int fd | char __user *buf | size_t count | - | - | fs/read_write.c:391 |
4 | sys_write | 0x04 | unsigned int fd | const char __user *buf | size_t count | - | - | fs/read_write.c:408 |
5 | sys_open | 0x05 | const char __user *filename | int flags | int mode | - | - | fs/open.c:900 |
6 | sys_close | 0x06 | unsigned int fd | - | - | - | - | fs/open.c:969 |
7 | sys_waitpid | 0x07 | pid_t pid | int __user *stat_addr | int options | - | - | kernel/exit.c:1771 |
8 | sys_creat | 0x08 | const char __user *pathname | int mode | - | - | - | fs/open.c:933 |
9 | sys_link | 0x09 | const char __user *oldname | const char __user *newname | - | - | - | fs/namei.c:2520 |
10 | sys_unlink | 0x0a | const char __user *pathname | - | - | - | - | fs/namei.c:2352 |
11 | sys_execve | 0x0b | char __user * | char user *user * | char user *user * | struct pt_regs * | - | arch/alpha/kernel/entry.S:925 |
12 | sys_chdir | 0x0c | const char __user *filename | - | - | - | - | fs/open.c:361 |
13 | sys_time | 0x0d | time_t __user *tloc | - | - | - | - | kernel/posix-timers.c:855 |
14 | sys_mknod | 0x0e | const char __user *filename | int mode | unsigned dev | - | - | fs/namei.c:2067 |
15 | sys_chmod | 0x0f | const char __user *filename | mode_t mode | - | - | - | fs/open.c:507 |
16 | sys_lchown16 | 0x10 | const char __user *filename | old_uid_t user | old_gid_t group | - | - | kernel/uid16.c:27 |
17 | not implemented | 0x11 | - | - | - | - | - | |
18 | sys_stat | 0x12 | char __user *filename | struct old_kernel_stat user *statbuf | - | - | - | fs/stat.c:150 |
19 | sys_lseek | 0x13 | unsigned int fd | off_t offset | unsigned int origin | - | - | fs/read_write.c:167 |
20 | sys_getpid | 0x14 | - | - | - | - | - | kernel/timer.c:1337 |
21 | sys_mount | 0x15 | char __user *dev_name | char __user *dir_name | char __user *type | unsigned long flags | void __user *data | fs/namespace.c:2118 |
22 | sys_oldumount | 0x16 | char __user *name | - | - | - | - | fs/namespace.c:1171 |
23 | sys_setuid16 | 0x17 | old_uid_t uid | - | - | - | - | kernel/uid16.c:67 |
24 | sys_getuid16 | 0x18 | - | - | - | - | - | kernel/uid16.c:212 |
25 | sys_stime | 0x19 | time_t __user *tptr | - | - | - | - | kernel/time.c:81 |
26 | sys_ptrace | 0x1a | long request | long pid | long addr | long data | - | kernel/ptrace.c:688 |
27 | sys_alarm | 0x1b | unsigned int seconds | - | - | - | - | kernel/timer.c:1314 |
28 | sys_fstat | 0x1c | unsigned int fd | struct old_kernel_stat user *statbuf | - | - | - | fs/stat.c:174 |
29 | sys_pause | 0x1d | - | - | - | - | - | kernel/signal.c:2700 |
30 | sys_utime | 0x1e | char __user *filename | struct utimbuf __user *times | - | - | - | fs/utimes.c:27 |
31 | not implemented | 0x1f | - | - | - | - | - | |
32 | not implemented | 0x20 | - | - | - | - | - | |
33 | sys_access | 0x21 | const char __user *filename | int mode | - | - | - | fs/open.c:356 |
34 | sys_nice | 0x22 | int increment | - | - | - | - | kernel/sched.c:4282 |
35 | not implemented | 0x23 | - | - | - | - | - | |
36 | sys_sync | 0x24 | - | - | - | - | - | fs/sync.c:98 |
37 | sys_kill | 0x25 | int pid | int sig | - | - | - | kernel/signal.c:2317 |
38 | sys_rename | 0x26 | const char __user *oldname | const char __user *newname | - | - | - | fs/namei.c:2765 |
39 | sys_mkdir | 0x27 | const char __user *pathname | int mode | - | - | - | fs/namei.c:2130 |
40 | sys_rmdir | 0x28 | const char __user *pathname | - | - | - | - | fs/namei.c:2244 |
41 | sys_dup | 0x29 | unsigned int fildes | - | - | - | - | fs/fcntl.c:131 |
42 | sys_pipe | 0x2a | int __user *fildes | - | - | - | - | fs/pipe.c:1117 |
43 | sys_times | 0x2b | struct tms __user *tbuf | - | - | - | - | kernel/sys.c:896 |
44 | not implemented | 0x2c | - | - | - | - | - | |
45 | sys_brk | 0x2d | unsigned long brk | - | - | - | - | mm/mmap.c:245 |
46 | sys_setgid16 | 0x2e | old_gid_t gid | - | - | - | - | kernel/uid16.c:51 |
47 | sys_getgid16 | 0x2f | - | - | - | - | - | kernel/uid16.c:222 |
48 | sys_signal | 0x30 | int sig | __sighandler_t handler | - | - | - | kernel/signal.c:2683 |
49 | sys_geteuid16 | 0x31 | - | - | - | - | - | kernel/uid16.c:217 |
50 | sys_getegid16 | 0x32 | - | - | - | - | - | kernel/uid16.c:227 |
51 | sys_acct | 0x33 | const char __user *name | - | - | - | - | kernel/acct.c:274 |
52 | sys_umount | 0x34 | char __user *name | int flags | - | - | - | fs/namespace.c:1132 |
53 | not implemented | 0x35 | - | - | - | - | - | |
54 | sys_ioctl | 0x36 | unsigned int fd | unsigned int cmd | unsigned long arg | - | - | fs/ioctl.c:613 |
55 | sys_fcntl | 0x37 | unsigned int fd | unsigned int cmd | unsigned long arg | - | - | fs/fcntl.c:429 |
56 | not implemented | 0x38 | - | - | - | - | - | |
57 | sys_setpgid | 0x39 | pid_t pid | pid_t pgid | - | - | - | kernel/sys.c:921 |
58 | not implemented | 0x3a | - | - | - | - | - | |
59 | sys_olduname | 0x3b | struct oldold_utsname __user * | - | - | - | - | kernel/sys.c:1132 |
60 | sys_umask | 0x3c | int mask | - | - | - | - | kernel/sys.c:1460 |
61 | sys_chroot | 0x3d | const char __user *filename | - | - | - | - | fs/open.c:408 |
62 | sys_ustat | 0x3e | unsigned dev | struct ustat __user *ubuf | - | - | - | fs/statfs.c:175 |
63 | sys_dup2 | 0x3f | unsigned int oldfd | unsigned int newfd | - | - | - | fs/fcntl.c:116 |
64 | sys_getppid | 0x40 | - | - | - | - | - | kernel/timer.c:1348 |
65 | sys_getpgrp | 0x41 | - | - | - | - | - | kernel/sys.c:1020 |
66 | sys_setsid | 0x42 | - | - | - | - | - | kernel/sys.c:1055 |
67 | sys_sigaction | 0x43 | int sig | const struct old_sigaction __user *act | struct old_sigaction __user *oact | - | - | arch/mips/kernel/signal.c:300 |
68 | sys_sgetmask | 0x44 | - | - | - | - | - | kernel/signal.c:2657 |
69 | sys_ssetmask | 0x45 | int newmask | - | - | - | - | kernel/signal.c:2663 |
70 | sys_setreuid16 | 0x46 | old_uid_t ruid | old_uid_t euid | - | - | - | kernel/uid16.c:59 |
71 | sys_setregid16 | 0x47 | old_gid_t rgid | old_gid_t egid | - | - | - | kernel/uid16.c:43 |
72 | sys_sigsuspend | 0x48 | int history0 | int history1 | old_sigset_t mask | - | - | arch/s390/kernel/signal.c:58 |
73 | sys_sigpending | 0x49 | old_sigset_t __user *set | - | - | - | - | kernel/signal.c:2562 |
74 | sys_sethostname | 0x4a | char __user *name | int len | - | - | - | kernel/sys.c:1165 |
75 | sys_setrlimit | 0x4b | unsigned int resource | struct rlimit __user *rlim | - | - | - | kernel/sys.c:1275 |
76 | sys_old_getrlimit | 0x4c | unsigned int resource | struct rlimit __user *rlim | - | - | - | kernel/sys.c:1256 |
77 | sys_getrusage | 0x4d | int who | struct rusage __user *ru | - | - | - | kernel/sys.c:1452 |
78 | sys_gettimeofday | 0x4e | struct timeval __user *tv | struct timezone __user *tz | - | - | - | kernel/time.c:101 |
79 | sys_settimeofday | 0x4f | struct timeval __user *tv | struct timezone __user *tz | - | - | - | kernel/time.c:185 |
80 | sys_getgroups16 | 0x50 | int gidsetsize | old_gid_t __user *grouplist | - | - | - | kernel/uid16.c:164 |
81 | sys_setgroups16 | 0x51 | int gidsetsize | old_gid_t __user *grouplist | - | - | - | kernel/uid16.c:187 |
82 | sys_old_select | 0x52 | struct sel_arg_struct __user *arg | - | - | - | - | fs/select.c:701 |
83 | sys_symlink | 0x53 | const char __user *old | const char __user *new | - | - | - | fs/namei.c:2419 |
84 | sys_lstat | 0x54 | char __user *filename | struct old_kernel_stat user *statbuf | - | - | - | fs/stat.c:162 |
85 | sys_readlink | 0x55 | const char __user *path | char __user *buf | int bufsiz | - | - | fs/stat.c:311 |
86 | sys_uselib | 0x56 | const char __user *library | - | - | - | - | fs/exec.c:107 |
87 | sys_swapon | 0x57 | const char __user *specialfile | int swap_flags | - | - | - | mm/swapfile.c:1793 |
88 | sys_reboot | 0x58 | int magic1 | int magic2 | unsigned int cmd | void __user *arg | - | kernel/sys.c:368 |
89 | sys_old_readdir | 0x59 | unsigned int | struct old_linux_dirent __user * | unsigned int | - | - | fs/readdir.c:105 |
90 | sys_old_mmap | 0x5a | struct mmap_arg_struct __user *arg | - | - | - | - | mm/mmap.c:1141 |
91 | sys_munmap | 0x5b | unsigned long addr | size_t len | - | - | - | mm/mmap.c:2109 |
92 | sys_truncate | 0x5c | const char __user *path | long length | - | - | - | fs/open.c:127 |
93 | sys_ftruncate | 0x5d | unsigned int fd | unsigned long length | - | - | - | fs/open.c:178 |
94 | sys_fchmod | 0x5e | unsigned int fd | mode_t mode | - | - | - | fs/open.c:436 |
95 | sys_fchown16 | 0x5f | unsigned int fd | old_uid_t user | old_gid_t group | - | - | kernel/uid16.c:35 |
96 | sys_getpriority | 0x60 | int which | int who | - | - | - | kernel/sys.c:216 |
97 | sys_setpriority | 0x61 | int which | int who | int niceval | - | - | kernel/sys.c:149 |
98 | not implemented | 0x62 | - | - | - | - | - | |
99 | sys_statfs | 0x63 | const char __user * path | struct statfs __user *buf | - | - | - | fs/statfs.c:102 |
100 | sys_fstatfs | 0x64 | unsigned int fd | struct statfs __user *buf | - | - | - | fs/statfs.c:136 |
101 | sys_ioperm | 0x65 | unsigned long | unsigned long | int | - | - | not found: |
102 | sys_socketcall | 0x66 | int call | unsigned long __user *args | - | - | - | net/socket.c:2210 |
103 | sys_syslog | 0x67 | int type | char __user *buf | int len | - | - | kernel/printk.c:412 |
104 | sys_setitimer | 0x68 | int which | struct itimerval __user *value | struct itimerval __user *ovalue | - | - | kernel/itimer.c:279 |
105 | sys_getitimer | 0x69 | int which | struct itimerval __user *value | - | - | - | kernel/itimer.c:103 |
106 | sys_newstat | 0x6a | char __user *filename | struct stat __user *statbuf | - | - | - | fs/stat.c:237 |
107 | sys_newlstat | 0x6b | char __user *filename | struct stat __user *statbuf | - | - | - | fs/stat.c:247 |
108 | sys_newfstat | 0x6c | unsigned int fd | struct stat __user *statbuf | - | - | - | fs/stat.c:273 |
109 | sys_uname | 0x6d | struct old_utsname __user * | - | - | - | - | kernel/sys.c:1115 |
110 | sys_iopl | 0x6e | unsigned int | struct pt_regs * | - | - | - | not found: |
111 | sys_vhangup | 0x6f | - | - | - | - | - | fs/open.c:1008 |
112 | not implemented | 0x70 | - | - | - | - | - | |
113 | sys_vm86old | 0x71 | struct vm86_struct __user * | struct pt_regs * | - | - | - | not found: |
114 | sys_wait4 | 0x72 | pid_t pid | int __user *stat_addr | int options | struct rusage __user *ru | - | kernel/exit.c:1726 |
115 | sys_swapoff | 0x73 | const char __user *specialfile | - | - | - | - | mm/swapfile.c:1533 |
116 | sys_sysinfo | 0x74 | struct sysinfo __user *info | - | - | - | - | kernel/timer.c:1565 |
117 | sys_ipc | 0x75 | - | - | - | - | - | ipc/syscall.c:16 |
118 | sys_fsync | 0x76 | unsigned int fd | - | - | - | - | fs/sync.c:221 |
119 | sys_sigreturn | 0x77 | struct pt_regs *regs | - | - | - | - | arch/alpha/kernel/entry.S:758 |
120 | sys_clone | 0x78 | unsigned long | unsigned long | unsigned long | unsigned long | struct pt_regs * | arch/alpha/kernel/entry.S:733 |
121 | sys_setdomainname | 0x79 | char __user *name | int len | - | - | - | kernel/sys.c:1214 |
122 | sys_newuname | 0x7a | struct new_utsname __user *name | - | - | - | - | kernel/sys.c:1097 |
123 | sys_modify_ldt | 0x7b | int | void __user * | unsigned long | - | - | not found: |
124 | sys_adjtimex | 0x7c | struct timex __user *txc_p | - | - | - | - | kernel/time.c:206 |
125 | sys_mprotect | 0x7d | unsigned long start | size_t len | unsigned long prot | - | - | mm/mprotect.c:221 |
126 | sys_sigprocmask | 0x7e | int how | old_sigset_t __user *set | old_sigset_t __user *oset | - | - | kernel/signal.c:2573 |
127 | not implemented | 0x7f | - | - | - | - | - | |
128 | sys_init_module | 0x80 | void __user *umod | unsigned long len | const char __user *uargs | - | - | kernel/module.c:2611 |
129 | sys_delete_module | 0x81 | const char __user *name_user | unsigned int flags | - | - | - | kernel/module.c:720 |
130 | not implemented | 0x82 | - | - | - | - | - | |
131 | sys_quotactl | 0x83 | unsigned int cmd | const char __user *special | qid_t id | void __user *addr | - | fs/quota/quota.c:333 |
132 | sys_getpgid | 0x84 | pid_t pid | - | - | - | - | kernel/sys.c:990 |
133 | sys_fchdir | 0x85 | unsigned int fd | - | - | - | - | fs/open.c:382 |
134 | sys_bdflush | 0x86 | int func | long data | - | - | - | fs/buffer.c:3278 |
135 | sys_sysfs | 0x87 | int option | unsigned long arg1 | unsigned long arg2 | - | - | fs/filesystems.c:182 |
136 | sys_personality | 0x88 | unsigned int personality | - | - | - | - | kernel/exec_domain.c:191 |
137 | not implemented | 0x89 | - | - | - | - | - | |
138 | sys_setfsuid16 | 0x8a | old_uid_t uid | - | - | - | - | kernel/uid16.c:118 |
139 | sys_setfsgid16 | 0x8b | old_gid_t gid | - | - | - | - | kernel/uid16.c:126 |
140 | sys_llseek | 0x8c | unsigned int fd | unsigned long offset_high | unsigned long offset_low | loff_t __user *result | unsigned int origin | fs/read_write.c:191 |
141 | sys_getdents | 0x8d | unsigned int fd | struct linux_dirent __user *dirent | unsigned int count | - | - | fs/readdir.c:191 |
142 | sys_select | 0x8e | int n | fd_set __user *inp | fd_set __user *outp | fd_set __user *exp | struct timeval __user *tvp | fs/select.c:596 |
143 | sys_flock | 0x8f | unsigned int fd | unsigned int cmd | - | - | - | fs/locks.c:1569 |
144 | sys_msync | 0x90 | unsigned long start | size_t len | int flags | - | - | mm/msync.c:31 |
145 | sys_readv | 0x91 | unsigned long fd | const struct iovec __user *vec | unsigned long vlen | - | - | fs/read_write.c:711 |
146 | sys_writev | 0x92 | unsigned long fd | const struct iovec __user *vec | unsigned long vlen | - | - | fs/read_write.c:732 |
147 | sys_getsid | 0x93 | pid_t pid | - | - | - | - | kernel/sys.c:1027 |
148 | sys_fdatasync | 0x94 | unsigned int fd | - | - | - | - | fs/sync.c:226 |
149 | sys_sysctl | 0x95 | struct sysctl_args user *args | - | - | - | - | kernel/sysctl_binary.c:1462 |
150 | sys_mlock | 0x96 | unsigned long start | size_t len | - | - | - | mm/mlock.c:491 |
151 | sys_munlock | 0x97 | unsigned long start | size_t len | - | - | - | mm/mlock.c:519 |
152 | sys_mlockall | 0x98 | int flags | - | - | - | - | mm/mlock.c:556 |
153 | sys_munlockall | 0x99 | - | - | - | - | - | mm/mlock.c:584 |
154 | sys_sched_setparam | 0x9a | pid_t pid | struct sched_param __user *param | - | - | - | kernel/sched.c:4616 |
155 | sys_sched_getparam | 0x9b | pid_t pid | struct sched_param __user *param | - | - | - | kernel/sched.c:4651 |
156 | sys_sched_setscheduler | 0x9c | pid_t pid | int policy | struct sched_param __user *param | - | - | kernel/sched.c:4601 |
157 | sys_sched_getscheduler | 0x9d | pid_t pid | - | - | - | - | kernel/sched.c:4625 |
158 | sys_sched_yield | 0x9e | - | - | - | - | - | kernel/sched.c:4851 |
159 | sys_sched_get_priority_max | 0x9f | int policy | - | - | - | - | kernel/sched.c:4989 |
160 | sys_sched_get_priority_min | 0xa0 | int policy | - | - | - | - | kernel/sched.c:5014 |
161 | sys_sched_rr_get_interval | 0xa1 | pid_t pid | struct timespec __user *interval | - | - | - | kernel/sched.c:5039 |
162 | sys_nanosleep | 0xa2 | struct timespec __user *rqtp | struct timespec __user *rmtp | - | - | - | kernel/hrtimer.c:1606 |
163 | sys_mremap | 0xa3 | unsigned long addr | unsigned long old_len | unsigned long new_len | unsigned long flags | unsigned long new_addr | mm/mremap.c:510 |
164 | sys_setresuid16 | 0xa4 | old_uid_t ruid | old_uid_t euid | old_uid_t suid | - | - | kernel/uid16.c:75 |
165 | sys_getresuid16 | 0xa5 | old_uid_t __user *ruid | old_uid_t __user *euid | old_uid_t __user *suid | - | - | kernel/uid16.c:84 |
166 | sys_vm86 | 0xa6 | unsigned long | unsigned long | struct pt_regs * | - | - | not found: |
167 | not implemented | 0xa7 | - | - | - | - | - | |
168 | sys_poll | 0xa8 | struct pollfd __user *ufds | unsigned int nfds | long timeout | - | - | fs/select.c:915 |
169 | sys_nfsservctl | 0xa9 | int cmd | struct nfsctl_arg __user *arg | void __user *res | - | - | fs/nfsctl.c:86 |
170 | sys_setresgid16 | 0xaa | old_gid_t rgid | old_gid_t egid | old_gid_t sgid | - | - | kernel/uid16.c:96 |
171 | sys_getresgid16 | 0xab | old_gid_t __user *rgid | old_gid_t __user *egid | old_gid_t __user *sgid | - | - | kernel/uid16.c:106 |
172 | sys_prctl | 0xac | int option | unsigned long arg2 | unsigned long arg3 | unsigned long arg4 | unsigned long arg5 | kernel/sys.c:1466 |
173 | sys_rt_sigreturn | 0xad | struct pt_regs * | - | - | - | - | arch/alpha/kernel/entry.S:771 |
174 | sys_rt_sigaction | 0xae | int sig | const struct sigaction __user *act | struct sigaction __user *oact | size_t sigsetsize | - | kernel/signal.c:2624 |
175 | sys_rt_sigprocmask | 0xaf | int how | sigset_t __user *set | sigset_t __user *oset | size_t sigsetsize | - | kernel/signal.c:2111 |
176 | sys_rt_sigpending | 0xb0 | sigset_t __user *set | size_t sigsetsize | - | - | - | kernel/signal.c:2171 |
177 | sys_rt_sigtimedwait | 0xb1 | const sigset_t __user *uthese | siginfo_t __user *uinfo | const struct timespec __user *uts | size_t sigsetsize | - | kernel/signal.c:2242 |
178 | sys_rt_sigqueueinfo | 0xb2 | int pid | int sig | siginfo_t __user *uinfo | - | - | kernel/signal.c:2404 |
179 | sys_rt_sigsuspend | 0xb3 | sigset_t __user *unewset | size_t sigsetsize | - | - | - | kernel/signal.c:2710 |
180 | sys_pread64 | 0xb4 | unsigned int fd | char __user *buf | size_t count | loff_t pos | - | not found: |
181 | sys_pwrite64 | 0xb5 | unsigned int fd | const char __user *buf | size_t count | loff_t pos | - | not found: |
182 | sys_chown16 | 0xb6 | const char __user *filename | old_uid_t user | old_gid_t group | - | - | kernel/uid16.c:19 |
183 | sys_getcwd | 0xb7 | char __user *buf | unsigned long size | - | - | - | fs/dcache.c:2104 |
184 | sys_capget | 0xb8 | cap_user_header_t header | cap_user_data_t dataptr | - | - | - | kernel/capability.c:161 |
185 | sys_capset | 0xb9 | cap_user_header_t header | const cap_user_data_t data | - | - | - | kernel/capability.c:235 |
186 | sys_sigaltstack | 0xba | const stack_t __user * | stack_t __user * | struct pt_regs * | - | - | arch/alpha/kernel/signal.c:199 |
187 | sys_sendfile | 0xbb | int out_fd | int in_fd | off_t __user *offset | size_t count | - | fs/read_write.c:897 |
188 | not implemented | 0xbc | - | - | - | - | - | |
189 | not implemented | 0xbd | - | - | - | - | - | |
190 | sys_vfork | 0xbe | struct pt_regs * | - | - | - | - | arch/alpha/kernel/entry.S:746 |
191 | sys_getrlimit | 0xbf | unsigned int resource | struct rlimit __user *rlim | - | - | - | kernel/sys.c:1237 |
192 | sys_mmap_pgoff | 0xc0 | - | - | - | - | - | mm/mmap.c:1091 |
193 | sys_truncate64 | 0xc1 | const char __user *path | loff_t length | - | - | - | not found: |
194 | sys_ftruncate64 | 0xc2 | unsigned int fd | loff_t length | - | - | - | not found: |
195 | sys_stat64 | 0xc3 | char __user *filename | struct stat64 __user *statbuf | - | - | - | fs/stat.c:358 |
196 | sys_lstat64 | 0xc4 | char __user *filename | struct stat64 __user *statbuf | - | - | - | fs/stat.c:369 |
197 | sys_fstat64 | 0xc5 | unsigned long fd | struct stat64 __user *statbuf | - | - | - | fs/stat.c:380 |
198 | sys_lchown | 0xc6 | const char __user *filename | uid_t user | gid_t group | - | - | fs/open.c:583 |
199 | sys_getuid | 0xc7 | - | - | - | - | - | kernel/timer.c:1359 |
200 | sys_getgid | 0xc8 | - | - | - | - | - | kernel/timer.c:1371 |
201 | sys_geteuid | 0xc9 | - | - | - | - | - | kernel/timer.c:1365 |
202 | sys_getegid | 0xca | - | - | - | - | - | kernel/timer.c:1377 |
203 | sys_setreuid | 0xcb | uid_t ruid | uid_t euid | - | - | - | kernel/sys.c:594 |
204 | sys_setregid | 0xcc | gid_t rgid | gid_t egid | - | - | - | kernel/sys.c:484 |
205 | sys_getgroups | 0xcd | int gidsetsize | gid_t __user *grouplist | - | - | - | kernel/groups.c:203 |
206 | sys_setgroups | 0xce | int gidsetsize | gid_t __user *grouplist | - | - | - | kernel/groups.c:232 |
207 | sys_fchown | 0xcf | unsigned int fd | uid_t user | gid_t group | - | - | fs/open.c:602 |
208 | sys_setresuid | 0xd0 | uid_t ruid | uid_t euid | uid_t suid | - | - | kernel/sys.c:696 |
209 | sys_getresuid | 0xd1 | uid_t __user *ruid | uid_t __user *euid | uid_t __user *suid | - | - | kernel/sys.c:746 |
210 | sys_setresgid | 0xd2 | gid_t rgid | gid_t egid | gid_t sgid | - | - | kernel/sys.c:761 |
211 | sys_getresgid | 0xd3 | gid_t __user *rgid | gid_t __user *egid | gid_t __user *sgid | - | - | kernel/sys.c:800 |
212 | sys_chown | 0xd4 | const char __user *filename | uid_t user | gid_t group | - | - | fs/open.c:539 |
213 | sys_setuid | 0xd5 | uid_t uid | - | - | - | - | kernel/sys.c:655 |
214 | sys_setgid | 0xd6 | gid_t gid | - | - | - | - | kernel/sys.c:531 |
215 | sys_setfsuid | 0xd7 | uid_t uid | - | - | - | - | kernel/sys.c:819 |
216 | sys_setfsgid | 0xd8 | gid_t gid | - | - | - | - | kernel/sys.c:852 |
217 | sys_pivot_root | 0xd9 | const char __user *new_root | const char __user *put_old | - | - | - | fs/namespace.c:2184 |
218 | sys_mincore | 0xda | unsigned long start | size_t len | unsigned char __user * vec | - | - | mm/mincore.c:256 |
219 | sys_madvise | 0xdb | unsigned long start | size_t len | int behavior | - | - | mm/madvise.c:335 |
220 | sys_getdents64 | 0xdc | unsigned int fd | struct linux_dirent64 __user *dirent | unsigned int count | - | - | fs/readdir.c:273 |
221 | sys_fcntl64 | 0xdd | unsigned int fd | unsigned int cmd | unsigned long arg | - | - | fs/fcntl.c:452 |
222 | not implemented | 0xde | - | - | - | - | - | |
223 | not implemented | 0xdf | - | - | - | - | - | |
224 | sys_gettid | 0xe0 | - | - | - | - | - | kernel/timer.c:1493 |
225 | sys_readahead | 0xe1 | int fd | loff_t offset | size_t count | - | - | not found: |
226 | sys_setxattr | 0xe2 | const char __user *path | const char __user *name | const void __user *value | size_t size | int flags | fs/xattr.c:279 |
227 | sys_lsetxattr | 0xe3 | const char __user *path | const char __user *name | const void __user *value | size_t size | int flags | fs/xattr.c:298 |
228 | sys_fsetxattr | 0xe4 | int fd | const char __user *name | const void __user *value | size_t size | int flags | fs/xattr.c:317 |
229 | sys_getxattr | 0xe5 | const char __user *path | const char __user *name | void __user *value | size_t size | - | fs/xattr.c:376 |
230 | sys_lgetxattr | 0xe6 | const char __user *path | const char __user *name | void __user *value | size_t size | - | fs/xattr.c:390 |
231 | sys_fgetxattr | 0xe7 | int fd | const char __user *name | void __user *value | size_t size | - | fs/xattr.c:404 |
232 | sys_listxattr | 0xe8 | const char __user *path | char __user *list | size_t size | - | - | fs/xattr.c:449 |
233 | sys_llistxattr | 0xe9 | const char __user *path | char __user *list | size_t size | - | - | fs/xattr.c:463 |
234 | sys_flistxattr | 0xea | int fd | char __user *list | size_t size | - | - | fs/xattr.c:477 |
235 | sys_removexattr | 0xeb | const char __user *path | const char __user *name | - | - | - | fs/xattr.c:509 |
236 | sys_lremovexattr | 0xec | const char __user *path | const char __user *name | - | - | - | fs/xattr.c:527 |
237 | sys_fremovexattr | 0xed | int fd | const char __user *name | - | - | - | fs/xattr.c:545 |
238 | sys_tkill | 0xee | int pid | int sig | - | - | - | kernel/signal.c:2395 |
239 | sys_sendfile64 | 0xef | int out_fd | int in_fd | loff_t __user *offset | size_t count | - | fs/read_write.c:916 |
240 | sys_futex | 0xf0 | - | - | - | - | - | kernel/futex.c:2605 |
241 | sys_sched_setaffinity | 0xf1 | pid_t pid | unsigned int len | unsigned long __user *user_mask_ptr | - | - | kernel/sched.c:4765 |
242 | sys_sched_getaffinity | 0xf2 | pid_t pid | unsigned int len | unsigned long __user *user_mask_ptr | - | - | kernel/sched.c:4817 |
243 | sys_set_thread_area | 0xf3 | struct user_desc __user * | - | - | - | - | arch/mips/kernel/syscall.c:222 |
244 | sys_get_thread_area | 0xf4 | struct user_desc __user * | - | - | - | - | not found: |
245 | sys_io_setup | 0xf5 | unsigned nr_reqs | aio_context_t __user *ctx | - | - | - | fs/aio.c:1245 |
246 | sys_io_destroy | 0xf6 | aio_context_t ctx | - | - | - | - | fs/aio.c:1283 |
247 | sys_io_getevents | 0xf7 | aio_context_t ctx_id | long min_nr | long nr | struct io_event __user *events | struct timespec __user *timeout | fs/aio.c:1808 |
248 | sys_io_submit | 0xf8 | aio_context_t | long | struct iocb user * user * | - | - | fs/aio.c:1711 |
249 | sys_io_cancel | 0xf9 | aio_context_t ctx_id | struct iocb __user *iocb | struct io_event __user *result | - | - | fs/aio.c:1746 |
250 | sys_fadvise64 | 0xfa | int fd | loff_t offset | size_t len | int advice | - | not found: |
251 | not implemented | 0xfb | - | - | - | - | - | |
252 | sys_exit_group | 0xfc | int error_code | - | - | - | - | kernel/exit.c:1087 |
253 | sys_lookup_dcookie | 0xfd | u64 cookie64 | char __user *buf | size_t len | - | - | not found: |
254 | sys_epoll_create | 0xfe | int size | - | - | - | - | fs/eventpoll.c:1215 |
255 | sys_epoll_ctl | 0xff | int epfd | int op | int fd | struct epoll_event __user *event | - | fs/eventpoll.c:1228 |
256 | sys_epoll_wait | 0x100 | int epfd | struct epoll_event __user *events | int maxevents | int timeout | - | fs/eventpoll.c:1320 |
257 | sys_remap_file_pages | 0x101 | unsigned long start | unsigned long size | unsigned long prot | unsigned long pgoff | unsigned long flags | mm/fremap.c:123 |
258 | sys_set_tid_address | 0x102 | int __user *tidptr | - | - | - | - | kernel/fork.c:920 |
259 | sys_timer_create | 0x103 | clockid_t which_clock | struct sigevent __user *timer_event_spec | timer_t __user * created_timer_id | - | - | kernel/posix-timers.c:522 |
260 | sys_timer_settime | 0x104 | timer_t timer_id | int flags | const struct itimerspec __user *new_setting | struct itimerspec __user *old_setting | - | kernel/posix-timers.c:800 |
261 | sys_timer_gettime | 0x105 | timer_t timer_id | struct itimerspec __user *setting | - | - | - | kernel/posix-timers.c:702 |
262 | sys_timer_getoverrun | 0x106 | timer_t timer_id | - | - | - | - | kernel/posix-timers.c:732 |
263 | sys_timer_delete | 0x107 | timer_t timer_id | - | - | - | - | kernel/posix-timers.c:855 |
264 | sys_clock_settime | 0x108 | clockid_t which_clock | const struct timespec __user *tp | - | - | - | kernel/posix-timers.c:941 |
265 | sys_clock_gettime | 0x109 | clockid_t which_clock | struct timespec __user *tp | - | - | - | kernel/posix-timers.c:954 |
266 | sys_clock_getres | 0x10a | clockid_t which_clock | struct timespec __user *tp | - | - | - | kernel/posix-timers.c:971 |
267 | sys_clock_nanosleep | 0x10b | clockid_t which_clock | int flags | const struct timespec __user *rqtp | struct timespec __user *rmtp | - | kernel/posix-timers.c:1001 |
268 | sys_statfs64 | 0x10c | const char __user *path | size_t sz | struct statfs64 __user *buf | - | - | fs/statfs.c:118 |
269 | sys_fstatfs64 | 0x10d | unsigned int fd | size_t sz | struct statfs64 __user *buf | - | - | fs/statfs.c:154 |
270 | sys_tgkill | 0x10e | int tgid | int pid | int sig | - | - | kernel/signal.c:2383 |
271 | sys_utimes | 0x10f | char __user *filename | struct timeval __user *utimes | - | - | - | fs/utimes.c:219 |
272 | sys_fadvise64_64 | 0x110 | int fd | loff_t offset | loff_t len | int advice | - | not found: |
273 | not implemented | 0x111 | - | - | - | - | - | |
274 | sys_mbind | 0x112 | - | - | - | - | - | mm/mempolicy.c:1232 |
275 | sys_get_mempolicy | 0x113 | int __user *policy | unsigned long __user *nmask | unsigned long maxnode | unsigned long addr | unsigned long flags | mm/mempolicy.c:1348 |
276 | sys_set_mempolicy | 0x114 | int mode | unsigned long __user *nmask | unsigned long maxnode | - | - | mm/mempolicy.c:1254 |
277 | sys_mq_open | 0x115 | const char __user *name | int oflag | mode_t mode | struct mq_attr __user *attr | - | ipc/mqueue.c:673 |
278 | sys_mq_unlink | 0x116 | const char __user *name | - | - | - | - | ipc/mqueue.c:746 |
279 | sys_mq_timedsend | 0x117 | mqd_t mqdes | const char __user *msg_ptr | size_t msg_len | unsigned int msg_prio | const struct timespec __user *abs_timeout | ipc/mqueue.c:840 |
280 | sys_mq_timedreceive | 0x118 | mqd_t mqdes | char __user *msg_ptr | size_t msg_len | unsigned int __user *msg_prio | const struct timespec __user *abs_timeout | ipc/mqueue.c:934 |
281 | sys_mq_notify | 0x119 | mqd_t mqdes | const struct sigevent __user *notification | - | - | - | ipc/mqueue.c:1023 |
282 | sys_mq_getsetattr | 0x11a | mqd_t mqdes | const struct mq_attr __user *mqstat | struct mq_attr __user *omqstat | - | - | ipc/mqueue.c:1154 |
283 | sys_kexec_load | 0x11b | unsigned long entry | unsigned long nr_segments | struct kexec_segment __user *segments | unsigned long flags | - | kernel/kexec.c:939 |
284 | sys_waitid | 0x11c | int which | pid_t pid | struct siginfo __user *infop | int options | struct rusage __user *ru | kernel/exit.c:1655 |
285 | not implemented | 0x11d | - | - | - | - | - | |
286 | sys_add_key | 0x11e | const char __user *_type | const char __user *_description | const void __user *_payload | size_t plen | key_serial_t destringid | security/keys/keyctl.c:57 |
287 | sys_request_key | 0x11f | const char __user *_type | const char __user *_description | const char __user *_callout_info | key_serial_t destringid | - | security/keys/keyctl.c:149 |
288 | sys_keyctl | 0x120 | int cmd | unsigned long arg2 | unsigned long arg3 | unsigned long arg4 | unsigned long arg5 | security/keys/keyctl.c:1338 |
289 | sys_ioprio_set | 0x121 | int which | int who | int ioprio | - | - | fs/ioprio.c:76 |
290 | sys_ioprio_get | 0x122 | int which | int who | - | - | - | fs/ioprio.c:192 |
291 | sys_inotify_init | 0x123 | - | - | - | - | - | fs/notify/inotify/inotify_user.c:680 |
292 | sys_inotify_add_watch | 0x124 | int fd | const char __user *path | u32 mask | - | - | fs/notify/inotify/inotify_user.c:685 |
293 | sys_inotify_rm_watch | 0x125 | int fd | __s32 wd | - | - | - | fs/notify/inotify/inotify_user.c:726 |
294 | sys_migrate_pages | 0x126 | pid_t pid | unsigned long maxnode | const unsigned long __user *from | const unsigned long __user *to | - | mm/mempolicy.c:1273 |
295 | sys_openat | 0x127 | int dfd | const char __user *filename | int flags | int mode | - | fs/open.c:913 |
296 | sys_mkdirat | 0x128 | int dfd | const char __user * pathname | int mode | - | - | fs/namei.c:2093 |
297 | sys_mknodat | 0x129 | int dfd | const char __user * filename | int mode | unsigned dev | - | fs/namei.c:2012 |
298 | sys_fchownat | 0x12a | int dfd | const char __user *filename | uid_t user | gid_t group | int flag | fs/open.c:558 |
299 | sys_futimesat | 0x12b | int dfd | char __user *filename | struct timeval __user *utimes | - | - | fs/utimes.c:191 |
300 | sys_fstatat64 | 0x12c | int dfd | char __user *filename | struct stat64 __user *statbuf | int flag | - | fs/stat.c:391 |
301 | sys_unlinkat | 0x12d | int dfd | const char __user * pathname | int flag | - | - | fs/namei.c:2341 |
302 | sys_renameat | 0x12e | int olddfd | const char __user * oldname | int newdfd | const char __user * newname | - | fs/namei.c:2671 |
303 | sys_linkat | 0x12f | int olddfd | const char __user *oldname | int newdfd | const char __user *newname | int flags | fs/namei.c:2470 |
304 | sys_symlinkat | 0x130 | const char __user * oldname | int newdfd | const char __user * newname | - | - | fs/namei.c:2377 |
305 | sys_readlinkat | 0x131 | int dfd | const char __user *path | char __user *buf | int bufsiz | - | fs/stat.c:284 |
306 | sys_fchmodat | 0x132 | int dfd | const char __user * filename | mode_t mode | - | - | fs/open.c:474 |
307 | sys_faccessat | 0x133 | int dfd | const char __user *filename | int mode | - | - | fs/open.c:286 |
308 | sys_pselect6 | 0x134 | - | - | - | - | - | fs/select.c:675 |
309 | sys_ppoll | 0x135 | struct pollfd __user *ufds | unsigned int nfds | struct timespec __user *tsp | const sigset_t __user *sigmask | size_t sigsetsize | fs/select.c:950 |
310 | sys_unshare | 0x136 | unsigned long unshare_flags | - | - | - | - | kernel/fork.c:1624 |
311 | sys_set_robust_list | 0x137 | struct robust_list_head __user *head | size_t len | - | - | - | kernel/futex.c:2351 |
312 | sys_get_robust_list | 0x138 | int pid | struct robust_list_head user * user *head_ptr | size_t __user *len_ptr | - | - | kernel/futex.c:2373 |
313 | sys_splice | 0x139 | - | - | - | - | - | fs/splice.c:1718 |
314 | sys_sync_file_range | 0x13a | int fd | loff_t offset | loff_t nbytes | unsigned int flags | - | not found: |
315 | sys_tee | 0x13b | int fdin | int fdout | size_t len | unsigned int flags | - | fs/splice.c:2061 |
316 | sys_vmsplice | 0x13c | int fd | const struct iovec __user *iov | unsigned long nr_segs | unsigned int flags | - | fs/splice.c:1692 |
317 | sys_move_pages | 0x13d | - | - | - | - | - | mm/migrate.c:1075 |
318 | sys_getcpu | 0x13e | unsigned __user *cpu | unsigned __user *node | struct getcpu_cache __user *cache | - | - | kernel/sys.c:1621 |
319 | sys_epoll_pwait | 0x13f | - | - | - | - | - | fs/eventpoll.c:1373 |
320 | sys_utimensat | 0x140 | int dfd | char __user *filename | struct timespec __user *utimes | int flags | - | fs/utimes.c:173 |
321 | sys_signalfd | 0x141 | int ufd | sigset_t __user *user_mask | size_t sizemask | - | - | fs/signalfd.c:265 |
322 | sys_timerfd_create | 0x142 | int clockid | int flags | - | - | - | fs/timerfd.c:164 |
323 | sys_eventfd | 0x143 | unsigned int count | - | - | - | - | fs/eventfd.c:434 |
324 | sys_fallocate | 0x144 | int fd | int mode | loff_t offset | loff_t len | - | not found: |
325 | sys_timerfd_settime | 0x145 | int ufd | int flags | const struct itimerspec __user *utmr | struct itimerspec __user *otmr | - | fs/timerfd.c:194 |
326 | sys_timerfd_gettime | 0x146 | int ufd | struct itimerspec __user *otmr | - | - | - | fs/timerfd.c:252 |
327 | sys_signalfd4 | 0x147 | int ufd | sigset_t __user *user_mask | size_t sizemask | int flags | - | fs/signalfd.c:211 |
328 | sys_eventfd2 | 0x148 | unsigned int count | int flags | - | - | - | fs/eventfd.c:409 |
329 | sys_epoll_create1 | 0x149 | int flags | - | - | - | - | fs/eventpoll.c:1187 |
330 | sys_dup3 | 0x14a | unsigned int oldfd | unsigned int newfd | int flags | - | - | fs/fcntl.c:53 |
331 | sys_pipe2 | 0x14b | int __user *fildes | int flags | - | - | - | fs/pipe.c:1101 |
332 | sys_inotify_init1 | 0x14c | int flags | - | - | - | - | fs/notify/inotify/inotify_user.c:640 |
333 | sys_preadv | 0x14d | unsigned long fd | const struct iovec __user *vec | unsigned long vlen | unsigned long pos_l | unsigned long pos_h | fs/read_write.c:759 |
334 | sys_pwritev | 0x14e | unsigned long fd | const struct iovec __user *vec | unsigned long vlen | unsigned long pos_l | unsigned long pos_h | fs/read_write.c:784 |
335 | sys_rt_tgsigqueueinfo | 0x14f | pid_t tgid | pid_t pid | int sig | siginfo_t __user *uinfo | - | kernel/signal.c:2437 |
336 | sys_perf_event_open | 0x150 | struct perf_event_attr __user *attr_uptr | pid_t pid | int cpu | int group_fd | unsigned long flags | kernel/perf_event.c:5065 |
337 | sys_recvmmsg | 0x151 | int fd | struct mmsghdr __user *msg | unsigned int vlen | unsigned flags | struct timespec __user *timeout | net/socket.c:2168 |
6.2 64系统调用表
%rax | System call | %rdi | %rsi | %rdx | %r10 | %r8 | %r9 |
---|---|---|---|---|---|---|---|
0 | sys_read | unsigned int fd | char *buf | size_t count | |||
1 | sys_write | unsigned int fd | const char *buf | size_t count | |||
2 | sys_open | const char *filename | int flags | int mode | |||
3 | sys_close | unsigned int fd | |||||
4 | sys_stat | const char *filename | struct stat *statbuf | ||||
5 | sys_fstat | unsigned int fd | struct stat *statbuf | ||||
6 | sys_lstat | fconst char *filename | struct stat *statbuf | ||||
7 | sys_poll | struct poll_fd *ufds | unsigned int nfds | long timeout_msecs | |||
8 | sys_lseek | unsigned int fd | off_t offset | unsigned int origin | |||
9 | sys_mmap | unsigned long addr | unsigned long len | unsigned long prot | unsigned long flags | unsigned long fd | unsigned long off |
10 | sys_mprotect | unsigned long start | size_t len | unsigned long prot | |||
11 | sys_munmap | unsigned long addr | size_t len | ||||
12 | sys_brk | unsigned long brk | |||||
13 | sys_rt_sigaction | int sig | const struct sigaction *act | struct sigaction *oact | size_t sigsetsize | ||
14 | sys_rt_sigprocmask | int how | sigset_t *nset | sigset_t *oset | size_t sigsetsize | ||
15 | sys_rt_sigreturn | unsigned long __unused | |||||
16 | sys_ioctl | unsigned int fd | unsigned int cmd | unsigned long arg | |||
17 | sys_pread64 | unsigned long fd | char *buf | size_t count | loff_t pos | ||
18 | sys_pwrite64 | unsigned int fd | const char *buf | size_t count | loff_t pos | ||
19 | sys_readv | unsigned long fd | const struct iovec *vec | unsigned long vlen | |||
20 | sys_writev | unsigned long fd | const struct iovec *vec | unsigned long vlen | |||
21 | sys_access | const char *filename | int mode | ||||
22 | sys_pipe | int *filedes | |||||
23 | sys_select | int n | fd_set *inp | fd_set *outp | fd_set*exp | struct timeval *tvp | |
24 | sys_sched_yield | ||||||
25 | sys_mremap | unsigned long addr | unsigned long old_len | unsigned long new_len | unsigned long flags | unsigned long new_addr | |
26 | sys_msync | unsigned long start | size_t len | int flags | |||
27 | sys_mincore | unsigned long start | size_t len | unsigned char *vec | |||
28 | sys_madvise | unsigned long start | size_t len_in | int behavior | |||
29 | sys_shmget | key_t key | size_t size | int shmflg | |||
30 | sys_shmat | int shmid | char *shmaddr | int shmflg | |||
31 | sys_shmctl | int shmid | int cmd | struct shmid_ds *buf | |||
32 | sys_dup | unsigned int fildes | |||||
33 | sys_dup2 | unsigned int oldfd | unsigned int newfd | ||||
34 | sys_pause | ||||||
35 | sys_nanosleep | struct timespec *rqtp | struct timespec *rmtp | ||||
36 | sys_getitimer | int which | struct itimerval *value | ||||
37 | sys_alarm | unsigned int seconds | |||||
38 | sys_setitimer | int which | struct itimerval *value | struct itimerval *ovalue | |||
39 | sys_getpid | ||||||
40 | sys_sendfile | int out_fd | int in_fd | off_t *offset | size_t count | ||
41 | sys_socket | int family | int type | int protocol | |||
42 | sys_connect | int fd | struct sockaddr *uservaddr | int addrlen | |||
43 | sys_accept | int fd | struct sockaddr *upeer_sockaddr | int *upeer_addrlen | |||
44 | sys_sendto | int fd | void *buff | size_t len | unsigned flags | struct sockaddr *addr | int addr_len |
45 | sys_recvfrom | int fd | void *ubuf | size_t size | unsigned flags | struct sockaddr *addr | int *addr_len |
46 | sys_sendmsg | int fd | struct msghdr *msg | unsigned flags | |||
47 | sys_recvmsg | int fd | struct msghdr *msg | unsigned int flags | |||
48 | sys_shutdown | int fd | int how | ||||
49 | sys_bind | int fd | struct sokaddr *umyaddr | int addrlen | |||
50 | sys_listen | int fd | int backlog | ||||
51 | sys_getsockname | int fd | struct sockaddr *usockaddr | int *usockaddr_len | |||
52 | sys_getpeername | int fd | struct sockaddr *usockaddr | int *usockaddr_len | |||
53 | sys_socketpair | int family | int type | int protocol | int *usockvec | ||
54 | sys_setsockopt | int fd | int level | int optname | char *optval | int optlen | |
55 | sys_getsockopt | int fd | int level | int optname | char *optval | int *optlen | |
56 | sys_clone | unsigned long clone_flags | unsigned long newsp | void *parent_tid | void *child_tid | ||
57 | sys_fork | ||||||
58 | sys_vfork | ||||||
59 | sys_execve | const char *filename | const char *const argv[] | const char *const envp[] | |||
60 | sys_exit | int error_code | |||||
61 | sys_wait4 | pid_t upid | int *stat_addr | int options | struct rusage *ru | ||
62 | sys_kill | pid_t pid | int sig | ||||
63 | sys_uname | struct old_utsname *name | |||||
64 | sys_semget | key_t key | int nsems | int semflg | |||
65 | sys_semop | int semid | struct sembuf *tsops | unsigned nsops | |||
66 | sys_semctl | int semid | int semnum | int cmd | union semun arg | ||
67 | sys_shmdt | char *shmaddr | |||||
68 | sys_msgget | key_t key | int msgflg | ||||
69 | sys_msgsnd | int msqid | struct msgbuf *msgp | size_t msgsz | int msgflg | ||
70 | sys_msgrcv | int msqid | struct msgbuf *msgp | size_t msgsz | long msgtyp | int msgflg | |
71 | sys_msgctl | int msqid | int cmd | struct msqid_ds *buf | |||
72 | sys_fcntl | unsigned int fd | unsigned int cmd | unsigned long arg | |||
73 | sys_flock | unsigned int fd | unsigned int cmd | ||||
74 | sys_fsync | unsigned int fd | |||||
75 | sys_fdatasync | unsigned int fd | |||||
76 | sys_truncate | const char *path | long length | ||||
77 | sys_ftruncate | unsigned int fd | unsigned long length | ||||
78 | sys_getdents | unsigned int fd | struct linux_dirent *dirent | unsigned int count | |||
79 | sys_getcwd | char *buf | unsigned long size | ||||
80 | sys_chdir | const char *filename | |||||
81 | sys_fchdir | unsigned int fd | |||||
82 | sys_rename | const char *oldname | const char *newname | ||||
83 | sys_mkdir | const char *pathname | int mode | ||||
84 | sys_rmdir | const char *pathname | |||||
85 | sys_creat | const char *pathname | int mode | ||||
86 | sys_link | const char *oldname | const char *newname | ||||
87 | sys_unlink | const char *pathname | |||||
88 | sys_symlink | const char *oldname | const char *newname | ||||
89 | sys_readlink | const char *path | char *buf | int bufsiz | |||
90 | sys_chmod | const char *filename | mode_t mode | ||||
91 | sys_fchmod | unsigned int fd | mode_t mode | ||||
92 | sys_chown | const char *filename | uid_t user | gid_t group | |||
93 | sys_fchown | unsigned int fd | uid_t user | gid_t group | |||
94 | sys_lchown | const char *filename | uid_t user | gid_t group | |||
95 | sys_umask | int mask | |||||
96 | sys_gettimeofday | struct timeval *tv | struct timezone *tz | ||||
97 | sys_getrlimit | unsigned int resource | struct rlimit *rlim | ||||
98 | sys_getrusage | int who | struct rusage *ru | ||||
99 | sys_sysinfo | struct sysinfo *info | |||||
100 | sys_times | struct sysinfo *info | |||||
101 | sys_ptrace | long request | long pid | unsigned long addr | unsigned long data | ||
102 | sys_getuid | ||||||
103 | sys_syslog | int type | char *buf | int len | |||
104 | sys_getgid | ||||||
105 | sys_setuid | uid_t uid | |||||
106 | sys_setgid | gid_t gid | |||||
107 | sys_geteuid | ||||||
108 | sys_getegid | ||||||
109 | sys_setpgid | pid_t pid | pid_t pgid | ||||
110 | sys_getppid | ||||||
111 | sys_getpgrp | ||||||
112 | sys_setsid | ||||||
113 | sys_setreuid | uid_t ruid | uid_t euid | ||||
114 | sys_setregid | gid_t rgid | gid_t egid | ||||
115 | sys_getgroups | int gidsetsize | gid_t *grouplist | ||||
116 | sys_setgroups | int gidsetsize | gid_t *grouplist | ||||
117 | sys_setresuid | uid_t *ruid | uid_t *euid | uid_t *suid | |||
118 | sys_getresuid | uid_t *ruid | uid_t *euid | uid_t *suid | |||
119 | sys_setresgid | gid_t rgid | gid_t egid | gid_t sgid | |||
120 | sys_getresgid | gid_t *rgid | gid_t *egid | gid_t *sgid | |||
121 | sys_getpgid | pid_t pid | |||||
122 | sys_setfsuid | uid_t uid | |||||
123 | sys_setfsgid | gid_t gid | |||||
124 | sys_getsid | pid_t pid | |||||
125 | sys_capget | cap_user_header_t header | cap_user_data_t dataptr | ||||
126 | sys_capset | cap_user_header_t header | const cap_user_data_t data | ||||
127 | sys_rt_sigpending | sigset_t *set | size_t sigsetsize | ||||
128 | sys_rt_sigtimedwait | const sigset_t *uthese | siginfo_t *uinfo | const struct timespec *uts | size_t sigsetsize | ||
129 | sys_rt_sigqueueinfo | pid_t pid | int sig | siginfo_t *uinfo | |||
130 | sys_rt_sigsuspend | sigset_t *unewset | size_t sigsetsize | ||||
131 | sys_sigaltstack | const stack_t *uss | stack_t *uoss | ||||
132 | sys_utime | char *filename | struct utimbuf *times | ||||
133 | sys_mknod | const char *filename | umode_t mode | unsigned dev | |||
134 | sys_uselib | NOT IMPLEMENTED | |||||
135 | sys_personality | unsigned int personality | |||||
136 | sys_ustat | unsigned dev | struct ustat *ubuf | ||||
137 | sys_statfs | const char *pathname | struct statfs *buf | ||||
138 | sys_fstatfs | unsigned int fd | struct statfs *buf | ||||
139 | sys_sysfs | int option | unsigned long arg1 | unsigned long arg2 | |||
140 | sys_getpriority | int which | int who | ||||
141 | sys_setpriority | int which | int who | int niceval | |||
142 | sys_sched_setparam | pid_t pid | struct sched_param *param | ||||
143 | sys_sched_getparam | pid_t pid | struct sched_param *param | ||||
144 | sys_sched_setscheduler | pid_t pid | int policy | struct sched_param *param | |||
145 | sys_sched_getscheduler | pid_t pid | |||||
146 | sys_sched_get_priority_max | int policy | |||||
147 | sys_sched_get_priority_min | int policy | |||||
148 | sys_sched_rr_get_interval | pid_t pid | struct timespec *interval | ||||
149 | sys_mlock | unsigned long start | size_t len | ||||
150 | sys_munlock | unsigned long start | size_t len | ||||
151 | sys_mlockall | int flags | |||||
152 | sys_munlockall | ||||||
153 | sys_vhangup | ||||||
154 | sys_modify_ldt | int func | void *ptr | unsigned long bytecount | |||
155 | sys_pivot_root | const char *new_root | const char *put_old | ||||
156 | sys__sysctl | struct __sysctl_args *args | |||||
157 | sys_prctl | int option | unsigned long arg2 | unsigned long arg3 | unsigned long arg4 | unsigned long arg5 | |
158 | sys_arch_prctl | struct task_struct *task | int code | unsigned long *addr | |||
159 | sys_adjtimex | struct timex *txc_p | |||||
160 | sys_setrlimit | unsigned int resource | struct rlimit *rlim | ||||
161 | sys_chroot | const char *filename | |||||
162 | sys_sync | ||||||
163 | sys_acct | const char *name | |||||
164 | sys_settimeofday | struct timeval *tv | struct timezone *tz | ||||
165 | sys_mount | char *dev_name | char *dir_name | char *type | unsigned long flags | void *data | |
166 | sys_umount2 | const char *target | int flags | ||||
167 | sys_swapon | const char *specialfile | int swap_flags | ||||
168 | sys_swapoff | const char *specialfile | |||||
169 | sys_reboot | int magic1 | int magic2 | unsigned int cmd | void *arg | ||
170 | sys_sethostname | char *name | int len | ||||
171 | sys_setdomainname | char *name | int len | ||||
172 | sys_iopl | unsigned int level | struct pt_regs *regs | ||||
173 | sys_ioperm | unsigned long from | unsigned long num | int turn_on | |||
174 | sys_create_module | REMOVED IN Linux 2.6 | |||||
175 | sys_init_module | void *umod | unsigned long len | const char *uargs | |||
176 | sys_delete_module | const chat *name_user | unsigned int flags | ||||
177 | sys_get_kernel_syms | REMOVED IN Linux 2.6 | |||||
178 | sys_query_module | REMOVED IN Linux 2.6 | |||||
179 | sys_quotactl | unsigned int cmd | const char *special | qid_t id | void *addr | ||
180 | sys_nfsservctl | NOT IMPLEMENTED | |||||
181 | sys_getpmsg | NOT IMPLEMENTED | |||||
182 | sys_putpmsg | NOT IMPLEMENTED | |||||
183 | sys_afs_syscall | NOT IMPLEMENTED | |||||
184 | sys_tuxcall | NOT IMPLEMENTED | |||||
185 | sys_security | NOT IMPLEMENTED | |||||
186 | sys_gettid | ||||||
187 | sys_readahead | int fd | loff_t offset | size_t count | |||
188 | sys_setxattr | const char *pathname | const char *name | const void *value | size_t size | int flags | |
189 | sys_lsetxattr | const char *pathname | const char *name | const void *value | size_t size | int flags | |
190 | sys_fsetxattr | int fd | const char *name | const void *value | size_t size | int flags | |
191 | sys_getxattr | const char *pathname | const char *name | void *value | size_t size | ||
192 | sys_lgetxattr | const char *pathname | const char *name | void *value | size_t size | ||
193 | sys_fgetxattr | int fd | const har *name | void *value | size_t size | ||
194 | sys_listxattr | const char *pathname | char *list | size_t size | |||
195 | sys_llistxattr | const char *pathname | char *list | size_t size | |||
196 | sys_flistxattr | int fd | char *list | size_t size | |||
197 | sys_removexattr | const char *pathname | const char *name | ||||
198 | sys_lremovexattr | const char *pathname | const char *name | ||||
199 | sys_fremovexattr | int fd | const char *name | ||||
200 | sys_tkill | pid_t pid | ing sig | ||||
201 | sys_time | time_t *tloc | |||||
202 | sys_futex | u32 *uaddr | int op | u32 val | struct timespec *utime | u32 *uaddr2 | u32 val3 |
203 | sys_sched_setaffinity | pid_t pid | unsigned int len | unsigned long *user_mask_ptr | |||
204 | sys_sched_getaffinity | pid_t pid | unsigned int len | unsigned long *user_mask_ptr | |||
205 | sys_set_thread_area | NOT IMPLEMENTED. Use arch_prctl | |||||
206 | sys_io_setup | unsigned nr_events | aio_context_t *ctxp | ||||
207 | sys_io_destroy | aio_context_t ctx | |||||
208 | sys_io_getevents | aio_context_t ctx_id | long min_nr | long nr | struct io_event *events | ||
209 | sys_io_submit | aio_context_t ctx_id | long nr | struct iocb **iocbpp | |||
210 | sys_io_cancel | aio_context_t ctx_id | struct iocb *iocb | struct io_event *result | |||
211 | sys_get_thread_area | NOT IMPLEMENTED. Use arch_prctl | |||||
212 | sys_lookup_dcookie | u64 cookie64 | long buf | long len | |||
213 | sys_epoll_create | int size | |||||
214 | sys_epoll_ctl_old | NOT IMPLEMENTED | |||||
215 | sys_epoll_wait_old | NOT IMPLEMENTED | |||||
216 | sys_remap_file_pages | unsigned long start | unsigned long size | unsigned long prot | unsigned long pgoff | unsigned long flags | |
217 | sys_getdents64 | unsigned int fd | struct linux_dirent64 *dirent | unsigned int count | |||
218 | sys_set_tid_address | int *tidptr | |||||
219 | sys_restart_syscall | ||||||
220 | sys_semtimedop | int semid | struct sembuf *tsops | unsigned nsops | const struct timespec *timeout | ||
221 | sys_fadvise64 | int fd | loff_t offset | size_t len | int advice | ||
222 | sys_timer_create | const clockid_t which_clock | struct sigevent *timer_event_spec | timer_t *created_timer_id | |||
223 | sys_timer_settime | timer_t timer_id | int flags | const struct itimerspec *new_setting | struct itimerspec *old_setting | ||
224 | sys_timer_gettime | timer_t timer_id | struct itimerspec *setting | ||||
225 | sys_timer_getoverrun | timer_t timer_id | |||||
226 | sys_timer_delete | timer_t timer_id | |||||
227 | sys_clock_settime | const clockid_t which_clock | const struct timespec *tp | ||||
228 | sys_clock_gettime | const clockid_t which_clock | struct timespec *tp | ||||
229 | sys_clock_getres | const clockid_t which_clock | struct timespec *tp | ||||
230 | sys_clock_nanosleep | const clockid_t which_clock | int flags | const struct timespec *rqtp | struct timespec *rmtp | ||
231 | sys_exit_group | int error_code | |||||
232 | sys_epoll_wait | int epfd | struct epoll_event *events | int maxevents | int timeout | ||
233 | sys_epoll_ctl | int epfd | int op | int fd | struct epoll_event *event | ||
234 | sys_tgkill | pid_t tgid | pid_t pid | int sig | |||
235 | sys_utimes | char *filename | struct timeval *utimes | ||||
236 | sys_vserver | NOT IMPLEMENTED | |||||
237 | sys_mbind | unsigned long start | unsigned long len | unsigned long mode | unsigned long *nmask | unsigned long maxnode | unsigned flags |
238 | sys_set_mempolicy | int mode | unsigned long *nmask | unsigned long maxnode | |||
239 | sys_get_mempolicy | int *policy | unsigned long *nmask | unsigned long maxnode | unsigned long addr | unsigned long flags | |
240 | sys_mq_open | const char *u_name | int oflag | mode_t mode | struct mq_attr *u_attr | ||
241 | sys_mq_unlink | const char *u_name | |||||
242 | sys_mq_timedsend | mqd_t mqdes | const char *u_msg_ptr | size_t msg_len | unsigned int msg_prio | const stuct timespec *u_abs_timeout | |
243 | sys_mq_timedreceive | mqd_t mqdes | char *u_msg_ptr | size_t msg_len | unsigned int *u_msg_prio | const struct timespec *u_abs_timeout | |
244 | sys_mq_notify | mqd_t mqdes | const struct sigevent *u_notification | ||||
245 | sys_mq_getsetattr | mqd_t mqdes | const struct mq_attr *u_mqstat | struct mq_attr *u_omqstat | |||
246 | sys_kexec_load | unsigned long entry | unsigned long nr_segments | struct kexec_segment *segments | unsigned long flags | ||
247 | sys_waitid | int which | pid_t upid | struct siginfo *infop | int options | struct rusage *ru | |
248 | sys_add_key | const char *_type | const char *_description | const void *_payload | size_t plen | ||
249 | sys_request_key | const char *_type | const char *_description | const char *_callout_info | key_serial_t destringid | ||
250 | sys_keyctl | int option | unsigned long arg2 | unsigned long arg3 | unsigned long arg4 | unsigned long arg5 | |
251 | sys_ioprio_set | int which | int who | int ioprio | |||
252 | sys_ioprio_get | int which | int who | ||||
253 | sys_inotify_init | ||||||
254 | sys_inotify_add_watch | int fd | const char *pathname | u32 mask | |||
255 | sys_inotify_rm_watch | int fd | __s32 wd | ||||
256 | sys_migrate_pages | pid_t pid | unsigned long maxnode | const unsigned long *old_nodes | const unsigned long *new_nodes | ||
257 | sys_openat | int dfd | const char *filename | int flags | int mode | ||
258 | sys_mkdirat | int dfd | const char *pathname | int mode | |||
259 | sys_mknodat | int dfd | const char *filename | int mode | unsigned dev | ||
260 | sys_fchownat | int dfd | const char *filename | uid_t user | gid_t group | int flag | |
261 | sys_futimesat | int dfd | const char *filename | struct timeval *utimes | |||
262 | sys_newfstatat | int dfd | const char *filename | struct stat *statbuf | int flag | ||
263 | sys_unlinkat | int dfd | const char *pathname | int flag | |||
264 | sys_renameat | int oldfd | const char *oldname | int newfd | const char *newname | ||
265 | sys_linkat | int oldfd | const char *oldname | int newfd | const char *newname | int flags | |
266 | sys_symlinkat | const char *oldname | int newfd | const char *newname | |||
267 | sys_readlinkat | int dfd | const char *pathname | char *buf | int bufsiz | ||
268 | sys_fchmodat | int dfd | const char *filename | mode_t mode | |||
269 | sys_faccessat | int dfd | const char *filename | int mode | |||
270 | sys_pselect6 | int n | fd_set *inp | fd_set *outp | fd_set *exp | struct timespec *tsp | void *sig |
271 | sys_ppoll | struct pollfd *ufds | unsigned int nfds | struct timespec *tsp | const sigset_t *sigmask | size_t sigsetsize | |
272 | sys_unshare | unsigned long unshare_flags | |||||
273 | sys_set_robust_list | struct robust_list_head *head | size_t len | ||||
274 | sys_get_robust_list | int pid | struct robust_list_head **head_ptr | size_t *len_ptr | |||
275 | sys_splice | int fd_in | loff_t *off_in | int fd_out | loff_t *off_out | size_t len | unsigned int flags |
276 | sys_tee | int fdin | int fdout | size_t len | unsigned int flags | ||
277 | sys_sync_file_range | long fd | loff_t offset | loff_t bytes | long flags | ||
278 | sys_vmsplice | int fd | const struct iovec *iov | unsigned long nr_segs | unsigned int flags | ||
279 | sys_move_pages | pid_t pid | unsigned long nr_pages | const void **pages | const int *nodes | int *status | int flags |
280 | sys_utimensat | int dfd | const char *filename | struct timespec *utimes | int flags | ||
281 | sys_epoll_pwait | int epfd | struct epoll_event *events | int maxevents | int timeout | const sigset_t *sigmask | size_t sigsetsize |
282 | sys_signalfd | int ufd | sigset_t *user_mask | size_t sizemask | |||
283 | sys_timerfd_create | int clockid | int flags | ||||
284 | sys_eventfd | unsigned int count | |||||
285 | sys_fallocate | long fd | long mode | loff_t offset | loff_t len | ||
286 | sys_timerfd_settime | int ufd | int flags | const struct itimerspec *utmr | struct itimerspec *otmr | ||
287 | sys_timerfd_gettime | int ufd | struct itimerspec *otmr | ||||
288 | sys_accept4 | int fd | struct sockaddr *upeer_sockaddr | int *upeer_addrlen | int flags | ||
289 | sys_signalfd4 | int ufd | sigset_t *user_mask | size_t sizemask | int flags | ||
290 | sys_eventfd2 | unsigned int count | int flags | ||||
291 | sys_epoll_create1 | int flags | |||||
292 | sys_dup3 | unsigned int oldfd | unsigned int newfd | int flags | |||
293 | sys_pipe2 | int *filedes | int flags | ||||
294 | sys_inotify_init1 | int flags | |||||
295 | sys_preadv | unsigned long fd | const struct iovec *vec | unsigned long vlen | unsigned long pos_l | unsigned long pos_h | |
296 | sys_pwritev | unsigned long fd | const struct iovec *vec | unsigned long vlen | unsigned long pos_l | unsigned long pos_h | |
297 | sys_rt_tgsigqueueinfo | pid_t tgid | pid_t pid | int sig | siginfo_t *uinfo | ||
298 | sys_perf_event_open | struct perf_event_attr *attr_uptr | pid_t pid | int cpu | int group_fd | unsigned long flags | |
299 | sys_recvmmsg | int fd | struct msghdr *mmsg | unsigned int vlen | unsigned int flags | struct timespec *timeout | |
300 | sys_fanotify_init | unsigned int flags | unsigned int event_f_flags | ||||
301 | sys_fanotify_mark | long fanotify_fd | long flags | __u64 mask | long dfd | long pathname | |
302 | sys_prlimit64 | pid_t pid | unsigned int resource | const struct rlimit64 *new_rlim | struct rlimit64 *old_rlim | ||
303 | sys_name_to_handle_at | int dfd | const char *name | struct file_handle *handle | int *mnt_id | int flag | |
304 | sys_open_by_handle_at | int dfd | const char *name | struct file_handle *handle | int *mnt_id | int flags | |
305 | sys_clock_adjtime | clockid_t which_clock | struct timex *tx | ||||
306 | sys_syncfs | int fd | |||||
307 | sys_sendmmsg | int fd | struct mmsghdr *mmsg | unsigned int vlen | unsigned int flags | ||
308 | sys_setns | int fd | int nstype | ||||
309 | sys_getcpu | unsigned *cpup | unsigned *nodep | struct getcpu_cache *unused | |||
310 | sys_process_vm_readv | pid_t pid | const struct iovec *lvec | unsigned long liovcnt | const struct iovec *rvec | unsigned long riovcnt | unsigned long flags |
311 | sys_process_vm_writev | pid_t pid | const struct iovec *lvec | unsigned long liovcnt | const struct iovcc *rvec | unsigned long riovcnt | unsigned long flags |
312 | sys_kcmp | pid_t pid1 | pid_t pid2 | int type | unsigned long idx1 | unsigned long idx2 | |
313 | sys_finit_module | int fd | const char __user *uargs | int flags | |||
314 | sys_sched_setattr | pid_t pid | struct sched_attr __user *attr | unsigned int flags | |||
315 | sys_sched_getattr | pid_t pid | struct sched_attr __user *attr | unsigned int size | unsigned int flags | ||
316 | sys_renameat2 | int olddfd | const char __user *oldname | int newdfd | const char __user *newname | unsigned int flags | |
317 | sys_seccomp | unsigned int op | unsigned int flags | const char __user *uargs | |||
318 | sys_getrandom | char __user *buf | size_t count | unsigned int flags | |||
319 | sys_memfd_create | const char __user *uname_ptr | unsigned int flags | ||||
320 | sys_kexec_file_load | int kernel_fd | int initrd_fd | unsigned long cmdline_len | const char __user *cmdline_ptr | unsigned long flags | |
321 | sys_bpf | int cmd | union bpf_attr *attr | unsigned int size | |||
322 | stub_execveat | int dfd | const char __user *filename | const char user *const user *argv | const char user *const user *envp | int flags | |
323 | userfaultfd | int flags | |||||
324 | membarrier | int cmd | int flags | ||||
325 | mlock2 | unsigned long start | size_t len | int flags | |||
326 | copy_file_range | int fd_in | loff_t __user *off_in | int fd_out | loff_t __user * off_out | size_t len | unsigned int flags |
327 | preadv2 | unsigned long fd | const struct iovec __user *vec | unsigned long vlen | unsigned long pos_l | unsigned long pos_h | int flags |
328 | pwritev2 | unsigned long fd | const struct iovec __user *vec | unsigned long vlen | unsigned long pos_l | unsigned long pos_h | int flags |