实现操作系统 00x86 与 x64 架构下函数参数传递的区别
Posted Imagine Miracle
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现操作系统 00x86 与 x64 架构下函数参数传递的区别相关的知识,希望对你有一定的参考价值。
1. x86 架构与 x64 架构简介
这两个词相信学过计算机和没学过计算机的都耳熟能详,本文对此仅作简单的阐述。x86
架构采用复杂指令集计算机 (CISC——Complex Instruction Set Computer
) 架构,因此该架构并没有大量的通用寄存器,仅使用少量的专用寄存器。
x86
架构由 8
个非特权整数寄存器 (Unprivileged interger register
) 组成,分别为:
寄存器名 | 描述 |
---|---|
eax |
累加寄存器 |
ebx |
基地址寄存器 |
ecx |
计数寄存器 |
edx |
数据寄存器(可用于 I/O 端口访问和算术功能) |
esi |
源索引寄存器 |
edi |
目标索引寄存器 |
ebp |
基地址指针寄存器 |
esp |
堆栈指针寄存器 |
每个寄存器最大可表示 32
位,且每个寄存器名均由 e
字母开头。当使用寄存器使用时不加 e
开头则表示使用该寄存器的低 16
位。如:
x86_64及aarch64架构传参规则
1. x86_64参数传递
x86_64汇编语言函数通过rdi、rsi、rdx、rcx、r8、r9(edi、esi、edx、ecx、r8、r9)传递。即:
- 1个参数: rdi(edi)
- 2个参数: rdi、rsi(edi、rsi)
- 3个参数: rdi、rsi、rdx(edi、esi、edx)
- 4个参数: rdi、rsi、rdx、rcx(edi、esi、edx、ecx)
- 5个参数: rdi、rsi、rdx、rcx、r8(edi、esi、edx、ecx、r8)
- 6个参数: rdi、rsi、rdx、rcx、r8、r9(edi、esi、edx、ecx、r8、r9)
当参数个数小于等于6个时, 使用寄存器rdi,rsi,rdx,rcx,r8,r9。从第7个参数开始通过栈传递, 顺序为从右往左入栈。
x64架构下一共有16个通用寄存器, 以’r’开头。而32位系统的寄存器是以’e’开头的. 实际上64位的系统架构也兼容了32位系统。我们仍然可以在64位系统中使用如’eax’等寄存器, 表示只使用’rax’寄存器的低32位, 其剩余的高32位会自动补全
/* x86_64.c */
# include<stdio.h>
void fun1(int a)
void fun2(int a,int b)
void fun3(int a,int b,int c)
void fun4(int a,int b,int c,int d)
void fun5(int a,int b,int c,int d,int e)
void fun6(int a,int b,int c,int d,int e,int f)
void fun7(int a,int b,int c,int d,int e,int f, int g)
void main()
int a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8;
fun1(a);
fun2(a,b);
fun3(a,b,c);
fun4(a,b,c,d);
fun5(a,b,c,d,e);
fun6(a,b,c,d,e,f);
fun7(a,b,c,d,e,f,g);
执行 gcc -S x86_64.c
movl -4(%rbp), %eax
movl %eax, %edi
call fun1
movl -8(%rbp), %edx
movl -4(%rbp), %eax
movl %edx, %esi
movl %eax, %edi
call fun2
movl -12(%rbp), %edx
movl -8(%rbp), %ecx
movl -4(%rbp), %eax
movl %ecx, %esi
movl %eax, %edi
call fun3
movl -16(%rbp), %ecx
movl -12(%rbp), %edx
movl -8(%rbp), %esi
movl -4(%rbp), %eax
movl %eax, %edi
call fun4
movl -20(%rbp), %edi
movl -16(%rbp), %ecx
movl -12(%rbp), %edx
movl -8(%rbp), %esi
movl -4(%rbp), %eax
movl %edi, %r8d
movl %eax, %edi
call fun5
movl -24(%rbp), %r8d
movl -20(%rbp), %edi
movl -16(%rbp), %ecx
movl -12(%rbp), %edx
movl -8(%rbp), %esi
movl -4(%rbp), %eax
movl %r8d, %r9d
movl %edi, %r8d
movl %eax, %edi
call fun6
movl -24(%rbp), %r9d
movl -20(%rbp), %r8d
movl -16(%rbp), %ecx
movl -12(%rbp), %edx
movl -8(%rbp), %esi
movl -4(%rbp), %eax
movl -28(%rbp), %edi
pushq %rdi
movl %eax, %edi
call fun7
2. aarch64参数传递
aarch64汇编语言函数前8个参数使用x0-x7寄存器(或低32位w0-w7寄存器)传递, 多于8个的参数均通过堆栈传递
/* aarch64.c */
# include<stdio.h>
void fun1(int a)
void fun2(int a,int b)
void fun3(int a,int b,int c)
void fun4(int a,int b,int c,int d)
void fun5(int a,int b,int c,int d,int e)
void fun6(int a,int b,int c,int d,int e,int f)
void fun7(int a,int b,int c,int d,int e,int f,int g)
void fun8(int a,int b,int c,int d,int e,int f,int g,int h)
void fun9(int a,int b,int c,int d,int e,int f,int g,int h,int i)
void main()
int a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9;
fun1(a);
fun2(a,b);
fun3(a,b,c);
fun4(a,b,c,d);
fun5(a,b,c,d,e);
fun6(a,b,c,d,e,f);
fun7(a,b,c,d,e,f,g);
fun8(a,b,c,d,e,f,g,h);
fun9(a,b,c,d,e,f,g,h,i);
执行 gcc -S aarch64.c
ldr w0, [sp, 76]
bl fun1
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun2
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun3
ldr w3, [sp, 64]
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun4
ldr w4, [sp, 60]
ldr w3, [sp, 64]
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun5
ldr w5, [sp, 56]
ldr w4, [sp, 60]
ldr w3, [sp, 64]
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun6
ldr w6, [sp, 52]
ldr w5, [sp, 56]
ldr w4, [sp, 60]
ldr w3, [sp, 64]
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun7
ldr w7, [sp, 48]
ldr w6, [sp, 52]
ldr w5, [sp, 56]
ldr w4, [sp, 60]
ldr w3, [sp, 64]
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun8
ldr w0, [sp, 44]
str w0, [sp]
ldr w7, [sp, 48]
ldr w6, [sp, 52]
ldr w5, [sp, 56]
ldr w4, [sp, 60]
ldr w3, [sp, 64]
ldr w2, [sp, 68]
ldr w1, [sp, 72]
ldr w0, [sp, 76]
bl fun9
以上是关于实现操作系统 00x86 与 x64 架构下函数参数传递的区别的主要内容,如果未能解决你的问题,请参考以下文章