Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用pmap分析进程的内存映射。[堆栈]_C_Linux_Linux Kernel_Stack_Mmap - Fatal编程技术网

C 使用pmap分析进程的内存映射。[堆栈]

C 使用pmap分析进程的内存映射。[堆栈],c,linux,linux-kernel,stack,mmap,C,Linux,Linux Kernel,Stack,Mmap,我试图理解栈在Linux中是如何工作的。我阅读了有关堆栈和进程初始化的部分,不清楚应该如何映射堆栈。以下是相关报价3.4.1: 堆栈状态 本节介绍exec BA_OS为其创建的机器状态 新工艺 及 未指定数据段和堆栈段最初是否为空 是否映射了执行权限。需要 在堆栈或数据段上执行代码应采取适当的 预防措施,例如致电mprotect 因此,我可以从上面的引号中推断,堆栈已映射,如果使用PROT_EXEC创建映射,则未指定。映射也是由exec创建的 问题是主线程的堆栈是使用MAP|u GROWSDOW

我试图理解栈在Linux中是如何工作的。我阅读了有关堆栈和进程初始化的部分,不清楚应该如何映射堆栈。以下是相关报价3.4.1:

堆栈状态

本节介绍exec BA_OS为其创建的机器状态 新工艺

未指定数据段和堆栈段最初是否为空 是否映射了执行权限。需要 在堆栈或数据段上执行代码应采取适当的 预防措施,例如致电mprotect

因此,我可以从上面的引号中推断,堆栈已映射,如果使用PROT_EXEC创建映射,则未指定。映射也是由exec创建的

问题是主线程的堆栈是使用MAP|u GROWSDOWN | MAP|u堆栈映射还是甚至通过sbrk

查看pmap-x,堆栈用[stack]标记为

将映射创建为

mmap(NULL, 4096,
     PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK,
     -1, 0);
只需创建匿名映射,如pmap-x中所示

我可以从上面的引号中推断堆栈已映射

从字面上说,这只是意味着内存被分配了。i、 e.这些虚拟地址与物理页面之间存在逻辑映射。我们知道这一点,因为您可以在_start中使用push或call指令,而无需从用户空间进行系统调用来分配堆栈

事实上,x86-64 System V ABI指定在进程启动时,argc、argv和envp在堆栈上

问题是主线程的堆栈是使用MAP|u GROWSDOWN | MAP|u堆栈映射还是甚至通过sbrk

ELF二进制加载程序为主线程堆栈设置_GROWSDOWN标志,但不设置MAP_堆栈标志。这是内核中的代码,它不经过常规的mmap系统调用接口

用户空间中没有任何东西使用mmapMAP_GROWSDOWN,因此通常主线程堆栈是内核中唯一具有VM_GROWSDOWN标志的映射

用于堆栈的虚拟内存aree VMA的标志的内部名称称为VM_GROWSDOWN。如果您感兴趣,以下是用于主线程堆栈的所有标志:VM_GROWSDOWN、VM_READ、VM_WRITE、VM_MAYREAD、VM_mayrite和VM_MAYEXEC。此外,如果指定ELF二进制文件具有可执行堆栈(例如,通过使用gcc-z execstack编译),则还将使用VM_EXEC标志。请注意,在支持向上增长的堆栈的体系结构上,如果内核是在定义了CONFIG_STACK_GROWSUP的情况下编译的,则使用VM_GROWSUP而不是VM_GROWSDOWN。可以找到在Linux内核中指定这些标志的代码行

/proc/../maps和pmap不使用VM_GROWSDOWN-它们依赖于地址比较。因此,它们可能无法准确确定主线程堆栈占用的虚拟地址空间的确切范围。另一方面,/proc/../smap查找VM_GROWSDOWN标志并将具有该标志的每个内存区域标记为gd。尽管它似乎忽略了VM_GROWSUP

所有这些工具/文件都会忽略映射堆栈标志。事实上,整个Linux内核忽略了这个标志,这可能就是程序加载器没有设置它的原因。如果内核确实希望开始专门处理线程堆栈分配,用户空间只会将其传递给将来的验证

sbrk在这里毫无意义;堆栈与断点不相邻,而且brk堆仍然朝堆栈方向向上增长。Linux将堆栈放在非常接近虚拟地址空间顶部的位置。因此,主堆栈当然不能与内核中的sbrk等价物一起分配

不,没有任何东西使用MAP_GROWSDOWN,甚至次级线程堆栈也没有,因为它通常不能安全使用

mmap2手册页上说MAP_GROWSDOWN用于堆栈,这是可笑的过时和误导。看见作为Ulrich Drepper,使用MAP_GROWSDOWN的代码通常会被破坏,并建议从Linux mmap和glibc头中删除该标志。这显然没有发生,但pthreads在那之前很久没有使用过它

MAP_GROWSDOWN为内核内的映射设置VM_GROWSDOWN标志。主线程还使用该标志来启用增长机制,因此线程堆栈可能能够以与主堆栈相同的方式增长:任意远至ulimit-s?如果堆栈指针低于页面错误位置。Linux不要求堆栈探测器接触大型多页堆栈阵列或alloca的每一页

线程堆栈完全预先分配;只有正常的物理页延迟分配来支持虚拟分配,才能避免为线程堆栈浪费空间

MAP_GROWSDOWN映射也可以按照mmap手册页所描述的方式增长:访问最低映射页下方的保护页也会触发增长,即使该页面位于红色区域底部下方

但是主要的 线程堆栈具有mmapMAP_GROWSDOWN无法获得的魔力。它保留到ulimit-s的增长空间,以防止随机选择mmap地址造成堆栈增长的障碍。这种魔力只适用于内核内程序加载器,它在execve期间映射主线程的堆栈,使其不受mmapNULL的影响。。。随机阻止未来堆栈增长

mmapMAP_FIXED仍然可以为主堆栈创建路障,但是如果您使用MAP_FIXED,您将100%负责不破坏任何东西。MAP_FIXED将替换现有映射和保留,但其他任何操作都会将主线程的堆栈增长空间视为保留空间;。我认为这是真的;值得尝试使用MAP\u FIXED\u NOREPLACE或一个非空提示地址

pthread_create不对线程堆栈使用MAP_GROWSDOWN,其他任何人也不应该这样做。一般不使用。默认情况下,Linux pthreads为线程堆栈分配完整大小。这会占用虚拟地址空间,但在实际接触到它之前,不会占用物理页面


这种不一致的结果导致一些人评论说它有效,一些人发现它在触摸返回值时仍然会出错,下面的页面听起来像-MAP\u GROWSDOWN甚至可能在使用标准主堆栈VM\u GROWSDOWN映射的方式之外有问题。

函数:sbrk用于更改数据段大小。它与堆栈无关如果我们检查pmap的源代码,我们可以看到它依赖于/proc/pid/stat文件中的信息来确定给定地址是否在堆栈中。初始化具有此信息的proc\t类型的对象。其中一个字段是start_stack,它保存主线程堆栈中程序堆栈的基址。pmap还……/proc/pid/smap以获取堆栈的大小。然后,在代码行,它将给定地址与基本堆栈地址进行比较,如果它位于堆栈区域,则标记为[stack]。因此,是否使用MAP_GROWSDOWN标志分配内存区域并不重要。该工具只是不检查此标志。此外,当将MAP_GROWSDOWN标志传递给mmap时,它会被转换为一个名为VM_GROWSDOWN的内部标志……页面错误处理程序会检查该标志,以确定堆栈中是否发生了页面错误,如果可能的话,它应该增长堆栈。所有线程的堆栈都用VM_GROWSDOWN标记。我认为,如果pmap使用MAP_GROWSDOWN而不是与程序堆栈地址进行比较,它将为分配有此标志的任何区域打印[stack],即使该区域未用作线程堆栈。因此,当mmap2手册页说MAP_GROWSDOWN用于堆栈时,它是准确的,“因为是的。”哈迪布雷斯:我刚刚更新了我的答案。感谢您的编辑,关于内核内VM标志的讨论非常有用。我认为用户空间中没有任何东西会使用MAP_GROWSDOWN,因为我认为这一点很重要。我没有寻找任何进一步的讨论,但很明显,MAP_GROWSDOWN实际上并没有从glibc标题中删除。
mmap(NULL, 4096,
     PROT_READ | PROT_WRITE,
     MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK,
     -1, 0);
00007fb6e42fa000       4       0       0 rw---   [ anon ]