我知道 ASLR 每次都会在不同的内存位置加载程序,但是,我不确定为什么在我存储在 Linux 虚拟机的磁盘
/dev/sda2
上的文件的情况下会发生这种情况。
mp:projects-20:17:09-$ ./lseek_demo
The end offset of file1 is 1268
The start offset of file2 is 0
Diff between them is -1268
The mem address of file1 is 0x7ffce008e738
The mem address of file2 is 0x7ffce008e740
mp:projects-20:17:12-$ ./lseek_demo
The end offset of file1 is 1268
The start offset of file2 is 0
Diff between them is -1268
The mem address of file1 is 0x7fff9113e148
The mem address of file2 is 0x7fff9113e150
这是我正在使用的代码
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <error.h>
void offsets(const char* fname1,const char* fname2)
{
int fd0 = open(fname1, O_RDWR);
int fd1 = open(fname2, O_RDWR);
if (fd0 == -1 || fd1 == -1)
perror("opne");
off_t off_fd0 = lseek(fd0, -1, SEEK_END);
off_t off_fd1 = lseek(fd1,0,SEEK_SET);
close(fd0);
close(fd1);
printf ("The end offset of file1 is %ld\n The start offset of file3 is %ld\n Diff between them is %ld\n",off_fd0, off_fd1,(off_fd1 - off_fd0));
printf ("The mem address of file1 is %p\n The mem address of file2 is %p\n",&off_fd0,&off_fd1);
}
int main()
{
offsets ("readme.txt","slack_space_calc.c");
return 0;
}
这是编译于
ubuntu 6.8.0-38-generic #38-Ubuntu
此代码:
off_t off_fd0 = lseek(fd0, -1, SEEK_END);
off_t off_fd1 = lseek(fd1,0,SEEK_SET);
声明两个(某些未指定位长度)有符号整数类型的局部变量,并将它们设置为
lseek()
的返回值。这些变量被下面的代码强制存储在堆栈上;稍后会详细介绍。
表达式
&off_fd0
返回指向off_fd0
变量的指针,而不是“文件”的地址。因此,当您使用 %p 打印它时,您正在打印该堆栈变量的内存地址。
一个有趣的旁注。如果删除该 print 语句,编译器很可能会优化一个或两个变量。 IE。它将把
lseek()
调用的返回值保存在 CPU 寄存器中。此时,变量根本没有地址。 (这取决于您使用的编译器、目标 CPU 架构以及为编译选择的优化级别。)表达式 &off_fd0
的存在迫使编译器为该变量分配堆栈存储,并在此过程中您的代码效率稍低。
至于为什么这些变量的地址在一次运行中会有所不同。曾经有一段时间情况并非如此——每次运行程序时,堆栈都会位于同一个位置。欢迎来到 ASLR - 甚至堆栈也会移动。