ARM linux:进程地址空间

时间:2012-05-22 07:42:00

标签: linux-kernel arm embedded-linux

我正在使用带有ARM cortex_A9_MPCORE处理器的开发板(雪球),使用3.0.8+内核运行linux。 我使用GDB和openocd进行调试。

我正在寻找一种方法来查找用户模式进程的地址空间,尤其是文本段和用户模式堆栈。

首先我查看/ proc /“PID”/ maps,例如我正在为其中一个进程运行此输出:

# cat /proc/1124/maps
00008000-000d5000 r-xp 00000000 b3:02 181        /system/bin/lbsd
000d5000-000f8000 rw-p 000cd000 b3:02 181        /system/bin/lbsd
000f8000-0014a000 rw-p 00000000 00:00 0          [heap]
0014a000-0014c000 rw-p 00000000 00:00 0          [heap]
.
.
.
b0001000-b0009000 r-xp 00001000 b3:02 183        /system/bin/linker
b0009000-b000a000 rw-p 00009000 b3:02 183        /system/bin/linker
b000a000-b0015000 rw-p 00000000 00:00 0 
bea00000-bea21000 rw-p 00000000 00:00 0          [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

然后使用GDB我编写了一个脚本,用于解析板上运行的任务列表,从init_task开始,对于每个任务,它获取task_struct中找到的mm_struct的值,然后提取start_code,end_code和start_stack的值。最后,脚本解析mmap指向的不同内存区域。 当电路板处于调试状态时脚本运行,皮质a9的两个核都停止

以下是与上述相同过程的GDB脚本的输出:

taskaddr 0xdf29f140
Name: lbsd
mm start text 8000
mm end text d4ba4
mm start stack bee63df0
####MEMORY REGIONS#####
vm_start 0x8000
vm_end 0xd5000
vm_flags 0x8001875
-----------------------
vm_start 0xd5000
vm_end 0xf8000
vm_flags 0x8101873
-----------------------
vm_start 0xf8000
vm_end 0x14a000
vm_flags 0x100073
-----------------------
vm_start 0x14a000
vm_end 0x14c000
vm_flags 0x100073
-----------------------
.
.
.
-----------------------
vm_start 0xb0001000
vm_end 0xb0009000
vm_flags 0x8000875
-----------------------
vm_start 0xb0009000
vm_end 0xb000a000
vm_flags 0x8100873
-----------------------
vm_start 0xb000a000
vm_end 0xb0015000
vm_flags 0x100073
-----------------------
vm_start 0xbee42000
vm_end 0xbee64000
vm_flags 0x100173
-----------------------
vm_start 0xffff0000
vm_end 0xffff1000
vm_flags 0x40c0055
-----------------------

内存区域匹配除了堆栈之外使用的方法,在/ proc方法的输出中它从bea00000开始,而在mm_struct的start_stack字段中它在bee63df0,而vm_struct指向的内存区域表示bee42000 。 有人可以解释这些值的差异吗?

我的第二个问题是关于00008000和000d5000之间的第一个存储区域的值,它对应于该过程的文本部分。我注意到很多进程共享这些地址。内核如何设法获取文本内存区域的真实地址?

1 个答案:

答案 0 :(得分:1)

在ARM上,堆栈会逐渐减少。这意味着堆栈从更高的地址开始。这在堆栈vm_flags的{​​{1}}中可见,其中vma位已设置。

堆栈VM_GROWSDOWN的{​​{1}}为vma,比vm_end的{​​{1}}高出528个字节。发生这种情况是因为在同一个VMA中堆栈顶部之上有一些东西:命令行,环境和辅助向量。

我不知道为什么堆栈(只有它)位于0xbee64000的不同地址。查看内核源代码,我看到start_stack可以显示为0xbee63df0当且仅当/proc/<pid>/maps在其中时,所以如果vma与您相同查看[stack]start_stack无法标记为start_stack。我能想到的唯一解释是它来自可执行文件的不同运行,并且除了堆栈之外的所有内容都禁用了地址布局随机化。


现在是第二个问题。

当您的进程正在运行时,硬件使用页表从虚拟地址(例如/proc/<pid>/maps)映射到页面的物理地址。内核也可以这样做;它有一个指向其vma中进程的根页表([stack])的指针。一旦它具有物理页码(0x8000),它就可以到达相应的pgd。有一大堆宏和函数可以完成所有这些操作。

但是页面可能会丢失。例如,您的可执行文件的其中一个页面可能尚未出现故障。页面表中该页面的条目将显示为缺失。然后内核查看相应的mm_struct,其中pfn内的偏移量具有从某处获取页面的足够信息,并将其插入页面表中。