实现操作系统 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 架构下函数参数传递的区别的主要内容,如果未能解决你的问题,请参考以下文章

WIN10 X64下通过TLS实现反调试

x64系统的判断和x64下文件和注册表访问的重定向(举例了GetProcAddress后转成函数指针的用法)

C语言中如何实现可变参函数

X.86 X64 汇编器中的正确堆栈操作

国产化之x64平台安装银河麒麟操作系统

在 x64 架构上获得 psyco 加速?