×
嵌入式 > 技术百科 > 详情

汇编技术内幕(6)

发布时间:2020-06-13 发布时间:
|
问题:全局变量和全局常量在进程地址空间的位置?

    显然,根据前面的叙述,全局变量在用户的数据段,那么全局常量呢,是数据段吗?
    同样的,可以利用mdb将test5进程挂起,然后用pmap命令求证一下:  
    # mdb test5        
    Loading modules: [ libc.so.1 ]
    > ::sysbp _exit         ; 在系统调用_exit处设置断点
    > :r                    ; 运行程序
    mdb: stop on entry to _exit
    mdb: target stopped at:
    libc.so.1`exit+0x2b:    jae     +0x15          
    >

    此时,程序运行后在_exit处挂起,可以利用pmap在另一个终端内查看test5进程的地址空间了:
    # ps -ef | grep test5
        root  1387  1386  0 02:23:53 pts/1    0:00 test5
        root  1399  1390  0 02:25:03 pts/3    0:00 grep test5
        root  1386  1338  0 02:23:41 pts/1    0:00 mdb test5
    # pmap -F 1387       ; 用pmap强制查看
    1387:   test5
    08044000      16K rwx--    [ stack ]         ; test5的stack
    08050000       4K r-x--  /export/home/asm/L3/test5         ; test5的代码段,起始地址为0x08050000
    08060000       4K rwx--  /export/home/asm/L3/test5         ; test5的数据段,起始地址为0x08060000
    DDAC0000     628K r-x--  /usr/lib/libc.so.1
    DDB6D000      24K rwx--  /usr/lib/libc.so.1
    DDB73000       4K rwx--  /usr/lib/libc.so.1
    DDB80000       4K r-x--  /usr/lib/libdl.so.1
    DDB90000     292K r-x--  /usr/lib/ld.so.1
    DDBE9000      16K rwx--  /usr/lib/ld.so.1
    DDBED000       8K rwx--  /usr/lib/ld.so.1
     total      1000K
    可以看到,由于test5程序没有使用malloc来申请内存,所以没有heap的映射
    前面用mdb观察过这些全局变量和常量的初始化值,它们的地址分别是:
    全局变量i,j,k:
        0x8060904起始的12字节            
    全局变量l,m,n:
        0x8060948起始的12字节
    全局常量o,p,q:      
        0x8050808起始的12字节
       显然,根据这些变量的地址,我们可以初步判断出这些变量属于哪个段:
    由于test5数据段起始地址为0x08060000,我们得出结论:全局变量i,j,k,l,m,n属于数据段
    而test5代码段的起始地址为0x08050000,我们得出结论:全局常量o,p,q属于代码段
    得出这个结论的确有点让人意外:全局常量竟然在代码段。
    却又似乎在情理之中:数据段内存映射后的属性是r/w/x,而常量要求是只读属性,所以在代码段(r-x)就合情合理了。

    问题:为什么这些全局变量地址不是连续的?
   
    很容易注意到,全局变量i,j,k和l,m,n以及全局常量o,p,q是连续声明的,但地址实际上并不连续,而是在3段连续12字节的地址上。
    当然,全局常量属于代码段,所以地址和全局变量是分开的;那么,为什么全局变量也并非连续呢?
       
    概念:ELF(Executable and Linking Format) 可执行连接格式

    ELF格式是UNIX系统实验室(USL)作为应用程序二进制接口(Application Binary Interface,ABI)而开发和发布的。
    目前,ELF格式是Unix/Linux平台上应用最广泛的二进制工业标准之一

    下图从不同视角给出了ELF文件的一般格式:

    Linking 视角                       Execution 视角
    ============                      ==============
    ELF header                        ELF header
    Program header table (optional)   Program header table
    Section 1                         Segment 1
    ...                               Segment 2
    Section n                         ...
    Section header table              Section header table (optional)

    图 3-2 ELF文件格式 摘自 EXECUTABLE AND LINKABLE FORMAT (ELF)

    可以根据test5 ELF文件的Program header table和Section header table中文件偏移量的信息描绘出test5的内容:

    entry name      起始文件偏移+实际大小=下个entry起始偏移
    -------------------------------------------------------
    ELF header                  0x0+0x34=0x34
    Program header              0x34+0xa0=0xd4
    Section 1  .interp          0xd4+0x11=0xe5
    000                         0xe5+0x3=0xe8
    Section 2  .hash            0xe8+0x104=0x1ec
    Section 3  .dynsym          0x1ec+0x200=0x3ec
    Section 4  .dynstr          0x3ec+0x11a=0x506
    00                          0x506+0x2=0x508
    Section 5  .SUNW_version    0x508+0x20=0x528
    Section 6  .rel.got         0x528+0x18=0x540
    Section 7  .rel.bss         0x540+0x8=0x548  
    Section 8  .rel.plt         0x548+0x38=0x580
    Section 9  .plt             0x580+0x80=0x600    
    Section 10 .text            0x600+0x1ec=0x7ec             
    Section 11 .init            0x7ec+0xd=0x7f9  
    Section 12 .fini            0x7f9+0x8=0x801
    000                         0x801+0x3=0x804
    Section 13 .rodata          0x804+0x10=0x814
    Section 14 .got             0x814+0x34=0x848
    Section 15 .dynamic         0x848+0xb8=900
    Section 16 .data            0x900+0x10=0x910
    Section 17 .ctors           0x910+0x8=0x918
    Section 18 .dtors           0x918+0x8=0x920
    Section 19 .eh_frame        0x920+0x4=0x924
    Section 20 .jcr             0x924+0x4=0x928
    Section 21 .data.rel.local  0x928+0x4=0x92c
    Section 22 .bss          0x92c+0x0=0x958
    Section 23 .symtab          0x92c+0x540=0xe6c
    Section 24 .strtab          0xe6c+0x20b=1077
    Section 25 .comment         0x1077+0x24d=0x12c4
    Section 26 .stab.index      0x12c4+0x24=0x12e8
    Section 27 .shstrtab        0x12e8+0xdc=0x13c4
    Section 28 .stab.indexstr   0x13c4+0x1c0=0x1584
    Section header table        0x1584+0x488=0x1a0c      ; 29x40=1160=0x488 这是根据Elf header的信息算得的
    ------------------------------------------------------
    图 3-3 test5的ELF文件格式

    # ls -al test5
    -rwxr-xr-x    1 root     other        6668 2004-12-19 06:56 test5

    可以看到test5的大小是0x1a0c字节,即6688字节。
    可以看到,.bss section用于保存未初始化的全局变量,因此不占据ELF文件空间;
    ELF文件装入时,会按照Section header table 22中的.bss的相关属性,为.bss映射相应大小的内存空间,并初始化为0


    ELF文件的Program header table描述了如何将ELF装入内存:
        Program Header 2 描述了用户代码段的起始地址和大小: 0x8050000+0x814=0x8050814
        Program Header 3 描述了用户数据段的起始地址和大小: 0x8060814+0x144=0x8060958

 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
FPGA及CPLD应用领域不断拓展