数据段之前未初始化的可写数据

时间:2016-12-06 05:06:48

标签: c assembly compilation brainfuck

我正在编写一个将brainfuck代码转换为x86_64程序集的简单程序。部分原因是在程序开始时创建一个大的零初始化数组。因此,每个编译的程序都以以下汇编代码开头:

.data
ARR:
    .space 32430
.text
.globl _start
.type _start, @function
_start:
    ...     #code as compiled from the brainfuck program
    ...

从那里编译的程序应该能够访问该数组的任何部分,但如果它试图在它之前或之后访问内存它应该是段错误的。

因为数组直接跟着一个.text部分,我的理解是只读的,并且因为它是程序的第一部分,所以我期望我想要的行为会自然而然地跟随。不幸的是,情况并非如此:已编译的程序能够访问数组开头左边(即地址低于)的非零初始化数据。

为什么会出现这种情况,是否有任何我可以在汇编代码中包含哪些内容来阻止它呢?

1 个答案:

答案 0 :(得分:0)

这当然是高度依赖系统的,但由于您的观察结果适合典型的Linux / GNU系统,我将参考这样一个系统。

  

我认为链接器并不是将我的片段放在我认为的位置。

是的,链接器不会按照它们在您的代码段中显示的顺序放置段,而是首先.text.data秒。我们可以看到这个e。 G。与

> objdump -h ARR

ARR:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00000042  08048074  08048074  00000074  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00007eae  080490b8  080490b8  000000b8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  

编译的程序能够访问数组开头左边(即地址低于)的非零初始化数据。

     

为什么会这样呢......

正如我们在上面的示例中所看到的,.data部分在内存地址080490b8处链接。虽然内存页面的长度为PAGE_SIZE(此处getconf PAGE_SIZE产生4096,即1000 16 )并从该大小的倍数开始,但数据的起始地址偏移量等于文件偏移 000000b8(数据存储在磁盘文件中),因为包含.data部分的文件页面作为copy-on-write页面映射到内存中。 .data部分下面的非零初始化数据恰好出现在第一个文件页面0到b7 16 的位置,包括{{1 }}

  

...我可以在汇编代码中包含任何可以阻止它的内容吗?

     

我更喜欢使用一种解决方案来放置我的网段,以防错误的数组访问导致段错误。

正如Margaret Bloom和Ped7g暗示的那样,你可以在.text以下分配额外的数据并创建一个无法访问的防护页面。通过将ARR下一个页面地址对齐,可以轻松完成此操作。下面的示例程序实现了这一点,并允许通过接受访问ARR数据的索引参数(可选地为负)来测试它;如果在边界内,它应该退出状态0,否则段错误。注意:此方法仅在ARR部分未在页面边界处结束时有效,因为如果确实如此,则.text无效;但由于汇编代码是使用转换器程序创建的,因此该程序应该能够检查并在需要时添加一些额外的.align 4096字节。

.text