曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 8371|回复: 0
打印 上一主题 下一主题

GCC __attribute__ 和 link 脚本控制 section 基地址

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34387
跳转到指定楼层
楼主
发表于 2009-8-21 22:06:17 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
网上看的一篇文章,感谢作者,另外加上自己的一点注释。
... ... ... ... .... .... .....

利用 GCC 的 __attribute__ 属性的 section 选项来控制数据区的基地址。
以下例子,主要涉及到两个知识点,一个是 GNU C 扩展中的 attribute section 属性,关于这个知识点的相关信息可以参考:http://www.groad.net/bbs/read.php?tid=1035
另外一个知识点是 ld 连接器所用到的 link 脚本相关知识。

测试代码
#include <stdio.h>

int localmemory0 __attribute__((section("LOCALmem"))) = 0;
int localmemory1 __attribute__((section("LOCALmem"))) = 0;
int globalmemory __attribute__((section("GLOBALmem"))) = 0;

int main (int argc, char *argv[])
{
    localmemory0 = 0x456;
    localmemory1 = 0x123;

    globalmemory = localmemory0 + localmemory1;
}
在上面的代码中,定义了两个非传统的 section : LOCALmem 和 GLOBALmem 。
程序里要求变量 localmemory0 和 localmemory1 存放在 section LOCALmem 中,而 globalmemory 存放在 section GLOBALmem 中。

下面编译程序
beyes@linux-beyes:~/C/GNU_C_EXT> gcc -c -o elf_section.o elf_section.c
或者
beyes@linux-beyes:~/C/GNU_C_EXT> gcc -c -o elf_section2.o -fdata-sections elf_section.c
-fdata-sections 选项的目的是让编译器为每一个单独申明的数据 section 实际分配一个 section,而不是占用 .bss ,在某些系统上需要显式的使用这一参数。

使用 objdump 命令查看生成的 elf_section.o 文件
beyes@linux-beyes:~/C/GNU_C_EXT> objdump -S elf_section.o

elf_section.o:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
   0:    8d 4c 24 04              lea    0x4(%esp),%ecx
   4:    83 e4 f0                 and    $0xfffffff0,%esp
   7:    ff 71 fc                 pushl  -0x4(%ecx)
   a:    55                       push   %ebp
   b:    89 e5                    mov    %esp,%ebp
   d:    51                       push   %ecx
   e:    83 ec 04                 sub    $0x4,%esp
  11:    c7 05 00 00 00 00 56     movl   $0x456,0x0
  18:    04 00 00
  1b:    c7 05 00 00 00 00 23     movl   $0x123,0x0
  22:    01 00 00
  25:    a1 00 00 00 00           mov    0x0,%eax
  2a:    8b 15 00 00 00 00        mov    0x0,%edx
  30:    01 d0                    add    %edx,%eax
  32:    a3 00 00 00 00           mov    %eax,0x0
  37:    83 c4 04                 add    $0x4,%esp
  3a:    59                       pop    %ecx
  3b:    5d                       pop    %ebp
  3c:    8d 61 fc                 lea    -0x4(%ecx),%esp
  3f:    c3                       ret   
上面的 objdump 使用了 -S 选项,这是查看目标文件反汇编代码的一个选项;对此,也可以使用 -d 选项,并建议使用 -d 选项。
上面加蓝色高亮的两条 movl 指令分别将数据存放到 localmemory0 和 localmemroy1 ;加粉红色高亮的 mov 指令将两个变量相加的结构存放到 globalmemory 中。
由于是目标文件,变量符号对应的地址没有经过解析和分配,所以指令变量中对应的地址都是 0x0 。

下面,使用一个 link 脚本来控制连接器 ld 输出 section 的己地址(像linux的内核源码树中的 arch/arm/vmlinux-armv.lds.in 文件也是这样的脚本文件<这里是ARM平台,编译内核后的文件)。
文件内容如下:
SECTIONS
{
    .text : {
       
     *(.text)
      }

      LOCALmem 0x1f0000 : {
 
      *(LOCALmem)
      }

    GLOBALmem 0xff0000 : {
   
    *(GLOBALmem)
      }

}
用下面的命令观察生成的 elf 文件内容:
beyes@linux-beyes:~/C/GNU_C_EXT> objdump -S elf_section.elf

elf_section.elf:     file format elf32-i386


Disassembly of section .text:

00000000 <main>:
   0:    8d 4c 24 04              lea    0x4(%esp),%ecx
   4:    83 e4 f0                 and    $0xfffffff0,%esp
   7:    ff 71 fc                 pushl  -0x4(%ecx)
   a:    55                       push   %ebp
   b:    89 e5                    mov    %esp,%ebp
   d:    51                       push   %ecx
   e:    c7 05 00 00 1f 00 56     movl   $0x456,0x1f0000
  15:    04 00 00
  18:    c7 05 04 00 1f 00 23     movl   $0x123,0x1f0004
  1f:    01 00 00
  22:    8b 15 00 00 1f 00        mov    0x1f0000,%edx
  28:    a1 04 00 1f 00           mov    0x1f0004,%eax
  2d:    8d 04 02                 lea    (%edx,%eax,1),%eax
  30:    a3 00 00 ff 00           mov    %eax,0xff0000
  35:    b8 00 00 00 00           mov    $0x0,%eax
  3a:    59                       pop    %ecx
  3b:    5d                       pop    %ebp
  3c:    8d 61 fc                 lea    -0x4(%ecx),%esp
  3f:    c3                       ret   
说明
ld 命令的选项 -T ,等同于选项 -c ,这是告诉 ld 从 -c 后面的文件(commandfile) 中读取连接命令。这些命令彻底的覆盖 ld 的缺省连接格式 (不是添加);commandfile 必须详尽的描述目标格式的所有细节。
在两个加了蓝色高亮的语句中,可以看到,0x456 和 0x123 两数已经分别搬往 0x1f0000 与 0x1f0004 两个地址。

使用 objdump -s 来查看一下生成的 elf 文件:
beyes@linux-beyes:~/C/GNU_C_EXT> objdump -s elf_section.elf

elf_section.elf:     file format elf32-i386

Contents of section .text:
 0000 8d4c2404 83e4f0ff 71fc5589 e551c705  .L$.....q.U..Q..
 0010 00001f00 56040000 c7050400 1f002301  ....V.........#.
 0020 00008b15 00001f00 a104001f 008d0402  ................
 0030 a30000ff 00b80000 0000595d 8d61fcc3  ..........Y].a..
Contents of section LOCALmem:
 1f0000 00000000 00000000                    ........       
Contents of section GLOBALmem:
 ff0000 00000000                             ....           
Contents of section .comment:
 0000 00474343 3a202853 55534520 4c696e75  .GCC: (SUSE Linu
 0010 78292034 2e332e32 205b6763 632d345f  x) 4.3.2 [gcc-4_
 0020 332d6272 616e6368 20726576 6973696f  3-branch revisio
 0030 6e203134 31323931 5d00               n 141291].     
Contents of section .comment.SUSE.OPTs:
 0000 6f737077 6700                        ospwg.         
上面命令中, -s 选项表示显示任何一个 section 的所有内容。在默认情况下,所有非空 section 都要显示。

由上可见,section LOCALmem 从 0x1f0000 开始,而 section GLOBALmem 从 0xff0000 开始,程序正文段 .text 从 0x0 地址开始。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-19 14:05 , Processed in 0.063774 second(s), 22 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表