一个x86-64的中央处理单元(CPU)包含一组16个存储64位值得通用目的寄存器。
这些寄存器用来存储整数数据和指针。
long exchange(long *xp, long y)
{
long x = *xp;
*xp = y;
return x;
}
像x这样的局部变量通常是保存在寄存器中,而不是内存中。
访问寄存器比访问内存要快得多。
指令类ADD由四条加法指令组成:addb、addw、addl、addq,分别是字节加法、
字加法、双字加法和四字加法。
long scale(long x, long y, long z) {
long t = x + 4*y + 12*z;
rerurn t;
}
x86-64中,可以通过寄存器最多传递6个整型(例如整数和指针)参数。
如果一个函数有大于6个整型参数,超出6个的部分就要通过栈来传递。
寄存器组是唯一被所有过程共享的资源。
.align 8
这就保证了它后面的数据(在此,是跳转表的开始)的起始地址是8个倍数。
因为每个表项长8个字节,后面的元素都会遵守8字节对齐的限制。
struct S1 {
int i;
char c;
int j;
};
用下面的命令行来启动GDB:
linux> gdb grog
为了在系统中插入攻击代码,攻击者既要插入代码,也要插入指向这段代码的指针,
这个指针也是攻击字符串的一部分。
int main() {
long local;
printf("local at %p\n", &local);
return 0;
}
这段代码只是简单地打印出main函数中局部变量的地址。在32位Linux上运行这段代码
10000次,这个地址的变化范围为0xff7fc59c到0xffffd09c,范围大小大约是2 的23次方。
在更新一点儿的机器上运行64位Linux,这个地址的变化范围为0x7fff0001b698到
0x7ffffffaa4a8,范围大小大约2的32次方。
在Linux系统中,栈随机化已经变成了标准行为。
采用ASLR,每次运行时程序的不同部分,包括程序代码、库代码、栈、全局变量和堆数据,
都会被加载到内存的不同区域。这就意味着在一台机器上运行一个程序,与在其他机器上运行
同样的程序,他们的地址映射大相径庭。这样才能对抗一些形式的攻击。
C++的对象用结构来表示,类似于C的struct。
C++的方法是用指向实现方法的代码的指针来表示的。
Java的目标代码是一种特殊的二进制表示,称为Java字节代码。
这种代码可以看成是虚拟机的机器级程序。正如它的名字暗示的那样,这种机器并不是
直接用硬件实现的,而是用软件解释器处理字节代码,模拟虚拟机的行为。
处理器体系结构
有15个程序寄存器:%rax,%rcx,%rdx,%rbx,%rsp,%rbq,%rsi,%rdi,%r8,%r14