- 论坛徽章:
- 0
|
有关于上述几类的地址,最近有做学习和整理,基本上是明白其含义,但是还不够火候
在此一来作为学习的标记,二来还希望大家可以不吝赐教
下面篇幅有点长,内容有点杂乱,问题也有点小多;望各位耐心看完 :wink:
相关帖子,有看过一些。比如: http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=2083672
理解上
由于intel(32位)处理器的分段机制,因此有了 逻辑地址的概念,其组成是 段选择符(16位) + 段内偏移量(32位)。该逻辑地址由cpu的分段单元解析后,得到32位线性地址。
如果没有分页部件的存在,该线性地址就对应于物理地址
分页部件把该线性地址转化成物理地址。根据查找页表来进行转化
在微机原理书上有说明,对于32位微处理器,可以访问2^32字节的物理存储器,但它支持多任务时,每个任务又能得到最大为2^46字节
物理存储器对应于物理上的内存,是cpu可以访问的存储器空间
虚拟存储器是程序占有的空间,其容量由cpu的内部结构所决定
对于8086cpu来说,程序占有的虚拟存储器和cpu能访问的存储器是一致的,都是1M。(8086的地址总线是20位)
对于 32位的cpu来说,两者是不同的。cpu最大可以访问的存储器是 4G, 而对于存储在磁盘的程序而言,最大可以写 2^46字节的程序
对于以上的理解,有
问题一: 为何在支持多任务时候,每个任务会有2^46字节。同时逻辑地址到底是48位还是46位?
看起来说和 cpu的内部结构有关。对于这个 46字节,根据后续的介绍有: 14位的段选择符 + 32位的段内偏移
因为段选择符的最低两位是相关的权限标志位。不知以上理解是否正确
以上都是有关理论上的知识,有
问题二:对于逻辑地址,在哪可以比较直白的看到该地址的存在?或者说通过什么方式我们可以看到这 48/46位的逻辑地址
我们可以通过使用 readelf -S a.out(参考下面的问题三中的讨论)可以来查看程序的虚拟内存空间。理论上我们在此可以看到最大 2^46大小的虚拟内存空间。
我理解上,其中列出的就是虚拟地址,也就等同于上述所说的 逻辑地址的偏移量。
对于上述的逻辑地址,后来在翻书时候有注意到,对于汇编语言中的直接寻址方式。(以下是8086cpu,也就是20位地址总线,16位数据总线结构的)
比如 “ mov AX, [1070H]“ 该操作是将 DS段的 1070H和 1071H两单元的内容放置到 AX中。因为直接寻址的默认段寄存器是 DS
如果要指定其他段寄存器,应该指令前用前缀指定段寄存器名称,比如 ” CS:mov BX, [3000H]“
以上两个指令,假设 DS为2000H, CS为5100H
指令一就是将 21070H和 21071H两单元内容存放到 AX中(DS向左偏移4位后加上后续的偏移量组成)
指令二是将 54000H和 54001H两单元内容存放到 BX中
21070H是逻辑地址还是线性地址??
如果是逻辑地址,是否说在汇编语言中可以查看到 逻辑地址的踪迹?
对于 程序,参考某网络上相关程序内存布局的文章- #include <stdio.h>
- #include <stdlib.h>
- int global_init_a=1;
- int global_uninit_a;
- int main()
- {
- int local_init_a=1;
- int local_uninit_a;
- int * malloc_p_a;
- malloc_p_a=malloc(sizeof(int));
- printf("\n &global_init_a=%p \t "
- "global_init_a=%d\n",&global_init_a,global_init_a);
- printf(" &global_uninit_a=%p \t "
- "global_uninit_a=%d\n",&global_uninit_a,global_uninit_a);
- printf("\n &local_init_a=%p \t "
- "local_init_a=%d\n",&local_init_a,local_init_a);
- printf(" &local_uninit_a=%p \t "
- "local_uninit_a=%d\n",&local_uninit_a,local_uninit_a);
-
- printf(" malloc_p_a=%p \t "
- "*malloc_p_a=%d\n",malloc_p_a,*malloc_p_a);
-
- while(1);
- return 0;
- }
复制代码 运行结果:- [martin@stack]$ gcc process_mem.c
- [martin@stack]$ ./a.out &
- [1] 7418
- [martin@stack]$
- &global_init_a=0x804a024 global_init_a=1
- &global_uninit_a=0x804a02c global_uninit_a=0
- &local_init_a=0xbfb1f5a4 local_init_a=1
- &local_uninit_a=0xbfb1f5a8 local_uninit_a=134513931
- malloc_p_a=0x8758008 *malloc_p_a=0
- [martin@stack]$
复制代码 查看进程的maps- [martin@stack]$ sudo cat /proc/7418/maps
- 08048000-08049000 r-xp 00000000 08:08 1700899 /home/martin/debug/work/test/stack/a.out
- 08049000-0804a000 r--p 00000000 08:08 1700899 /home/martin/debug/work/test/stack/a.out
- 0804a000-0804b000 rw-p 00001000 08:08 1700899 /home/martin/debug/work/test/stack/a.out
- 08758000-08779000 rw-p 00000000 00:00 0 [heap]
- b7542000-b7543000 rw-p 00000000 00:00 0
- b7543000-b76ec000 r-xp 00000000 08:0a 1570780 /lib/i386-linux-gnu/libc-2.19.so
- b76ec000-b76ee000 r--p 001a9000 08:0a 1570780 /lib/i386-linux-gnu/libc-2.19.so
- b76ee000-b76ef000 rw-p 001ab000 08:0a 1570780 /lib/i386-linux-gnu/libc-2.19.so
- b76ef000-b76f2000 rw-p 00000000 00:00 0
- b7709000-b770c000 rw-p 00000000 00:00 0
- b770c000-b770d000 r-xp 00000000 00:00 0 [vdso]
- b770d000-b772d000 r-xp 00000000 08:0a 1570756 /lib/i386-linux-gnu/ld-2.19.so
- b772d000-b772e000 r--p 0001f000 08:0a 1570756 /lib/i386-linux-gnu/ld-2.19.so
- b772e000-b772f000 rw-p 00020000 08:0a 1570756 /lib/i386-linux-gnu/ld-2.19.so
- bfb00000-bfb21000 rw-p 00000000 00:00 0 [stack]
- [martin@stack]$
复制代码 使用 readelf查看 a.out程序的Stack- [martin@stack]$ readelf -S a.out
- There are 30 section headers, starting at offset 0x1154:
- Section Headers:
- [Nr] Name Type Addr Off Size ES Flg Lk Inf Al
- [ 0] NULL 00000000 000000 000000 00 0 0 0
- [ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
- [ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
- [ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
- [ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000020 04 A 5 0 4
- [ 5] .dynsym DYNSYM 080481cc 0001cc 000060 10 A 6 1 4
- [ 6] .dynstr STRTAB 0804822c 00022c 000053 00 A 0 0 1
- [ 7] .gnu.version VERSYM 08048280 000280 00000c 02 A 5 0 2
- [ 8] .gnu.version_r VERNEED 0804828c 00028c 000020 00 A 6 1 4
- [ 9] .rel.dyn REL 080482ac 0002ac 000008 08 A 5 0 4
- [10] .rel.plt REL 080482b4 0002b4 000020 08 A 5 12 4
- [11] .init PROGBITS 080482d4 0002d4 000023 00 AX 0 0 4
- [12] .plt PROGBITS 08048300 000300 000050 04 AX 0 0 16
- [13] .text PROGBITS 08048350 000350 000222 00 AX 0 0 16
- [14] .fini PROGBITS 08048574 000574 000014 00 AX 0 0 4
- [15] .rodata PROGBITS 08048588 000588 000123 00 A 0 0 4
- [16] .eh_frame_hdr PROGBITS 080486ac 0006ac 00002c 00 A 0 0 4
- [17] .eh_frame PROGBITS 080486d8 0006d8 0000ac 00 A 0 0 4
- [18] .init_array INIT_ARRAY 08049f08 000f08 000004 00 WA 0 0 4
- [19] .fini_array FINI_ARRAY 08049f0c 000f0c 000004 00 WA 0 0 4
- [20] .jcr PROGBITS 08049f10 000f10 000004 00 WA 0 0 4
- [21] .dynamic DYNAMIC 08049f14 000f14 0000e8 08 WA 6 0 4
- [22] .got PROGBITS 08049ffc 000ffc 000004 04 WA 0 0 4
- [23] .got.plt PROGBITS 0804a000 001000 00001c 04 WA 0 0 4
- [24] .data PROGBITS 0804a01c 00101c 00000c 00 WA 0 0 4
- [25] .bss NOBITS 0804a028 001028 000008 00 WA 0 0 4
- [26] .comment PROGBITS 00000000 001028 000024 01 MS 0 0 1
- [27] .shstrtab STRTAB 00000000 00104c 000106 00 0 0 1
- [28] .symtab SYMTAB 00000000 001604 000460 10 29 45 4
- [29] .strtab STRTAB 00000000 001a64 000288 00 0 0 1
- Key to Flags:
- W (write), A (alloc), X (execute), M (merge), S (strings)
- I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
- O (extra OS processing required) o (OS specific), p (processor specific)
- [martin@stack]$
复制代码 重点在于进程的 maps表,从 readelf可以看出,程序的 bss和 data数据段的虚拟地址是 0804a01c,这个应该是程序的虚拟内存空间。根据以上讨论,该虚拟内存空间可以大于 4G
该地址也可以在进程的maps中看到。
问题三:对于进程的 maps中,stack的地址 bfb00000应该是该进程占用的实际物理内存空间的物理地址,那为何还会有类似 08049000地址,这个不是程序的虚拟地址么?
这个有可能是针对 linux进程的内存管理方面的知识,不是特别清楚,所以也在此咨询下各位大婶 |
|