Chinaunix首页 | 论坛 | 博客
  • 博客访问: 175336
  • 博文数量: 42
  • 博客积分: 2185
  • 博客等级: 大尉
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-11 21:32
文章分类

全部博文(42)

文章存档

2012年(5)

2011年(13)

2010年(6)

2009年(18)

我的朋友

分类: LINUX

2009-06-11 21:58:58

假定我们有一个如下的数据结构:

struct foo_s {
  char* name;
  char* name;
  int i1;
  int i2;
};

我们需要动态的增加一些struct foo_s的数据,比较直观的方法是我们可以做一组接口,如将上面的结构增加一个链接指针,通过结构动态的增加struct foo_s的数据。但有时候我们仅仅需要动态的增加一些struct foo_s的对象(实例),因此通过这种方式仍然不够灵活/方便。

通过使用ELF文件格式的特殊字段,我们可以采用如下方法:

#define foo_section __attribute__((unused,section(".foo_sect")))

#define MAKE_FOO_ENTRY(nam, typ, x, y) \
  struct foo_s __foo_s_##nam foo_section = { #name, #typ, x, y }

在代码的任何位置我们可以定义一个struct foo_s的对象,如:

MAKE_FOO_ENTRY("name1", "type1", 1, 2);
...
MAKE_FOO_ENTRY("name2", "type2", 3, 4);

这样所有的struct foo_s的对象都被放到了一个独立的ELF section,即.foo_sect。

到目前为止我们并不知道这些对象的具体地址,利用ld (gnu ld)的link script,我们可以这样做:

# foo.ld.S
...

. = .
__foo_start = .
.foo_sect : { *(.foo_sect) }
__foo_end = .

了解一点ld link script的应该很容易了解以上的代码的含义:
. = .  /* 其实没什么含义,不过在`.'可能没有对其的时候自动对其而已 */
__foo_start = . /* __foo_start = 当前linker的地址 */
.foo_sect : { *(.foo_sect) } /* 将所有文件(*)的.foo_sect字段都加入.foo_sect字段 */
__foo_end = . /* 同__foo_start */

这样结合ld script,通过引入两个变量__foo_start与__foo_end,我们可以很容易的找到所有struct foo_s的对象,如:

struct foo_s *p = (struct foo_s*)&__foo_start;
while(p!= (struct foo_s*)&__foo_end) {
  printf("name: %s, type: %s, i1: %d, i2: %d\n",
    p->name, p->type, p->i1, p->i2);
  ++p;
}

当然由于引入的link script,我们需要自己手动调用ld来链接我们的程序。

注意:
1) 我们并不需要写一个完整的foo.ld.S,通过调用
  ld --verbose
默认会生成一个ld.S模板,只需要增加上面我们提到的__foo_xxx相关内容即可,如:

...
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    KEEP (*(.gnu.linkonce.d.*personality*))
    SORT(CONSTRUCTORS)
  }

  . = .;
  __foo_s_start = .;
  .foo.sect : { *(.foo.sect) }
  __foo_s_end = .;

  .data1          : { *(.data1) }
  _edata = .;
  PROVIDE (edata = .);
  __bss_start = .;
...

2) 通过了ld链接我们需要指定使用这个foo.ld.S文件,而且链接需要不少crt??.o文件,这个我们可以通过编译一个hello.c文件:
  gcc -v hello.c -o hello
会自动输出相应的ld输出命令,如:

GNU C version 3.4.3 (i686-pc-linux-gnu)
        compiled by GNU C version 3.2.3 20030502 (Red Hat Linux 3.2.3-42).
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
 as -V -Qy -o /tmp/ccaGnvUs.o /tmp/cc8ZSw0M.s
GNU assembler version 2.15.92.0.2 (i386-redhat-linux) using BFD version 2.15.92.0.2 20040927
 /usr/i686-pc-linux-gnu/3.4.3/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o ex07 /usr/lib/crt1.o /usr/lib/crti.o /usr/i686-pc-linux-gnu/3.4.3/crtbegin.o -L/usr/i686-linux2.4/lib/gcc/i686-pc-linux-gnu/3.4.3 -L/usr/i686-linux2.4/lib/gcc/i686-pc-linux-gnu/3.4.3/../../.. /tmp/ccaGnvUs.o -lgcc -lc -lgcc /usr/i686-linux2.4/lib/gcc/i686-pc-linux-gnu/3.4.3/crtend.o /usr/lib/crtn.o

因此,我们可以写一个类似的Makefile:

all:
        /bin/rm -f foo foo.o
        gcc -c foo.c
        ld -dynamic-linker /lib/ld-linux.so.2 -o foo -T foo.ld.S /usr/lib/crt1.o /usr/lib/crti.o /usr/i686-pc-linux-gnu/3.4.3/crtbegin.o -L/usr/i686-linux2.4/lib/gcc/i686-pc-linux-gnu/3.4.3 -L/usr/i686-linux2.4/lib/gcc/i686-pc-linux-gnu/3.4.3/../../.. ex25.o -lgcc -lc  /usr/i686-linux2.4/lib/gcc/i686-pc-linux-gnu/3.4.3/crtend.o /usr/lib/crtn.o

通过readelf程序,我们可以看到section .foo_sect被正确创建:

readelf -S ./foo

  ...
  [23] .foo.sect         PROGBITS        0804967c 00067c 000040 00  WA  0   0  4
  ...



阅读(1171) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:qemu源代码分析 (一)

给主人留下些什么吧!~~