精华内容
下载资源
问答
  • 定位于重定位的概念定义 相机定位 相机定位(Camera Localization)是求解基于基本坐标系下的相机精确姿态的问题,这个基本坐标系可以是不断变化的,也可以是始终固定的。基本坐标不断变化时的任务,例如,求解相对...

    相机定位、相机重定位和视觉里程计的概念定义

    什么是相机定位?什么是相机重定位?什么是视觉里程计?

    相机定位

    相机定位(Camera Localization)是求解基于基本坐标系下的相机精确姿态的问题,这个基本坐标系可以是不断变化的,也可以是始终固定的。基本坐标不断变化时的任务,例如,求解相对位姿。基本坐标系始终固定的任务,例如,求解绝对相机位姿,在该任务中,这个基本坐标系称为世界坐标系。相机定位是一个笼统的概念,可以理解为具有求解6DoF位姿这一类任务的统称。

    相机重定位

    相机重定位(Camera Relocalization)是估计特定数据相对于已知场景的精确位置和方向的问题。相机重定位是相机定位的子问题,是场景已知的且基本坐标系始终固定的相机定位任务。相机重定位还可以划分为视觉相机重定位(或视觉重定位)、非视觉重定位等子问题。

    视觉里程计

    视觉里程计(Visual Odometry)是如何根据图像来估计相机运动。视觉里程计也是相机定位的子问题,是基于视觉信息的场景逐渐探索的且基本坐标系发生变化的相机定位任务。

    展开全文
  • 重定位

    2020-12-30 16:44:36
    重定位重定位是连接符号引用与符号定义的过程。例如,程序调用函数时,关联的调用指令必须在执行时将控制权转移到正确的目标地址。可重定位文件必须包含说明如何修改其节内容的信息。通过此信息,可执行文件和共享...

    重定位节

    重定位是连接符号引用与符号定义的过程。例如,程序调用函数时,关联的调用指令必须在执行时将控制权转移到正确的目标地址。可重定位文件必须包含说明如何修改其节内容的信息。通过此信息,可执行文件和共享目标文件可包含进程的程序映像的正确信息。重定位项即是这些数据。

    重定位项可具有以下结构。请参见 sys/elf.h。typedef struct {

    Elf32_Addr r_offset;

    Elf32_Word r_info;

    } Elf32_Rel;

    typedef struct {

    Elf32_Addr r_offset;

    Elf32_Word r_info;

    Elf32_Sword r_addend;

    } Elf32_Rela;

    typedef struct {

    Elf64_Addr r_offset;

    Elf64_Xword r_info;

    } Elf64_Rel;

    typedef struct {

    Elf64_Addr r_offset;

    Elf64_Xword r_info;

    Elf64_Sxword r_addend;

    } Elf64_Rela;r_offset

    此成员指定应用重定位操作的位置。不同的目标文件对于此成员的解释会稍有不同。

    对于可重定位文件,该值表示节偏移。重定位节说明如何修改文件中的其他节。重定位偏移会在第二节中指定一个存储单元。

    对于可执行文件或共享目标文件,该值表示受重定位影响的存储单元的虚拟地址。此信息使重定位项对于运行时链接程序更为有用。

    虽然为了使相关程序可以更有效地访问,不同目标文件的成员的解释会发生变化,但重定位类型的含义保持相同。

    r_info

    此成员指定必须对其进行重定位的符号表索引以及要应用的重定位类型。例如,调用指令的重定位项包含所调用的函数的符号表索引。如果索引是未定义的符号索引 STN_UNDEF,则重定位将使用零作为符号值。

    重定位类型特定于处理器。重定位项的重定位类型或符号表索引是将 ELF32_R_TYPE 或 ELF32_R_SYM 分别应用于项的 r_info 成员所得的结果。#define ELF32_R_SYM(info) ((info)>>8)

    #define ELF32_R_TYPE(info) ((unsigned char)(info))

    #define ELF32_R_INFO(sym, type) (((sym)<<8)+(unsigned char)(type))

    #define ELF64_R_SYM(info) ((info)>>32)

    #define ELF64_R_TYPE(info) ((Elf64_Word)(info))

    #define ELF64_R_INFO(sym, type) (((Elf64_Xword)(sym)<<32)+ \

    (Elf64_Xword)(type))

    对于 64 位 SPARC Elf64_Rela 结构,r_info 字段可进一步细分为 8 位类型标识符和 24 位类型相关数据字段。对于现有的重定位类型,数据字段为零。但是,新的重定位类型可能会使用数据位。#define ELF64_R_TYPE_DATA(info) (((Elf64_Xword)(info)<<32)>>40)

    #define ELF64_R_TYPE_ID(info) (((Elf64_Xword)(info)<<56)>>56)

    #define ELF64_R_TYPE_INFO(data, type) (((Elf64_Xword)(data)<<8)+ \

    (Elf64_Xword)(type))

    r_addend

    此成员指定常量加数,用于计算将存储在可重定位字段中的值。

    Rela 项包含显式加数。Rel 类型的项会在要修改的位置中存储一个隐式加数。32 位 SPARC 仅使用 Elf32_Rela 重定位项。64 位 SPARC 和 64

    位 x86 仅使用 Elf64_Rela 重定位项。因此,r_addend 成员用作重定位加数。x86 仅使用 Elf32_Rel 重定位项。要重定位的字段包含该加数。在所有情况下,加数和计算所得的结果使用相同的字节顺序。

    重定位节可以引用其他两个节:符号表(由 sh_link 节头项标识)和要修改的节(由 sh_info 节头项标识)。节中指定了这些关系。如果可重定位目标文件中存在重定位节,则需要 sh_info 项,但对于可执行文件和共享目标文件,该项是可选的。重定位偏移满足执行重定位的要求。

    在所有情况下,r_offset 值都会指定受影响存储单元的第一个字节的偏移或虚拟地址。重定位类型可指定要更改的位以及计算这些位的值的方法。

    重定位计算

    以下表示法用于说明重定位计算。A

    用于计算可重定位字段的值的加数。

    B

    执行过程中将共享目标文件装入内存的基本地址。通常,生成的共享目标文件的基本虚拟地址为 0。但是,共享目标文件的执行地址不相同。请参见程序头。

    G

    执行过程中,重定位项的符号地址所在的全局偏移表中的偏移。请参见全局偏移表(特定于处理器)。

    GOT

    全局偏移表的地址。请参见全局偏移表(特定于处理器)。

    L

    符号的过程链接表项的节偏移或地址。请参见过程链接表(特定于处理器)。

    P

    使用 r_offset 计算出的重定位的存储单元的节偏移或地址。

    S

    索引位于重定位项中的符号的值。

    Z

    索引位于重定位项中的符号的大小。

    SPARC: 重定位

    在 SPARC 平台上,重定位项适用于字节 (byte8)、半字 (half16)、字 (word32) 和扩展字 (xword64)。

    重定位字段 (disp19, disp22, disp30) 的 dispn 系列都是字对齐、带符号扩展的 PC 相对位移。全部将值编码为其最低有效位都位于字的位置 0,仅在分配给值的位数方面有所不同。

    d2/disp8 和 d2/disp14 变体使用两个非连续位字段 d2 和 dispn 对 16 位和 10 位位移值进行编码。

    重定位字段的 immn 系列(imm5、imm6、imm7、imm10、imm13 和 imm22)表示无符号整型常数。全部将值编码为其最低有效位都位于字的位置 0,仅在分配给值的位数方面有所不同。

    重定位字段的 simmn 系列(simm10、simm11、simm13 和 simm22)表示带符号的整型常数。全部将值编码为其最低有效位都位于字的位置 0,仅在分配给值的位数方面有所不同。

    SPARC: 重定位类型

    下表中的字段名称可确定重定位类型是否会检查 overflow。计算出的重定位值可以大于预期的字段,并且重定位类型可以验证 (V) 值是适合结果还是将结果截断 (T)。例如,V-simm13 表示计算出的值不能包含 simm13 字段外有意义的非零位。

    表 12-13 SPARC: ELF 重定位类型

    名称

    字段

    计算

    R_SPARC_NONE

    0

    R_SPARC_8

    1

    V-byte8

    S + A

    R_SPARC_16

    2

    V-half16

    S + A

    R_SPARC_32

    3

    V-word32

    S + A

    R_SPARC_DISP8

    4

    V-byte8

    S + A - P

    R_SPARC_DISP16

    5

    V-half16

    S + A - P

    R_SPARC_DISP32

    6

    V-disp32

    S + A - P

    R_SPARC_WDISP30

    7

    V-disp30

    (S + A - P) >> 2

    R_SPARC_WDISP22

    8

    V-disp22

    (S + A - P) >> 2

    R_SPARC_HI22

    9

    T-imm22

    (S + A) >> 10

    R_SPARC_22

    10

    V-imm22

    S + A

    R_SPARC_13

    11

    V-simm13

    S + A

    R_SPARC_LO10

    12

    T-simm13

    (S + A) & 0x3ff

    R_SPARC_GOT10

    13

    T-simm13

    G & 0x3ff

    R_SPARC_GOT13

    14

    V-simm13

    G

    R_SPARC_GOT22

    15

    T-simm22

    G >> 10

    R_SPARC_PC10

    16

    T-simm13

    (S + A - P) & 0x3ff

    R_SPARC_PC22

    17

    V-disp22

    (S + A - P) >> 10

    R_SPARC_WPLT30

    18

    V-disp30

    (L + A - P) >> 2

    R_SPARC_COPY

    19

    请参阅此表后面的说明。

    R_SPARC_GLOB_DAT

    20

    V-word32

    S + A

    R_SPARC_JMP_SLOT

    21

    请参阅此表后面的说明。

    R_SPARC_RELATIVE

    22

    V-word32

    B + A

    R_SPARC_UA32

    23

    V-word32

    S + A

    R_SPARC_PLT32

    24

    V-word32

    L + A

    R_SPARC_HIPLT22

    25

    T-imm22

    (L + A) >> 10

    R_SPARC_LOPLT10

    26

    T-simm13

    (L + A) & 0x3ff

    R_SPARC_PCPLT32

    27

    V-word32

    L + A - P

    R_SPARC_PCPLT22

    28

    V-disp22

    (L + A - P) >> 10

    R_SPARC_PCPLT10

    29

    V-simm13

    (L + A - P) & 0x3ff

    R_SPARC_10

    30

    V-simm10

    S + A

    R_SPARC_11

    31

    V-simm11

    S + A

    R_SPARC_HH22

    34

    V-imm22

    (S + A) >> 42

    R_SPARC_HM10

    35

    T-simm13

    ((S + A) >> 32) & 0x3ff

    R_SPARC_LM22

    36

    T-imm22

    (S + A) >> 10

    R_SPARC_PC_HH22

    37

    V-imm22

    (S + A - P) >> 42

    R_SPARC_PC_HM10

    38

    T-simm13

    ((S + A - P) >> 32) & 0x3ff

    R_SPARC_PC_LM22

    39

    T-imm22

    (S + A - P) >> 10

    R_SPARC_WDISP16

    40

    V-d2/disp14

    (S + A - P) >> 2

    R_SPARC_WDISP19

    41

    V-disp19

    (S + A - P) >> 2

    R_SPARC_7

    43

    V-imm7

    S + A

    R_SPARC_5

    44

    V-imm5

    S + A

    R_SPARC_6

    45

    V-imm6

    S + A

    R_SPARC_HIX22

    48

    V-imm22

    ((S + A) ^ 0xffffffffffffffff) >> 10

    R_SPARC_LOX10

    49

    T-simm13

    ((S + A) & 0x3ff) | 0x1c00

    R_SPARC_H44

    50

    V-imm22

    (S + A) >> 22

    R_SPARC_M44

    51

    T-imm10

    ((S + A) >> 12) & 0x3ff

    R_SPARC_L44

    52

    T-imm13

    (S + A) & 0xfff

    R_SPARC_REGISTER

    53

    V-word32

    S + A

    R_SPARC_UA16

    55

    V-half16

    S + A

    R_SPARC_GOTDATA_HIX22

    80

    V-imm22

    ((S + A - GOT) >> 10) ^ ((S + A - GOT) >> 31)

    R_SPARC_GOTDATA_LOX10

    81

    T-imm13

    ((S + A - GOT) & 0x3ff) | (((S + A - GOT) >> 31) & 0x1c00)

    R_SPARC_GOTDATA_OP_HIX22

    82

    T-imm22

    (G >> 10) ^ (G >> 31)

    R_SPARC_GOTDATA_OP_LOX10

    83

    T-imm13

    (G & 0x3ff) | ((G >> 31) & 0x1c00)

    R_SPARC_GOTDATA_OP

    84

    Word32

    请参阅此表后面的说明。

    R_SPARC_SIZE32

    86

    V-word32

    Z + A

    R_SPARC_WDISP10

    88

    V-d2/disp8

    (S + A - P) >> 2

    注 -其他重定位类型可用于线程局部存储引用。这些重定位类型将在第 14 章中介绍。

    一些重定位类型的语义不只是简单的计算:R_SPARC_GOT10

    与 R_SPARC_LO10 类似,不同的是此重定位指向符号的 GOT 项的地址。此外,R_SPARC_GOT10 还指示链接编辑器创建全局偏移表。

    R_SPARC_GOT13

    与 R_SPARC_13 类似,不同的是此重定位指向符号的 GOT 项的地址。此外,R_SPARC_GOT13 还指示链接编辑器创建全局偏移表。

    R_SPARC_GOT22

    与 R_SPARC_22 类似,不同的是此重定位指向符号的 GOT 项的地址。此外,R_SPARC_GOT22 还指示链接编辑器创建全局偏移表。

    R_SPARC_WPLT30

    与 R_SPARC_WDISP30 类似,不同的是此重定位指向符号的过程链接表项的地址。此外,R_SPARC_WPLT30 还指示链接编辑器创建过程链接表。

    R_SPARC_COPY

    由链接编辑器为动态可执行文件创建,用于保留只读文本段。此重定位偏移成员指向可写段中的位置。符号表索引指定应在当前目标文件和共享目标文件中同时存在的符号。执行过程中,运行时链接程序将与共享目标文件的符号关联的数据复制到偏移所指定的位置。请参见复制重定位。

    R_SPARC_GLOB_DAT

    与 R_SPARC_32 类似,不同的是此重定位会将 GOT 项设置为所指定符号的地址。使用特殊重定位类型,可以确定符号和 GOT 项之间的对应关系。

    R_SPARC_JMP_SLOT

    由链接编辑器为动态目标文件创建,用于提供延迟绑定。此重定位偏移成员可指定过程链接表项的位置。运行时链接程序会修改过程链接表项,以将控制权转移到指定的符号地址。

    R_SPARC_RELATIVE

    由链接编辑器为动态目标文件创建。此重定位偏移成员可指定共享目标文件中包含表示相对地址的值的位置。运行时链接程序通过将装入共享目标文件的虚拟地址与相对地址相加,计算对应的虚拟地址。此类型的重定位项必须为符号表索引指定值零。

    R_SPARC_UA32

    与 R_SPARC_32 类似,不同的是此重定位指向未对齐的字。必须将要重定位的字作为任意对齐的四个独立字节进行处理,而不是作为根据体系结构要求对齐的字进行处理。

    R_SPARC_LM22

    与 R_SPARC_HI22 类似,不同的是此重定位会进行截断而不是验证。

    R_SPARC_PC_LM22

    与 R_SPARC_PC22 类似,不同的是此重定位会进行截断而不是验证。

    R_SPARC_HIX22

    与 R_SPARC_LOX10 一起用于可执行文件,这些可执行文件在 64 位地址空间中的上限为 4 GB。与 R_SPARC_HI22 类似,但会提供链接值的补码。

    R_SPARC_LOX10

    与 R_SPARC_HIX22 一起使用。与 R_SPARC_LO10 类似,但始终设置链接值的位 10 到 12。

    R_SPARC_L44

    与 R_SPARC_H44 和 R_SPARC_M44 重定位类型一起使用,以生成 44 位的绝对寻址模型。

    R_SPARC_REGISTER

    用于初始化寄存器符号。此重定位偏移成员包含要初始化的寄存器编号。对于此寄存器必须存在对应的寄存器符号。该符号必须为 SHN_ABS 类型。

    R_SPARC_GOTDATA_OP_HIX22、R_SPARC_GOTDATA_OP_LOX10 和 R_SPARC_GOTDATA_OP

    这些重定位类型用于代码转换。

    64 位 SPARC: 重定位类型

    重定位计算中使用的以下表示法是特定于 64 位 SPARC 的。O

    用于计算重定位字段的值的辅助加数。此加数通过应用 ELF64_R_TYPE_DATA 宏从 r_info 字段中提取。

    下表中列出的重定位类型是扩展或修改针对 32 位 SPARC 定义的重定位类型所得的。请参见SPARC: 重定位类型。

    表 12-14 64 位 SPARC: ELF 重定位类型

    名称

    字段

    计算

    R_SPARC_HI22

    9

    V-imm22

    (S + A) >> 10

    R_SPARC_GLOB_DAT

    20

    V-xword64

    S + A

    R_SPARC_RELATIVE

    22

    V-xword64

    B + A

    R_SPARC_64

    32

    V-xword64

    S + A

    R_SPARC_OLO10

    33

    V-simm13

    ((S + A) & 0x3ff) + O

    R_SPARC_DISP64

    46

    V-xword64

    S + A - P

    R_SPARC_PLT64

    47

    V-xword64

    L + A

    R_SPARC_REGISTER

    53

    V-xword64

    S + A

    R_SPARC_UA64

    54

    V-xword64

    S + A

    R_SPARC_H34

    85

    V-imm22

    (S + A) >> 12

    R_SPARC_SIZE64

    87

    V-xword64

    Z + A

    以下重定位类型的语义不只是简单的计算:R_SPARC_OLO10

    与 R_SPARC_LO10 类似,不同的是会添加额外的偏移,以充分利用 13 位带符号的直接字段。

    x86: 重定位

    在 x86 上,重定位项应用于字 (word32) 和扩展字 (xword64)。

    word32 指定一个占用 4 个字节的 32 位字段,此字段以任意字节对齐。这些值使用与 x86 体系结构中的其他字值相同的字节顺序。

    32 位 x86: 重定位类型

    下表中列出的重定位类型是针对 32 位 x86 定义的。

    表 12-15 32 位 x86: ELF 重定位类型

    名称

    字段

    计算

    R_386_NONE

    0

    R_386_32

    1

    word32

    S + A

    R_386_PC32

    2

    word32

    S + A - P

    R_386_GOT32

    3

    word32

    G + A

    R_386_PLT32

    4

    word32

    L + A - P

    R_386_COPY

    5

    请参阅此表后面的说明。

    R_386_GLOB_DAT

    6

    word32

    S

    R_386_JMP_SLOT

    7

    word32

    S

    R_386_RELATIVE

    8

    word32

    B + A

    R_386_GOTOFF

    9

    word32

    S + A - GOT

    R_386_GOTPC

    10

    word32

    GOT + A - P

    R_386_32PLT

    11

    word32

    L + A

    R_386_16

    20

    word16

    S + A

    R_386_PC16

    21

    word16

    S + A - P

    R_386_8

    22

    word8

    S + A

    R_386_PC8

    23

    word8

    S + A - P

    R_386_SIZE32

    38

    word32

    Z + A

    注 -其他重定位类型可用于线程局部存储引用。这些重定位类型将在第 14 章中介绍。

    一些重定位类型的语义不只是简单的计算:R_386_GOT32

    计算 GOT 的基本地址与符号的 GOT 项之间的距离。此重定位还指示链接编辑器创建全局偏移表。

    R_386_PLT32

    计算符号的过程链接表项的地址,并指示链接编辑器创建一个过程链接表。

    R_386_COPY

    由链接编辑器为动态可执行文件创建,用于保留只读文本段。此重定位偏移成员指向可写段中的位置。符号表索引指定应在当前目标文件和共享目标文件中同时存在的符号。执行过程中,运行时链接程序将与共享目标文件的符号关联的数据复制到偏移所指定的位置。请参见复制重定位。

    R_386_GLOB_DAT

    用于将 GOT 项设置为所指定符号的地址。使用特殊重定位类型,可以确定符号和 GOT 项之间的对应关系。

    R_386_JMP_SLOT

    由链接编辑器为动态目标文件创建,用于提供延迟绑定。此重定位偏移成员可指定过程链接表项的位置。运行时链接程序会修改过程链接表项,以将控制权转移到指定的符号地址。

    R_386_RELATIVE

    由链接编辑器为动态目标文件创建。此重定位偏移成员可指定共享目标文件中包含表示相对地址的值的位置。运行时链接程序通过将装入共享目标文件的虚拟地址与相对地址相加,计算对应的虚拟地址。此类型的重定位项必须为符号表索引指定值零。

    R_386_GOTOFF

    计算符号的值与 GOT 的地址之间的差值。此重定位还指示链接编辑器创建全局偏移表。

    R_386_GOTPC

    与 R_386_PC32 类似,不同的是它在其计算中会使用 GOT 的地址。此重定位中引用的符号通常是 _GLOBAL_OFFSET_TABLE_,该符号还指示链接编辑器创建全局偏移表。

    x64: 重定位类型

    下表中列出的重定位是针对 x64 定义的。

    表 12-16 x64: ELF 重定位类型

    名称

    字段

    计算

    R_AMD64_NONE

    0

    R_AMD64_64

    1

    word64

    S + A

    R_AMD64_PC32

    2

    word32

    S + A - P

    R_AMD64_GOT32

    3

    word32

    G + A

    R_AMD64_PLT32

    4

    word32

    L + A - P

    R_AMD64_COPY

    5

    请参阅此表后面的说明。

    R_AMD64_GLOB_DAT

    6

    word64

    S

    R_AMD64_JUMP_SLOT

    7

    word64

    S

    R_AMD64_RELATIVE

    8

    word64

    B + A

    R_AMD64_GOTPCREL

    9

    word32

    G + GOT + A - P

    R_AMD64_32

    10

    word32

    S + A

    R_AMD64_32S

    11

    word32

    S + A

    R_AMD64_16

    12

    word16

    S + A

    R_AMD64_PC16

    13

    word16

    S + A - P

    R_AMD64_8

    14

    word8

    S + A

    R_AMD64_PC8

    15

    word8

    S + A - P

    R_AMD64_PC64

    24

    word64

    S + A - P

    R_AMD64_GOTOFF64

    25

    word64

    S + A - GOT

    R_AMD64_GOTPC32

    26

    word32

    GOT + A + P

    R_AMD64_SIZE32

    32

    word32

    Z + A

    R_AMD64_SIZE64

    33

    word64

    Z + A

    注 -其他重定位类型可用于线程局部存储引用。这些重定位类型将在第 14 章中介绍。

    大多数重定位类型的特殊语义与用于 x86 的语义相同。一些重定位类型的语义不只是简单的计算:R_AMD64_GOTPCREL

    此重定位类型具有与 R_AMD64_GOT32 或等效 R_386_GOTPC 重定位类型不同的语义。x64 体系结构提供了相对于指令指针的寻址模式。因此,可以使用单个指令从 GOT 装入地址。

    针对 R_AMD64_GOTPCREL 重定位类型进行的计算提供了 GOT 中指定了符号地址的位置与应用重定位的位置之间的差值。

    R_AMD64_32

    计算出的值会截断为 32 位。链接编辑器可验证为重定位生成的值是否会使用零扩展为初始的 64 位值。

    R_AMD64_32S

    计算出的值会截断为 32 位。链接编辑器可验证为重定位生成的值是否会使用符号扩展为初始的 64 位值。

    R_AMD64_8、R_AMD64_16、R_AMD64_PC16 和 R_AMD64_PC8

    这些重定位类型不适用于 x64 ABI,在此列出是为了说明。R_AMD64_8 重定位类型会将计算出的值截断为 8 位。R_AMD64_16 重定位类型会将所计算的值截断为 16 位。

    展开全文
  • 概述重定位操作是连接符号引用(symbolic references)和符号定义(symbolic definitions)的过程。例如,程序中调用一个(外部)函数,代码中我们只需要指定函数名(符号引用)即可,但是当程序实际运行的时候,相关的CALL...

    概述

    重定位操作是连接符号引用(symbolic references)和符号定义(symbolic definitions)的过程。例如,程序中调用一个(外部)函数,代码中我们只需要指定函数名(符号引用)即可,但是当程序实际运行的时候,相关的CALL指令必须能够正确无误地跳转到函数实际地址处(符号定义)去执行函数代码。可是在链接阶段之前,符号的虚拟地址(亦可称运行时地址)并没有分配,只有在链接阶段的符号解析过程中链接器才会为符号分配虚拟地址。在符号地址确认后,链接器这才会修改机器指令(即重定位操作是在符号解析之后),可是链接器并不会聪明到可以自动找到可重定位文件中引用外部符号的地方(即需要修改的地方),所以可重定位文件必须提供相应的信息来帮助链接器,换句话说,可重定位文件中必须包含相关的信息来告诉链接器如何去修改节的内容,只有这样,最后生成的可执行文件或者共享库才会包含正确的信息来构建最终的进程映像。可重定位项就是帮助链接器进行重定位操作的信息。

    重定位就是把符号引用与符号定义链接起来的过程,这也是 android linker 的主要工作之一。

    当程序中调用一个函数时,相关的 call 指令必须在执行期将控制流转到正确的目标地址。所以,so 文件中必须包含一些重定位相关的信息,linker 据此完成重定位的工作。

    链接时重定位

    在.o文件链接时将发生重定位

    这些重定位信息保存在一系列的重定位项中(.rel.dyn等表),重定位项的结构如下:

    typedef struct

    {

    Elf32_Addr r_offset; /* Address */

    Elf32_Word r_info; /* Relocation type and symbol index */

    } Elf32_Rel;

    typedef struct

    {

    Elf32_Addr r_offset; /* Address */

    Elf32_Word r_info; /* Relocation type and symbol index */

    Elf32_Sword r_addend; /* Addend */

    } Elf32_Rela;

    r_offset

    本数据成员给出重定位所作用的位置。对于重定位文件来说,此值是受重定位作用的存储单元在节中的字节偏移量;对于可执行文件或共享ELF文件来说,此值是受重定位作用的存储单元的虚拟地址。

    r_info

    本数据成员既给出了重定位所作用的符号表索引,也给出了重定位的类型。以下是应用于 r_info 的宏定义。

    #define ELF32_R_SYM(val) ((val) >> 8) //得到符号表的索引

    #define ELF32_R_TYPE(val) ((val) & 0xff) //得到type

    #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))

    r_addend

    本成员指定了一个加数,这个加数用于计算需要重定位的域的值。

    Elf32_Rela 与 Elf32_Rel 在结构上只有一处不同,就是前者有 r_addend。Elf32_Rela 中是用r_addend 显式地指出加数;而对 Elf32_Rel来说,加数是隐含在被修改的位置里的。Elf32_Rel中加数的形式这里并不定义,它可以依处理器架构(ELF32_R_TYPE(info))的不同而自行决定。

    计算方式

    计算方式是根据ELF32_R_TYPE宏定义得到类型决定的,我给出一些386架构的计算方式:

    被重定位域(relocatable field)是一个 32 位的域,占 4 字节并且地址向 4 字节对齐,其字节序与所在体系结构下其他双字长数据的字节序相同。重定位项用于描述如何修改如下的指令和数据域:

    2055bd794e58

    image.png

    为了下面的描述方便,这里定义以下几种运算符号:

    A 表示用于计算重定位域值的加数。

    B 表示在程序运行期,共享ELF被装入内存时的基地址。一般来说,共享ELF文件在构建时基地址为 0,但在运行时则不是。

    G 表示可重定位项在全局偏移量表中的位置,这里存储了此重定位项在运行期间的地址。更多信息参见下文“全局偏移量表”。

    -GOT 表示全局偏移量表的地址。

    L 表示一个符号的函数连接表项的所在之处,可能是节内偏移量,或者是内存地址。函数连接表项把函数调用定位到合适的位置。在构建期间,连接编辑器创建初始的函数连接表;在运行期间,动态连接器会修改表项。更多信息参见“函数连接表”部分。

    P 表示被重定位的存储单元在节内的偏移量或者内存地址,由 r_offset 计算得到。

    S 表示重定位项中某个索引值所代表的符号的值。

    重定位类型指定了哪些位需要被修改以及如何算计它们的值,下面使用x86系统处理器的重定位类型的计算方法说明。

    名字

    数据类型

    计算

    R_386_GOT32

    3

    word32

    G+A

    R_386_PLT32

    4

    word32

    L+A-P

    R_386_COPY

    5

    none

    none

    R_386_GLOB_DAT

    6

    word32

    S

    R_386_JMP_SLOT

    7

    word32

    S

    R_386_RELATIVE

    8

    word32

    B+A

    R_386_GOTOFF

    9

    word32

    S+A-GOT

    R_386_GOTPC

    10

    word32

    GOT+A-P

    编译链接

    编译器编译源代码后生成的文件叫做目标文件,从目标文件的结构上讲,它是已经编译后的可执行文件格式,只是还没有链接的过程,其中可能有些符号或有些地址还没有被调整。其实它本身就是按照可执行文件格式存储的,只是跟真正的可执行文件在结构上稍有不同。

    简单的说,目标文件就是源代码编译后但未进行链接的那些中间文件(Winodws的.obj和Linux下的.o) ,它跟可执行文件的内容结构很相似,所以一般跟可执行文件格式一起采用一种格式存储。从某种意义上,可以把目标文件和可执行文件看成是一种类型的文件。在Linux下,称之为ELF文件。

    libc简介

    在Linux中,常用的C语言库运行库glibc动态链接形式保存在"/lib"目录下,文件名叫做“libc.so”,整个系统只保留一份C语言库的动态链接文件“libc.so”,而所有的C语言编写的、动态链接的程序都可以在运行时使用它。

    当程序被装载时,系统的动态链接器 会将程序所需的动态链接库装载到进程的地址空间,并且将程序中所有未决议的符号绑定到相应的动态链接库中,并进行重定位工作。

    装载时重定位

    基本思路是:在链接时,对所有绝对地址的引用不作重定位,而把这一步推迟到装载时再完成。一旦模块装载地址确定,即目标地址确定,那么系统就对程序中所有的绝对地址引用进行重定位。

    假设函数foobar相对于代码段的起始地址是0x100,当模块被装载到0x10000000时,我们假设代码段位于模块的最开始,即代码段的装载地址也是0x10000000,那么我们就可以确定foobar的地位为0x1000100。这时候,系统遍历模块中的重定位表,把所有对foobar的地址引用都重定位至0x10000100。

    地址无关代码(PIC)

    装载时重定位解决了动态模块中有绝对地址引用的问题,但是又带了指令部分无法在多个进程间共享的问题。

    具体想法就是把程序模块中共享的指令部分在装载时不需要因为装载地址的改变而改变。把指令中那些需要被修改的部分分离出来,跟数据部分放在一起,这样指令部分就可以保持不变,而数据部分可以在每个进程中拥有一个副本。这种方案就是目前的地址无关代码(PIC)技术

    具体方法:先分析模块中各种类型的地址引用方式,把共享对象模块中地址引用按照是否跨模块分为两类:模块内部引用和模块外部引用。

    ;按照不同的引用方式又可以分为指令引用和数据访问。

    2055bd794e58

    image.png

    全局偏移表(GOT)

    对于类型三,我们需要用到代码地址无关(PIC)技术,基本的思想就是把跟地址相关部分放到数据段里面。

    ELF的做法是在数据段里建立一个指向这些变量的指针数据,称为全局偏移表(GOT),当代码需要引用该全局变量时,可以通过GOT中相对应的项间接引用。

    2055bd794e58

    image.png

    如图,当指令需要访问变量b时,程序先会找到GOT,然后根据GOT中的变量所对应的项找到变量的目标地址。

    由于GOT本身是放在数据段的,所以它可以在模块装载时被修改,并且每个进程都可以有独立的副本,相互不受影响。

    对于模块间调用和跳转,GOT中保存的是目标函数的地址,可以借助GOT中的项进行间接跳转。

    方法:先得到当前指令地址PC,然后加上一个偏移地址得到函数地址在GOT中的偏移,然后一个间接调用

    2055bd794e58

    image.png

    延迟绑定(PLT)

    基本思想

    动态链接以牺牲一部份性能为代价。PLT是另一种优化动态链接性能的方法。

    在动态链接下,程序模块之间包含了大量的函数引用,所以在程序开始执行前,会耗费不少时间解决函数引用的符号查找以及重定位。

    但是,在一个程序运行过程中,可能很多函数在程序执行完时都不会被用到,比如一些错误处理函数。

    所以ELF采用了一种叫做延迟绑定的做法。

    基本思想:就是当函数第一次被用到时才进行绑定。如果没有用则不进行绑定,所以在开始时模块间的函数调用都没有进行绑定,而是需要用到时才绑定。

    具体做法

    动态链接器需要某个函数来完成地址绑定工作,这个函数至少要知道这个地址绑定发生在哪个模块 哪个函数,如lookup(module,function)。

    在glibc中,lookup的函数真名叫做_dl_runtime_reolve()

    当我们调用某个外部模块时,调用函数并不直接通过GOT跳转,而是通过一个叫做PLT项的结构来进行跳转,每个外部函数在PLT中都有一个相应的项,比如bar()函数在PLT中的项地址叫做bar@plt,具体实现

    bar@plt:

    jmp *(bar@GOT)

    push n

    push moduleID

    jump _dl_runtime_resolve

    第一条指令是一条通过GOT间接跳转指令,bar@GOT表示GOT中保存bar()这个函数的相应项。

    但是为了实现延迟绑定,连接器在初始化阶段没有将bar()地址填入GOT,而是将“push n”的地址填入到bar@GOT中,所以第一条指令的效果是跳转到第二条指令,相当于没有进行任何操作。第二条指令将n压栈,接着将模块ID压栈,跳转到_dl_runtime_resolve。实际上就是lookup(module,function)的调用。

    _dl_runtime_resolve()在工作完成后将bar()真实地址填入bar@GOT中。

    一旦bar()解析完毕,再次调用bar@plt时,直接就能跳转到bar()的真实地址。

    实际实现

    PLT的真正实现要更复杂些,ELF将GOT拆分成两个表“.got”和".got.plt",前者用来保存全局变量引用的地址,后者用来保存函数引用的地址。

    也就是说,所有对于外部函数的引用被分离出来放到了“.got.plt”中

    最后在给出一些要用到一些表

    .rel.text

    重定位的地方在.text段内,以offset指定具体要定位位置。在连接时候由连接器完成。注意比较.text段前后变化。指的是比较.o文件和最终的执行文件(或者动态库文件)。就是重定位前后比较,以上是说明了具体比较对象而已。

    .rel.dyn

    重定位的地方在.got段内。主要是针对外部数据变量符号。例如全局数据。重定位在程序运行时定位,一般是在.init段内。定位过程:获得符号对应value后,根据rel.dyn表中对应的offset,修改.got表对应位置的value。另外,.rel.dyn 含义是指和dyn有关,一般是指在程序运行时候,动态加载。区别于rel.plt,rel.plt是指和plt相关,具体是指在某个函数被调用时候加载。

    .rel.plt

    重定位的地方在.got.plt段内(注意也是.got内,具体区分而已)。 主要是针对外部函数符号。一般是函数首次被调用时候重定位。可看汇编,理解其首次访问是如何重定位的,实际很简单,就是初次重定位函数地址,然后把最终函数地址放到.got.plt内,以后读取该.got.plt就直接得到最终函数地址(参考过程说明)。 所有外部函数调用都是经过一个对应桩函数,这些桩函数都在.plt段内。

    过程说明:调用对应桩函数--->桩函数取出.got表(具体是.got.plt)表内地址--->然后跳转到这个地址.如果是第一次,这个跳转地址默认是桩函数本身跳转处地址的下一个指令地址(目的是通过桩函数统一集中取地址和加载地址),后续接着把对应函数的真实地址加载进来放到.got.plt表对应处,同时跳转执行该地址指令.以后桩函数从.got.plt取得地址都是真实函数地址了。

    .plt段,存放重定位桩函数的。

    强调说明

    .rel.text属于普通重定位辅助段 ,他由编译器编译产生,存在于obj文件内。连接器连接时,他 用于最终可执行文件或者动态库的重定位。通过它修改原obj文件的.text段后,和并 到 最终可执行文件或者动态文件的.text段。

    注:readelf -r a.o 查看 .rel.text。其类型一般为R_386_32和R_386_PC32

    .rel.dyn和.rel.plt是动态定位辅助段。由连接器产生,存在于可执行文件或者动态库文件内。借助这两个辅助段可以动态修改对应.got和.got.plt段,从而实现运行时重定位。

    .rel.dyn 对应地点在.got表内;.rel.plt 在.got.plt,注意不是在.text,这点和普通不同,也是重要点。

    .rel.text由编译器产生,然后在连接时候,由链接器负责根据.rel.text对.text段进行修改,从而达到重定位目的;

    .rel.dyn和.rel.plt由连接器产生,然后在运行时候,动态加载符号地址。

    对于数据,根据.rel.dyn找到.got中的offset位置;

    对于函数则通过.plt桩函数和.rel.plt段来获取函数真实地址,然后存在于.got.plt。

    要理解动态连接中访问外部符号是通过.got和.got.plt

    展开全文
  • 重定位文件详解

    2021-03-26 20:41:22
    重定位文件是一个ELF格式的二进制文件,这里从ELF文件格式入手分析可重定位文件的结构。 生成可重定位文件 使用代码如下 #include<stdio.h> int main() { printf("hello world\n"); return 0; } ...

    目录

    生成可重定位文件

    可重定位文件分析

    解析文件头

    分析ELF文件各部分

    ELF header

    section header table 及 sections


     

    可重定位文件是一个ELF格式的二进制文件,这里从ELF文件格式入手分析可重定位文件的结构。

    生成可重定位文件

    使用代码如下

    #include<stdio.h>
    
    int main()
    {
        printf("hello world\n");
        return 0;
    }

    生成文件指令

    gcc -E hello.c -o hello.i
    gcc -S hello.i -o hello.s
    gcc -c hello.s -o hello.o

     

    可重定位文件分析

    解析文件头

    使用readelf命令查看构成

    $ readelf -h hello.o 
    ELF Header: 
      Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
      Class:                             ELF64 
      Data:                              2's complement, little endian 
      Version:                           1 (current) 
      OS/ABI:                            UNIX - System V 
      ABI Version:                       0 
      Type:                              REL (Relocatable file) 
      Machine:                           Advanced Micro Devices X86-64 
      Version:                           0x1 
      Entry point address:               0x0 
      Start of program headers:          0 (bytes into file) 
      Start of section headers:          792 (bytes into file) 
      Flags:                             0x0 
      Size of this header:               64 (bytes) 
      Size of program headers:           0 (bytes) 
      Number of program headers:         0 
      Size of section headers:           64 (bytes) 
      Number of section headers:         14 
      Section header string table index: 13

    关注如下字段:

    Type: REL (Relocatable file)

    说明 .o 文件的类型为可重定位文件

    Number of program headers: 0

    可以看出可重定位文件的 program header table 的长度为 0 。因为 program header table 保存的是 segment 信息,而 segment 是为了给加载器提供可执行程序在加载时所需的信息的,又因为可重定位文件本身并不能直接执行,因此在可重定位文件里不需要 program header table 。

    Entry point address: 0x0

    由于可重定位文件不能直接执行,因此入口地址为 0(默认值)。

    Start of section headers :

    从ELF文件起始地址偏移 792 个字节处是 section header table 的起始地址,section header table 中有 14 项,每项的大小为 64 byte

    Size of section headers: 64 (bytes)

    ELF文件头大小为 64 byte。

     

    分析ELF文件各部分

    可重定位文件属于二进制文件,在linux机器上可以使用 hexdump 命令来查看二进制文件的内容

    $ hexdump -C hello.o 
    00000000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00  |.ELF............| 
    00000010  01 00 3e 00 01 00 00 00  00 00 00 00 00 00 00 00  |..>.............| 
    00000020  00 00 00 00 00 00 00 00  18 03 00 00 00 00 00 00  |................| 
    00000030  00 00 00 00 40 00 00 00  00 00 40 00 0e 00 0d 00  |....@.....@.....| 
    00000040  f3 0f 1e fa 55 48 89 e5  48 8d 3d 00 00 00 00 e8  |....UH..H.=.....| 
    00000050  00 00 00 00 b8 00 00 00  00 5d c3 68 65 6c 6c 6f  |.........].hello| 
    00000060  20 77 6f 72 6c 64 00 00  47 43 43 3a 20 28 55 62  | world..GCC: (Ub| 
    00000070  75 6e 74 75 20 39 2e 33  2e 30 2d 31 37 75 62 75  |untu 9.3.0-17ubu| 
    00000080  6e 74 75 31 7e 32 30 2e  30 34 29 20 39 2e 33 2e  |ntu1~20.04) 9.3.| 
    00000090  30 00 00 00 00 00 00 00  04 00 00 00 10 00 00 00  |0...............| 
    000000a0  05 00 00 00 47 4e 55 00  02 00 00 c0 04 00 00 00  |....GNU.........| 
    000000b0  03 00 00 00 00 00 00 00  14 00 00 00 00 00 00 00  |................| 
    000000c0  01 7a 52 00 01 78 10 01  1b 0c 07 08 90 01 00 00  |.zR..x..........| 
    000000d0  1c 00 00 00 1c 00 00 00  00 00 00 00 1b 00 00 00  |................| 
    000000e0  00 45 0e 10 86 02 43 0d  06 52 0c 07 08 00 00 00  |.E....C..R......| 
    000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000100  00 00 00 00 00 00 00 00  01 00 00 00 04 00 f1 ff  |................| 
    00000110  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000120  00 00 00 00 03 00 01 00  00 00 00 00 00 00 00 00  |................| 
    00000130  00 00 00 00 00 00 00 00  00 00 00 00 03 00 03 00  |................| 
    00000140  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000150  00 00 00 00 03 00 04 00  00 00 00 00 00 00 00 00  |................| 
    00000160  00 00 00 00 00 00 00 00  00 00 00 00 03 00 05 00  |................| 
    00000170  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000180  00 00 00 00 03 00 07 00  00 00 00 00 00 00 00 00  |................| 
    00000190  00 00 00 00 00 00 00 00  00 00 00 00 03 00 08 00  |................| 
    000001a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    000001b0  00 00 00 00 03 00 09 00  00 00 00 00 00 00 00 00  |................| 
    000001c0  00 00 00 00 00 00 00 00  00 00 00 00 03 00 06 00  |................| 
    000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    000001e0  09 00 00 00 12 00 01 00  00 00 00 00 00 00 00 00  |................| 
    000001f0  1b 00 00 00 00 00 00 00  0e 00 00 00 10 00 00 00  |................| 
    00000200  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000210  24 00 00 00 10 00 00 00  00 00 00 00 00 00 00 00  |$...............| 
    00000220  00 00 00 00 00 00 00 00  00 68 65 6c 6c 6f 2e 63  |.........hello.c| 
    00000230  00 6d 61 69 6e 00 5f 47  4c 4f 42 41 4c 5f 4f 46  |.main._GLOBAL_OF| 
    00000240  46 53 45 54 5f 54 41 42  4c 45 5f 00 70 75 74 73  |FSET_TABLE_.puts| 
    00000250  00 00 00 00 00 00 00 00  0b 00 00 00 00 00 00 00  |................| 
    00000260  02 00 00 00 05 00 00 00  fc ff ff ff ff ff ff ff  |................| 
    00000270  10 00 00 00 00 00 00 00  04 00 00 00 0c 00 00 00  |................| 
    00000280  fc ff ff ff ff ff ff ff  20 00 00 00 00 00 00 00  |........ .......| 
    00000290  02 00 00 00 02 00 00 00  00 00 00 00 00 00 00 00  |................| 
    000002a0  00 2e 73 79 6d 74 61 62  00 2e 73 74 72 74 61 62  |..symtab..strtab| 
    000002b0  00 2e 73 68 73 74 72 74  61 62 00 2e 72 65 6c 61  |..shstrtab..rela| 
    000002c0  2e 74 65 78 74 00 2e 64  61 74 61 00 2e 62 73 73  |.text..data..bss| 
    000002d0  00 2e 72 6f 64 61 74 61  00 2e 63 6f 6d 6d 65 6e  |..rodata..commen| 
    000002e0  74 00 2e 6e 6f 74 65 2e  47 4e 55 2d 73 74 61 63  |t..note.GNU-stac| 
    000002f0  6b 00 2e 6e 6f 74 65 2e  67 6e 75 2e 70 72 6f 70  |k..note.gnu.prop| 
    00000300  65 72 74 79 00 2e 72 65  6c 61 2e 65 68 5f 66 72  |erty..rela.eh_fr| 
    00000310  61 6d 65 00 00 00 00 00  00 00 00 00 00 00 00 00  |ame.............| 
    00000320  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    * 
    00000350  00 00 00 00 00 00 00 00  20 00 00 00 01 00 00 00  |........ .......| 
    00000360  06 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000370  40 00 00 00 00 00 00 00  1b 00 00 00 00 00 00 00  |@...............| 
    00000380  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    00000390  00 00 00 00 00 00 00 00  1b 00 00 00 04 00 00 00  |................| 
    000003a0  40 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |@...............| 
    000003b0  58 02 00 00 00 00 00 00  30 00 00 00 00 00 00 00  |X.......0.......| 
    000003c0  0b 00 00 00 01 00 00 00  08 00 00 00 00 00 00 00  |................| 
    000003d0  18 00 00 00 00 00 00 00  26 00 00 00 01 00 00 00  |........&.......| 
    000003e0  03 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    000003f0  5b 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |[...............| 
    00000400  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    00000410  00 00 00 00 00 00 00 00  2c 00 00 00 08 00 00 00  |........,.......| 
    00000420  03 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000430  5b 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |[...............| 
    00000440  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    00000450  00 00 00 00 00 00 00 00  31 00 00 00 01 00 00 00  |........1.......| 
    00000460  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000470  5b 00 00 00 00 00 00 00  0c 00 00 00 00 00 00 00  |[...............| 
    00000480  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    00000490  00 00 00 00 00 00 00 00  39 00 00 00 01 00 00 00  |........9.......| 
    000004a0  30 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |0...............| 
    000004b0  67 00 00 00 00 00 00 00  2b 00 00 00 00 00 00 00  |g.......+.......| 
    000004c0  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    000004d0  01 00 00 00 00 00 00 00  42 00 00 00 01 00 00 00  |........B.......| 
    000004e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    000004f0  92 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000500  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    00000510  00 00 00 00 00 00 00 00  52 00 00 00 07 00 00 00  |........R.......| 
    00000520  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000530  98 00 00 00 00 00 00 00  20 00 00 00 00 00 00 00  |........ .......| 
    00000540  00 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  |................| 
    00000550  00 00 00 00 00 00 00 00  6a 00 00 00 01 00 00 00  |........j.......| 
    00000560  02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000570  b8 00 00 00 00 00 00 00  38 00 00 00 00 00 00 00  |........8.......| 
    00000580  00 00 00 00 00 00 00 00  08 00 00 00 00 00 00 00  |................| 
    00000590  00 00 00 00 00 00 00 00  65 00 00 00 04 00 00 00  |........e.......| 
    000005a0  40 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |@...............| 
    000005b0  88 02 00 00 00 00 00 00  18 00 00 00 00 00 00 00  |................| 
    000005c0  0b 00 00 00 09 00 00 00  08 00 00 00 00 00 00 00  |................| 
    000005d0  18 00 00 00 00 00 00 00  01 00 00 00 02 00 00 00  |................| 
    000005e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    000005f0  f0 00 00 00 00 00 00 00  38 01 00 00 00 00 00 00  |........8.......| 
    00000600  0c 00 00 00 0a 00 00 00  08 00 00 00 00 00 00 00  |................| 
    00000610  18 00 00 00 00 00 00 00  09 00 00 00 03 00 00 00  |................| 
    00000620  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000630  28 02 00 00 00 00 00 00  29 00 00 00 00 00 00 00  |(.......).......| 
    00000640  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    00000650  00 00 00 00 00 00 00 00  11 00 00 00 03 00 00 00  |................| 
    00000660  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 
    00000670  a0 02 00 00 00 00 00 00  74 00 00 00 00 00 00 00  |........t.......| 
    00000680  00 00 00 00 00 00 00 00  01 00 00 00 00 00 00 00  |................| 
    * 
    00000698

    上述就是 hello.o 文件的实际内容

    NOTE:

    1. 最前面一列是 hexdump 命令添加的,并非 ELF 文件的内容。它是一个十六进制的数字,表示字节序号。如 00000040 f3 0f 1e fa 55 48 89 e5 ,其中 00000040,即 0x40,十进制为64表示hello.o文件的第64个字节为 'f3'
    2. 最后一部分由两个 '|' 包含的数字和字符也是hexdump命令添加的,它将其左侧的十六进制数字转化成了对应的ASCII字符,所有的控制字符表示为 '.',所有的可显示字符表示为对应的字符或图形。

    ELF header

    根据ELF文件的结构,ELF文件最开始的部分是ELF header,它是一个64字节大小的结构体,也就是对应了hello.o的前64个字符,即从0000000 - 00000040的部分。前十六个字节应该是对应其magic number的部分。我们注意到,从0000000 - 0000000F正好就是使用readelf读出来的magic的值。剩下的部分只要结合struct ElfN_Ehdr的成员信息和hexdump命令输出的内容即可一一验证。

    section header table 及 sections

    由于不存在 program header table,ELF header 后就是 section。使用下述命令查看 section header table

    $ readelf -S hello.o 
    There are 14 section headers, starting at offset 0x318: 
     
    Section Headers: 
      [Nr] Name              Type             Address           Offset 
           Size              EntSize          Flags  Link  Info  Align 
      [ 0]                   NULL             0000000000000000  00000000 
           0000000000000000  0000000000000000           0     0     0 
      [ 1] .text             PROGBITS         0000000000000000  00000040 
           000000000000001b  0000000000000000  AX       0     0     1 
      [ 2] .rela.text        RELA             0000000000000000  00000258 
           0000000000000030  0000000000000018   I      11     1     8 
      [ 3] .data             PROGBITS         0000000000000000  0000005b 
           0000000000000000  0000000000000000  WA       0     0     1 
      [ 4] .bss              NOBITS           0000000000000000  0000005b 
           0000000000000000  0000000000000000  WA       0     0     1 
      [ 5] .rodata           PROGBITS         0000000000000000  0000005b 
           000000000000000c  0000000000000000   A       0     0     1 
      [ 6] .comment          PROGBITS         0000000000000000  00000067 
           000000000000002b  0000000000000001  MS       0     0     1 
      [ 7] .note.GNU-stack   PROGBITS         0000000000000000  00000092 
           0000000000000000  0000000000000000           0     0     1 
      [ 8] .note.gnu.propert NOTE             0000000000000000  00000098 
           0000000000000020  0000000000000000   A       0     0     8 
      [ 9] .eh_frame         PROGBITS         0000000000000000  000000b8 
           0000000000000038  0000000000000000   A       0     0     8 
      [10] .rela.eh_frame    RELA             0000000000000000  00000288 
           0000000000000018  0000000000000018   I      11     9     8 
      [11] .symtab           SYMTAB           0000000000000000  000000f0 
           0000000000000138  0000000000000018          12    10     8 
      [12] .strtab           STRTAB           0000000000000000  00000228 
           0000000000000029  0000000000000000           0     0     1 
      [13] .shstrtab         STRTAB           0000000000000000  000002a0 
           0000000000000074  0000000000000000           0     0     1 
    Key to Flags: 
      W (write), A (alloc), X (execute), M (merge), S (strings), I (info), 
      L (link order), O (extra OS processing required), G (group), T (TLS), 
      C (compressed), x (unknown), o (OS specific), E (exclude), 
      l (large), p (processor specific)

    计算 section 的分布方法如下

    .text 偏移为0x40,即在ELF Header之后第一个 section,然后下一个是 0x40 + 0x1b = 0x5b

    找到为 .data,以后计算类似

    通过上面的方法,就可以推断出各个 section 的顺序。

    各个 section 的详细内容如下:

    • .text段保存了可执行代码经过汇编之后的内容;
    • .data和.bss并没有占据任何空间,原因是代码中并未定义局部变量或者全局变量;
    • .rodata的起始地址是0x5b,占据0xc个字节的空间,根据hexdump命令输出的信息,其内容应该是:c3 68 65 6c 6c 6f 20 77 6f 72 6c 64,根据ASCII表,其对应的字符为:h e l l o , w o r l d NULL。正好就是我们的C代码中唯一的一个需要保存到 .rodata 段的字符串常量”hello, world”;

     

    .commont的起始地址是0x67,大小为0x2b byte,将hexdump内容截取出来,并转化成ASCII字符为:GCC: (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0,可以看出正好就是我们在前面介绍开发环境的时候使用的GCC版本信息;

    • .strtab指的是string table,起始地址是0x228,大小为0x29 byte,将hexdump内容截取出来,并转化成ASCII字符为:hello.c .main._GLOBAL_OFFSET_TABLE_.puts,可见其中保存了原C文件中的文件名和函数名等信息;

    • .shstrtab指的是 section header string table,经过同上分析,其中保存了各个section的名字;
    • .symtab保存了符号表,其中包括了.strtab里面定义的三个符号;每个符号对应的符号表是一个Elf64_Symbol结构体。除了包含.strtab外,符号表中还包含了一些section的符号表条目,这些条目给链接的时候需要和其他可重定位文件或者库的对应的section合并时提供了必要的信息。在上述例子中,其.symtab的内容如下:
    $ readelf -s hello.o 
     
    Symbol table '.symtab' contains 13 entries: 
       Num:    Value          Size Type    Bind   Vis      Ndx Name 
         0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS hello.c 
         2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
         3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
         4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
         5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
         6: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
         7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
         8: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 
         9: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
        10: 0000000000000000    27 FUNC    GLOBAL DEFAULT    1 main 
        11: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_ 
        12: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND puts
    • .eh_frame:其内部存放了以DWARF格式保存的一些调试信息。
    • .rel.text:包含了代码段中引用的外部函数和全局变量的重定位条目。上述hello.o文件中我们得到它的.rel.text的内容包括:
    $ readelf -r hello.o 
     
    Relocation section '.rela.text' at offset 0x258 contains 2 entries: 
      Offset          Info           Type           Sym. Value    Sym. Name + Addend 
    00000000000b  000500000002 R_X86_64_PC32     0000000000000000 .rodata - 4 
    000000000010  000c00000004 R_X86_64_PLT32    0000000000000000 puts - 4
    • .rela.eh_frame:这个section同.rel.text一样属于重定位信息的section,只不过它包含的是eh_frame的重定位信息,内容如下
    $ readelf -r hello.o 
     
    Relocation section '.rela.text' at offset 0x258 contains 2 entries: 
      Offset          Info           Type           Sym. Value    Sym. Name + Addend 
    00000000000b  000500000002 R_X86_64_PC32     0000000000000000 .rodata - 4 
    000000000010  000c00000004 R_X86_64_PLT32    0000000000000000 puts - 4 
     
    Relocation section '.rela.eh_frame' at offset 0x288 contains 1 entry: 
      Offset          Info           Type           Sym. Value    Sym. Name + Addend 
    000000000020  000200000002 R_X86_64_PC32     0000000000000000 .text + 0

     

    展开全文
  • ELF重定位

    2021-10-30 16:36:35
    重定位技术实际上是给二进制打补丁的机制,如果使用了动态连接器,可以使用重定位在内存打热补丁。 ELF重定位重定位技术实际上是给二进制打补丁的机制,如果使用了动态连接器,可以使用重定位在内存打热补丁。...
  • 重定位表结构解析

    2021-10-24 11:47:28
    目录预备知识一、相关实验实验目的实验环境实验步骤一实验步骤二实验步骤三 预备知识 一、相关实验 本实验要求您已经认真学习和完成了《IMAGE_DOS_HEADER解析》、《PE头之IMAGE_FILE_...2)了解PE文件的重定位表结构
  • 一种特殊类型的可重定位目标文件,可以在加载或者运行 时被动态的加载进内存并链接。 3.使用多个源码的项目 比如有两个源程序main.c和sum.c 使用gcc编译器并链接生成可执行程序p:gcc -O2 -g -o p main.c sum.c ./p -...
  • 发生太多重定位怎么办

    千次阅读 2020-12-19 16:29:07
    发生太多重定位出现Safari,是因为网络设置不稳定,在设置中进行网络还原即可。Safari是苹果计算机的操作系统macOS中的浏览器,使用了KDE的KHTML作为浏览器的运算核心。Safari 是一款浏览器、一个平台,也是对锐意...
  • 因为发生太多重定位

    千次阅读 2020-12-19 16:28:18
    Safari浏览器下提示打不开该网页,因为发生了太多重定位,可能是因为正尝试查看的网站所致。当网站的重定位问题解决后,Safari可能会在此后打开此网站。如果重定位信息不再需要后已进行缓存,也可能会发生此问题。...
  • 一文详解回环检测与重定位

    千次阅读 2021-03-07 00:22:23
    标题:VINS-Mono代码解读—回环检测与重定位 pose graph loop closing作者:Manii来源:https://blog.csdn.net/qq_41839222/...
  • 2、何为符号解析和符号重定位?在链接中,将函数和变量统称为符号。函数名或变量名称为符号名。链接过程中很关键的一部分就是符号的管理,每一个目标文件都会有一个相应的符号表,这个表里记录了目标文件中所用到的...
  • Relocatable object file(可重定位的对象文件). Contains binary code and data in a form that can be combined with other relocatable object files at compile time to create an executable object file. ...
  • •包含重定位信息(指出哪些符号引用处需要重定位) •文件扩展名为.o(相当于Windows中的.obj文件) 我们都知道可重定位目标文件都是用来进行链接生成可执行目标文件的,那么下面我们来看下相应的链接试图
  • 链接器——重定位

    2020-12-28 22:27:08
    链接器通过把每个符号定义与一个内存位置关联起来,从而重定位这些节,然后修改所有对这些符号的引用,使得它们指向这个这个内存位置。 重定位条目:当汇编器生成一个目标模块时,它并不知道数据和代码最终将放在...
  • elf可重定位记录

    2021-06-05 00:54:16
    相关概念:重定位条目:当汇编器生成一个目标模块时,它并不知道数据和代码最终将存放在存储器中的什么位置。它也不知道这个模块引用的任何外部定义的函数和全局变量。所以,无论何时汇编器遇到对最终位置未指定目标...
  • C模拟页式地址重定位

    2020-12-23 21:58:04
    库导入和宏定义 #include <stdio.h> #include <stdlib.h> #include <time.h> #define u32 int #define u8 char #define f32 float 创建进程结构体存放进程的大小以及进程的页数和...
  • 程序重定位 运行时重定位 在编译形成可执行程序时,用到的地址都是从 0 开始的相对地址,这个地址通常被称作逻辑地址,当程序被载入到物理内存中时,可能使用任意一段空闲物理内存 此时为保证程序的顺利执行,就...
  • 1、为什么需要重定位 因为特殊情况这块地址不给用了你要挪到另外一个地方,你本来是在哪里的挪到另外一个地方你还是在哪里 如下图所示: 小明在教室A是第一排,搬到教室B小明还是第一排 2、待修复数据如下: ...
  • //定义个容器来装 pnp求解的结果 vector*> vpPnPsolvers; //给求解器容器大小与候选帧数量相同 vpPnPsolvers.resize(nKFs); //每个候选关键帧与当前帧的匹配关系 vector*> > vvpMapPointMatches; ...
  • //定义一个数组haveBeenUsedMemoryBlockNum,用来存储已经分配出去的内存块号,这样就可以在后面的随机分配内存块号时,把已经分配的内存块剔除出去 //每分配出去一个内存块,就把块号存储到...
  • 符号解析与重定位

    2021-06-16 11:04:58
    重定位 //a.c extern int shared; int main() { int a = 100; swap(&a, &shared); } //b.c int shared = 1; void swap(int* a, int* b) { *a ^= *b ^= *a ^= *b; } 将"a.c"和"b.c"分别编译成目标文件...
  • 代码重定位

    2021-06-02 15:08:59
    1.段的概念以及重定位的引入 首先看下面的图: 我们知道,CPU可以直接访问SDRAM,NOR,SRAM(片内4k内存)以及NOR FLASH控制器,而不能直接访问NAND,但是我们为什么又可以烧写bin文件到nand上呢? 下面来分析Nand,...
  • 我们继续来讲解链接器的重定位。 程序的运行过程就是CPU不断的从内存中取出指令然后执行执行的过程,对于函数调用来说比如我们在C/C++语言中调用简单的加法函数add,其对应的汇编指令可能是这样的: call 0x4004fd ...
  • u-boot的编译选项 笔者一直认为由-fPIC和-fPIE参数编译生成的目标文件,链接成动态库或可执行文件后,在运行时可动态重定位,从而实现了“位置无关地执行”,即Position Independent Execute。不过笔者犯了经验...
  • 13_代码重定位

    2021-01-30 18:23:03
    文章目录13_代码重定位1、段的概念2、链接脚本2.1、链接脚本编写2.2、重定位过程2.3、程序分析3、C语言写重定位代码3.1、汇编写3.2、C语言写3.3、C语言、汇编代码分析3.4、C代码如何使用链接脚本中定义的变量 ...
  • ET_REL:重定位文件。通常是还未被链接到可执行程序中的一段位置独立的代码,例如linux中的.o格式的文件。 ET_EXEC:可执行文件。 ET_DYN:共享目标文件。ELF类型为dynamic,意味着该文件被标记为了一个动态的可连接...
  • 任务动机:根和据暴露的问题,视觉重定位模块更新了第二个版本。与之前相比主要有如下改进:1. 使用两种定位模式(基于地图和基于BOW)实现稳定定位; 2. 定位频率保持5Hz左右; 3. 只需要激光板回传优化后的低频轨迹...
  • 我正在调查共享库的重定位,并遇到了一些奇怪的问题.考虑以下代码:int myglob;int ml_util_func(int p){return p + 2;}int ml_func2(int a, int b){int c = ml_util_func(a);return c + b + myglob;}我用gcc -shared...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 174,071
精华内容 69,628
关键字:

动态重定位的定义