在Linux上开始堆栈

PSk*_*cik 7 c linux memory

我以为我可以通过在main中获取变量的地址并向上舍入到页面边界来获得我的进程堆栈的开始(考虑到我的堆栈增长).

我将其与报告的边界进行了比较,/proc/self/maps并且它总是偏离1,2或3页(每页4096字节),从不偏移.差异随每次运行而变化,以下(混乱,非简约)管道中使用的此C程序证明了差异.

stacksz.c:

#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#define CAT "cat /proc/XXXXXXXXXXX/maps"
#define CATP "cat /proc/%ld/maps"
#define MASK ((sizeof(char)<<12)-1)

int main()
{
    uintptr_t  top = (uintptr_t)&top + MASK & ~MASK;

    char cat[sizeof CAT];
    sprintf(cat,CATP,(long)getpid());
    if(system(cat)) return 1;

    printf(" %lx stack\n", top);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

bash管道:

gcc stacksz.c && echo "$(( $(./a.out |grep stack |tr '-' ' ' |cut -d' ' -f2 |sed 's/^/0x/'|tr '\n' -|sed 's/-$//') ))"
Run Code Online (Sandbox Code Playgroud)

我很好奇是否有人能解释这种现象.机器是Linux precision 4.15.0-43-generic #46-Ubuntu SMP x86_64.`(我在1000次运行中获得了以下偏移分布:

4096 195
8192 490
12288 315
Run Code Online (Sandbox Code Playgroud)

).

Ctx*_*Ctx 5

ASLR 首先完全随机化虚拟内存中的堆栈位置。但它的作用还不止于此:它还随机化相对于堆栈映射顶部的堆栈指针!

来自linux源代码:

unsigned long arch_align_stack(unsigned long sp)
{
        if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space)
                sp -= get_random_int() % 8192;
        return sp & ~0xf;
}
Run Code Online (Sandbox Code Playgroud)

这里,如果 ASLR 处于活动状态,则堆栈指针减少 0-8192 字节,然后对齐 16 字节。这解释了1-3页的可变偏移量。