Chinaunix首页 | 论坛 | 博客
  • 博客访问: 59738
  • 博文数量: 15
  • 博客积分: 353
  • 博客等级: 一等列兵
  • 技术积分: 175
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-12 16:15
文章分类
文章存档

2011年(15)

我的朋友

分类: 嵌入式

2011-12-23 17:32:17

1.基本信息

需要在cpu-.c中填写bfd_arch_info结构,是目标CPU的基本参数。需要添加的信息如下:

类型

字段名

说明

int

bits_per_word;

字长

int

bits_per_address;

地址长

int

bits_per_byte;

字节长

enum bfd_architecture

arch

枚举类型bfd_architecture,该类型由archures.c自动生成。生成的符号形如bfd_arch_cr16

unsigned long

mach

型号(Machine value),用于区分CPU变种

const char

*arch_name;

体系(Architecture)名字的缩写

const char

*printable_name;

体系(Architecture)名字的全名

unsigned int

section_align_power;

节对齐指数(Section alignment power) i386,mcore是3,arm是4

bfd_boolean

the_default;

指出是否是该体系中的默认型号。如果是默认型号,应该处于链表的开头,以便通过*next访问其他型号。

const struct bfd_arch_info *

(*compatible)(…)

判断一个两个体系是否兼容,可以引用bfd_default_compatible(…)

bfd_boolean

(*scan) (…);

判断一个字符串是否属于该体系,可以引用bfd_default_scan (…)

const struct

bfd_arch_info *next;

若该文件内包含多个该结构定义,则在这里指出

基本信息

在`elfNN-CPU.c'中定义下列内容:

定义方法为使用宏定义,如#define XX 1

标识符

定义方法

TARGET_BIG_SYM

必须提供给目标向量(target vector)一个独一无二长度C语言名字。这个名字应该同样地出现在下列文件中:targets.c, config.bfd, configure.in.

TARGET_BIG_NAME

定义为目标向量所使用的名字。用户会通过该名字指定目标文件格式。链接器脚本中通常也会使用它。

TARGET_LITTLE_SYM

TARGET_LITTLE_NAME

ELF_ARCH

BFD体系(bfd_architecture'枚举类型,通常是bfd_arch_CPU)。

ELF_MACHINE_CODE

ELF头中的e_machine。

ELF_MAXPAGESIZE

定义为虚拟页的最大值。无内存管理硬件就设为1。

数据

 

GAS

GAS中读写目标文件的逻辑全部调用BFD来实现,而自身专注于汇编指令的处理上面。

BFD对GAS的要求,即BFD对输入数据的要求:

a.GAS产生新的重定位类型。

b.GAS调用bfd_install_relocation。

 

2) 类型常量

在bfd-in2.h中添加新的重定位类型,即一组枚举常量。由于是填入到已有的结构,只有保证形式一致即可。

 

3) 全局常量和宏定义

在include/elf目录新建CPU.h定义在BFD之外使用的新的类型。

尤其需要定义下列宏:

`START_RELOC_NUMBERS'

`RELOC_NUMBER'

`FAKE_RELOC'

`EMPTY_RELOC'

`END_RELOC_NUMBERS'

仿照同类定义即可。

 

结构

Howto结构保存重定位参数信息,供多个函数使用。

首先,在-.c中添加reloc_howto_struct结构的数组,数组的每一个元素包括下列信息:

注:假定只有RELA重定位。

类型

字段名

说明

unsigned int

type;

重定位类型内部标识

unsigned int

rightshift;

重定位结果右移。

int

size;

该值非一般观念上的大小。使用bfd_get_reloc_size来获取实际大小。

0->8

1->16

2->32

-2->32,relocation=-relocation

-1->16,relocation=-relocation

4->64

unsigned int

bitsize

重定位项的位数。溢出检查使用。

bfd_boolean

pc_relative

指出重定位是否相对于addend地址。

unsigned int

bitpos

重定位

enum complain_overflow

complain_on_overflow

需要检查的溢出错误类型

bfd_reloc_status_type

(*special_function) (…)

常规重定位之前调用

char*

name

重定位名字

bfd_boolean

partial_inplace

使用RELA应该设为FALSE。其他信息:

When performing a partial link(ld –r) relocation will be modified. Values of TRUE should be looked on with suspicion. For relocs that aren't used in partial links (e.g. GOT stuff) it doesn't matter what this is set to.

bfd_vma

src_mask

计算前掩码

bfd_vma

dst_mask

计算后掩码

bfd_boolean

pcrel_offset

PC相关的重定位

然后,实现下列函数:

函数名

输入

输出

实现提示

bfd_reloc_type_lookup

重定位类型枚举值

重定位信息结构

从前面定义的howto数组中查找对应项并返回

bfd_reloc_name_lookup

重定位类型名称

重定位信息结构

elf_info_to_howto

arelent结构

Rela结构

重定位信息结构

使用ELFNN_R_TYPE宏从输入获取重定位类型,再返回前面定义的对应的howto结构指针。

  5) 重定位功能检查

检查下列函数的代码,确保他们能正确利用howto结构的数据:

bfd_install_relocation

bfd_elf_generic_reloc

bfd_perform_relocation

elf_backend_relocate_section

_bfd_final_link_relocate

_bfd_relocate_contents

应该通过详细分析所以函数的代码,来确定每一个重定位是否都能够被正确处理。若分析代码量太大,可以结合输入输出测试来检查。最后,如果确定某(些)函数功能不完善的,需要在elf32-cpu.c中重写对应的函数。

重定位

elf_backend_relocate_section函数会被链接器调用,完成对所有的节的内容的重定位。

定义了该函数后,会自动把下列后端替换为ELF专用的默认函数:

接口

不定义elf_backend_relocate_section

定义elf_backend_relocate_section

bfd_elfNN_bfd_link_hash_table_create

_bfd_generic_link_hash_table_create

_bfd_elf_link_hash_table_create

bfd_elfNN_bfd_link_add_symbols

_bfd_generic_link_add_symbols

bfd_elf_link_add_symbols

bfd_elfNN_bfd_final_link

_bfd_generic_final_link

bfd_elf_final_link

值得注意的是,不定义elf_backend_relocate_section,链接器会调用bfd_perform_relocation完成同样的工作。但若不使用ELF专用函数,可能缺失部分ELF格式特有的信息。

函数名:elf_backend_relocate_section

输入:节内容,重定位、符号相关信息。

功能:重定位节内容。

输出:重定位过后的节内容,若可再重定位就还要包括重定位信息。

返回值:FALSE表示错误,RUE表示成功,2表示成功且重定位结果应该保存。

函数主流程:

for 每一个重定位 do

If 重定位类型是未知的 then 输出异常,continue

If 是本地重定位 then

计算重定位结果

else

对全局符号重定位(RELOC_FOR_GLOBAL_SYMBOL)

end

if 该节被移除 then continue

if 可再重定位 then continue

特殊重定位预处理

最终连接重定位(_bfd_final_link_relocate)

根据返回值生成异常信息

end

实现提示:

_perform_relocation是实现同样功能的最通用函数,只不过不处理ELF特有信息,可以参考。

  5. 链接时Relax

典型的relax场景为:一个指令集会有多个间接跳转指令,区别在于跳转的距离。如果不知道实际的跳转距离,则只能采用调整距离最大的那条跳转指令。如果在汇编链接时发现跳转距离不大,就可以relax为一条距离较近的跳转指令,这样性能和代码体积可以优化。在汇编阶段,重定位接口bfd_relocate_section中,在其中的final_link_relocate部分,增加修改指令(relax代码优化)的功能。

在GNU Linker中,链接时的relax实现方法为:

在bfd_relax_section接口中(调用链接器的时候添加-relax参数),循环遍历重定位项,对目标重定位类型,适当修改指令。由于修改指令一般需要改变大小,所以,每次修改指令,也需要遍历其他重定位项,修改他们的信息,同时将其他数据一并移动。算法复杂度接近O(n^2),并且数据移动的I/O操作也是极为耗时的。

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

上一篇:嵌入式CPU的工具链移植—BFD对重定位的处理

下一篇:没有了

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