objdump vs / proc / pid / maps的虚拟内存地址?
我正在尝试了解程序的可执行程序集在程序加载/运行时的确切位置.我发现有两个资源在讨论这个问题,但它们有点难以阅读:
> Understanding ELF using readelf and objdump Linux article(代码格式混乱) 所以,这是一个简短的例子;我很感兴趣尾部程序的可执行部分最终在哪里.基本上,objdump告诉我这个: $objdump -dj .text /usr/bin/tail | head -10 /usr/bin/tail: file format elf32-i386 Disassembly of section .text: 08049100 <.text>: 8049100: 31 ed xor %ebp,%ebp 8049102: 5e pop %esi 8049103: 89 e1 mov %esp,%ecx ... 我假设我看到在这里调用tail的’main()’,没有剥离符号.无论如何,可执行部分的开头是,根据这个,0x08049100;我对它最终到底的地方感兴趣. 然后,我在后台运行尾巴,得到它的pid: $/usr/bin/tail -f & echo $! 28803 …我检查它的/ proc / pid / maps: $cat /proc/28803/maps 00547000-006a8000 r-xp 00000000 08:05 3506 /lib/i386-linux-gnu/libc-2.13.so ... 008c6000-008c7000 r-xp 00000000 00:00 0 [vdso] 08048000-08054000 r-xp 00000000 08:05 131469 /usr/bin/tail 08054000-08055000 r--p 0000b000 08:05 131469 /usr/bin/tail 08055000-08056000 rw-p 0000c000 08:05 131469 /usr/bin/tail 08af1000-08b12000 rw-p 00000000 00:00 0 [heap] b76de000-b78de000 r--p 00000000 08:05 139793 /usr/lib/locale/locale-archive ... bf845000-bf866000 rw-p 00000000 00:00 0 [stack] 现在我有三次尾 – 但是可执行段r-xp(它是.text?)显然是在0x08048000(一个地址显然是was standardized back with SYSV for x86;另一个看到Anatomy of a Program in Memory : Gustavo Duarte的图像) 使用下面的gnuplot脚本,我得到了这个图像: 第一个(最上面)的图显示了来自objdump(从0x0开始)的部分的“文件偏移”;中间图显示来自objdump和底部图的部分的“VMA”(虚拟内存地址)显示来自/ proc / pid / maps的布局 – 这两个部分都从0x08048000开始;所有三个图都显示相同的范围. 比较最上层和中间的情节,似乎这些部分“从原样”可执行文件到VMA地址(除了结尾)之外更多地翻译;这样整个可执行文件(不仅仅是.text部分)从0x08048000开始. 但是比较中间和底部的情节,似乎当程序在内存中运行时,只有.text被“推回”到0x08048000 – 而且不仅如此,它现在看起来更大了! 我到目前为止唯一的解释是我在某处读到的内容(但丢失了链接):内存中的图像必须分配整数页(大小为4096字节),并从页边界开始.整个页面数量说明了更大的尺寸 – 但是,鉴于所有这些都是虚拟地址,为什么需要将它们“捕捉”到页面边界(也可能不会将虚拟地址映射到物理地址)页面边界?) 那么 – 有人可以提供一个解释,以便为什么/ proc / pid / maps看到.text部分在与objdump不同的虚拟地址区域中? mem.gp gnuplot脚本: #!/usr/bin/env gnuplot set term wxt size 800,500 exec = "/usr/bin/tail" ; # cannot do - apparently gnuplot waits for children to exit,so locks here: #runcmd = "bash -c '" . exec . " -f & echo $!'" #print runcmd #pid = system(runcmd) ; #print runcmd,"pid",pid # run tail -f & echo $! in another shell; then enter pid here: pid = 28803 # $1 Idx $2 Name $3 Size $4 VMA $5 LMA $6 File off cmdvma = "<objdump -h ".exec." | awk '$1 ~ "^[0-9]+$" && $2 !~ ".gnu_debuglink" {print $1,$2,"0X"$3,"0X"$4;}'" ; cmdfo = "<objdump -h ".exec." | awk '$1 ~ "^[0-9]+$" && $2 !~ ".gnu_debuglink" {print $1,"0X"$6;}'" ; cmdmaps = "<cat /proc/".pid."/maps | awk '{split($1,a,"-");b1=strtonum("0x"a[1]);b2=strtonum("0x"a[2]);printf("%d "%s" 0x%08X 0x%08Xn",NR,$6,b2-b1,b1);}'" print cmdvma print cmdfo print cmdmaps set format x "0x%08X" # "%016X"; set xtics rotate by -45 font ",7"; unset ytics unset colorbox set cbrange [0:25] set yrange [0.5:1.5] set macros set multiplot layout 3,1 columnsfirst # 0x08056000-0x08048000 = 0xe000 set xrange [0:0xe000] set tmargin at screen 1 set bmargin at screen 0.667+0.1 plot cmdfo using 4:(1+$0*0.01):4:($4+$3):0 with xerrorbars lc palette t "File off", cmdfo using 4:(1):2 with labels font ",6" left rotate by -45 t "" set xrange [0x08048000:0x08056000] set tmargin at screen 0.667 set bmargin at screen 0.333+0.1 plot cmdvma using 4:(1+$0*0.01):4:($4+$3):0 with xerrorbars lc palette t "VMA", cmdvma using 4:(1):2 with labels font ",6" left rotate by -45 t "" set tmargin at screen 0.333 set bmargin at screen 0+0.1 plot cmdmaps using 4:(1+$0*0.01):4:($4+$3):0 with xerrorbars lc palette t "/proc/pid/maps", cmdmaps using 4:(1):2 with labels font ",6" left rotate by -45 t "" unset multiplot #system("killall -9 " . pid) ; 解决方法
简短的回答是,可加载的段基于类型为PT_LOAD的ELF程序头被映射到内存中.
例如,在我的CentOS 6.4上: objdump -x `which tail` Program Header: LOAD off 0x00000000 vaddr 0x08048000 paddr 0x08048000 align 2**12 filesz 0x0000e4d4 memsz 0x0000e4d4 flags r-x LOAD off 0x0000e4d4 vaddr 0x080574d4 paddr 0x080574d4 align 2**12 filesz 0x000003b8 memsz 0x0000054c flags rw- 从/ proc / pid / maps: cat /proc/2671/maps | grep `which tail` 08048000-08057000 r-xp 00000000 fd:00 133669 /usr/bin/tail 08057000-08058000 rw-p 0000e000 fd:00 133669 /usr/bin/tail 你会注意到map和objdump对后续部分的加载地址所说的有区别,但这与加载器计算部分占用的内存量以及对齐字段有关.第一个可加载段映射到0x08048000,大小为0x0000e4d4,因此您希望它从0x08048000变为0x080564d4,但对齐表示在2 ^ 12字节页上对齐.如果你做数学运算,你最终得到0x8057000,匹配/ proc / pid / maps.所以第二个段映射到0x8057000并且大小为0x0000054c(结束于0x805754c),它与0x8058000对齐,匹配/ proc / pid / maps. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |