x86和x86_64架构的区别
32位最大寻址空间
- x86是32位的架构,地址总线宽度为32位
- 理论可访问的最大寻址空间为
2^32字节,约等于4GB - 实际中,操作系统通常将其中一部分用于内核空间,用户态程序可用空间为2GB或者3GB
- 超过该限制的应用将无法在纯32位的系统中运行
但是渐渐的32位的架构不够我们的需求,所以64位就应运而生
64位最大寻址空间
- x86_64是64位架构,地址总线宽度为64位
- 理论可以访问的最大寻址空间为
2^64字节,约等于16EB(Exabytes) - 当前主流的CPU实际支持48位至52位的虚拟地址,即最大寻址能力在256TB至4PB之间
- 用户进程可使用更大内存空间,适用于虚拟化、数据库、AI等高内存应用场景
x86下的寄存器
通用寄存器
- EAX:累加器,用于算术和逻辑运算
- EBX:基址寄存器,可用于访问内存中的变量
- ECX:计数器,常用于循环和字符串操作
- EDX:数据寄存器,用于乘除法指令中作为拓展位使用
- ESI:源索引,用于字符串复制、数组访问等场景
- EDI:目的索引,与ESI搭配使用
- ESP:栈指针,始终指向栈顶
- EBP:基址指针,用于建立函数的栈帧结构
分段寄存器
- CS:代码段寄存器
- DS:数据段寄存器
- SS:栈段寄存器
- ES、FS、GS:扩展段寄存器,用于额外访问内存或线程本地存储
分段机制在实模式和保护模式下意义不同,在现代系统中多数用于兼容目的或线程本地数据访问
特殊用途寄存器
- EIP:指令指针寄存器,指向下一条将要执行的指令地址
- EFLAGS:标志寄存器,用于记录算术、逻辑操作结果状态
- ZF:零标志,结果是否为零
- CF:进位标志,是否产生进位
- OF:溢出标志,是否产生有符号溢出
- SF:符号标志,结果是否为负
子寄存器
所有32位通用寄存器都可以拆分访问其低位部分
例如:
- AX是EAX的低16位,AH是AX的高8位,AL是AX的低8位
- 同理BX->BH/BL,...
子寄存器常用于字节级别的数据处理,例如处理ASCII字符、I/O操作、传感器数据采集等
简单代码分析x86寄存器
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int c = a + b;
int arr[3] = {1, 2, 3};
int i;
for(i = 0; i < 3; i++)
printf("arr[%d] = %d\n", i, arr[i]);
return 0;
}gcc -m32 -g -fno-pie -no-pie -o x86_test x86_test.clayout regs此时eax清空

EIP:指令指针寄存器,指向下一条将要执行的指令地址

EAX:累加器,用于算术和逻辑运算(计算结果存储在eax)

数组和i


此处ebp-0x18为基地址,eax为下标,4为数据类型int的大小




在调试的过程中可以发现每当push一个值,esp基本都会减少4,正印证了栈是从高往低增长,然后esp永远指向栈顶,ebp永远指向栈底
x86_64下的寄存器
寄存器数量扩展
除了保留所有x86兼容寄存器外,x86_64架构新增以下64位寄存器:
- RAX、RBX、RCX、RDX、RSP、RBP、RSI、RDI
- 新增:R8、R9、R10、R11、R12、R13、R14、R15
每个寄存器均支持64位运算,并可拆分为32位、16位、8位子寄存器访问
RIP会替代EIP,作为64位的指令指针
调用约定变化
在64位系统下,参数的传递改由寄存器优先完成
System V(Linux、macOS):
- 参数依次放入RDI、RSI、RDX、RCX、R8、R9
Windows x64: - 参数依次放入RCX、RDX、R8、R9
超过参数寄存器数量后,继续使用栈传递,返回值通常存储在RAX寄存器
兼容模式:运行32位程序
64位处理器支持在兼容模式下运行32位程序
Windows使用WOW64(Windows on Windows 64)子系统完成兼容
Linux可以安装32位动态链接库或运行在兼容模式内核下完成支持
CPU在进入兼容模式时,将只启用前32位寄存器位宽和寻址
简单代码分析x86_64寄存器
#include <stdio.h>
long add(long a, long b, long c, long d, long e, long f) {
return a+b+c+d+e+f;
}
int main() {
long result = add(1,2,3,4,5,6);
printf("Result:%ld",result);
return 0;
}编译指令:
gcc -g x64_test.c -o x64_test调试:
- 在add函数中查看RDI、RSI、RDX、RCX、R8、R9的值
- 使用layout reg或info reg可以实时查看寄存器变化
可以看到这边的x64位的程序传递参数先传递到寄存器的地位R9、R8、RCX、RDX、RSI、RDI,途中显示的r9d、r8d、ecx、edx、esi、edi都是32位的子寄存器
此外rip替代eip,一直指示着下一段要执行代码的地址

进行两两相加,值存放到RDX中

最终结果传递到RAX中

接下来就是在调用printf的时候将两个参数放入RSI和RDI了

评论 (0)