use object::read::{Object, ObjectSection};
use object::{elf, macho, pe, xcoff};
use object::{read, write};
use object::{
Architecture, BinaryFormat, Endianness, RelocationEncoding, RelocationFlags, RelocationKind,
SymbolFlags, SymbolKind, SymbolScope,
};
fn check_reloc(
format: BinaryFormat,
arch: Architecture,
kind: RelocationKind,
encoding: RelocationEncoding,
size: u8,
expected: RelocationFlags,
canonical: bool,
) {
let endian = match arch {
Architecture::PowerPc | Architecture::PowerPc64 => Endianness::Big,
_ => Endianness::Little,
};
let mut object = write::Object::new(format, arch, endian);
let section = object.section_id(write::StandardSection::Text);
object.append_section_data(section, &[0; 8], 1);
let symbol = object.add_symbol(write::Symbol {
name: b"sym".to_vec(),
value: 0,
size: 0,
kind: SymbolKind::Text,
scope: SymbolScope::Linkage,
weak: false,
section: write::SymbolSection::Section(section),
flags: SymbolFlags::None,
});
object
.add_relocation(
section,
write::Relocation {
offset: 0,
symbol,
addend: 0,
flags: RelocationFlags::Generic {
kind,
encoding,
size,
},
},
)
.unwrap();
let bytes = object.write().unwrap();
let file = read::File::parse(&*bytes).unwrap();
let section = file.sections().next().unwrap();
let (_, reloc) = section.relocations().next().unwrap();
let context =
format!("(K::{kind:?}, E::{encoding:?}, {size}) A::{arch:?} expected_flags={expected:?}");
assert_eq!(reloc.flags(), expected, "{context}");
if canonical {
assert_eq!(
reloc.kind(),
if reloc.subtractor().is_some() {
assert_eq!(kind, RelocationKind::Relative);
RelocationKind::Absolute
} else {
kind
},
"{context}"
);
assert_eq!(reloc.encoding(), encoding, "{context}");
assert_eq!(reloc.size(), size, "{context}");
}
}
#[test]
fn reloc_round_trip() {
use Architecture as A;
use BinaryFormat as F;
use RelocationEncoding as E;
use RelocationKind as K;
let elf_r = |arch, r_type| (F::Elf, arch, RelocationFlags::Elf { r_type });
let macho_r = |arch, r_type, r_pcrel, r_length| {
(
F::MachO,
arch,
RelocationFlags::MachO {
r_type,
r_pcrel,
r_length,
},
)
};
let coff_r = |arch, typ| (F::Coff, arch, RelocationFlags::Coff { typ });
let xcoff_r =
|arch, r_rtype, r_rsize| (F::Xcoff, arch, RelocationFlags::Xcoff { r_rtype, r_rsize });
let cases: Vec<(
(RelocationKind, RelocationEncoding, u8),
Vec<(BinaryFormat, Architecture, RelocationFlags)>,
Vec<(BinaryFormat, Architecture, RelocationFlags)>,
)> = vec![
(
(K::None, E::Generic, 0),
vec![
elf_r(A::I386, elf::R_386_NONE),
elf_r(A::X86_64, elf::R_X86_64_NONE),
elf_r(A::Arm, elf::R_ARM_NONE),
elf_r(A::Aarch64, elf::R_AARCH64_NONE),
elf_r(A::PowerPc, elf::R_PPC_NONE),
elf_r(A::PowerPc64, elf::R_PPC64_NONE),
],
vec![],
),
(
(K::Absolute, E::Generic, 8),
vec![
elf_r(A::I386, elf::R_386_8),
elf_r(A::X86_64, elf::R_X86_64_8),
macho_r(A::I386, macho::GENERIC_RELOC_VANILLA, false, 0),
macho_r(A::X86_64, macho::X86_64_RELOC_UNSIGNED, false, 0),
],
vec![],
),
(
(K::Absolute, E::Generic, 16),
vec![
elf_r(A::I386, elf::R_386_16),
elf_r(A::X86_64, elf::R_X86_64_16),
elf_r(A::Aarch64, elf::R_AARCH64_ABS16),
macho_r(A::I386, macho::GENERIC_RELOC_VANILLA, false, 1),
macho_r(A::X86_64, macho::X86_64_RELOC_UNSIGNED, false, 1),
macho_r(A::Aarch64, macho::ARM64_RELOC_UNSIGNED, false, 1),
coff_r(A::I386, pe::IMAGE_REL_I386_DIR16),
],
vec![],
),
(
(K::Absolute, E::Generic, 32),
vec![
elf_r(A::I386, elf::R_386_32),
elf_r(A::X86_64, elf::R_X86_64_32),
elf_r(A::Arm, elf::R_ARM_ABS32),
elf_r(A::Aarch64, elf::R_AARCH64_ABS32),
elf_r(A::PowerPc, elf::R_PPC_ADDR32),
elf_r(A::PowerPc64, elf::R_PPC64_ADDR32),
macho_r(A::I386, macho::GENERIC_RELOC_VANILLA, false, 2),
macho_r(A::X86_64, macho::X86_64_RELOC_UNSIGNED, false, 2),
macho_r(A::Arm, macho::ARM_RELOC_VANILLA, false, 2),
macho_r(A::Aarch64, macho::ARM64_RELOC_UNSIGNED, false, 2),
macho_r(A::PowerPc, macho::PPC_RELOC_VANILLA, false, 2),
macho_r(A::PowerPc64, macho::PPC_RELOC_VANILLA, false, 2),
coff_r(A::I386, pe::IMAGE_REL_I386_DIR32),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_ADDR32),
coff_r(A::Arm, pe::IMAGE_REL_ARM_ADDR32),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_ADDR32),
xcoff_r(A::PowerPc, xcoff::R_POS, 31),
xcoff_r(A::PowerPc64, xcoff::R_POS, 31),
],
vec![],
),
(
(K::Absolute, E::Generic, 64),
vec![
elf_r(A::X86_64, elf::R_X86_64_64),
elf_r(A::Aarch64, elf::R_AARCH64_ABS64),
elf_r(A::PowerPc64, elf::R_PPC64_ADDR64),
macho_r(A::X86_64, macho::X86_64_RELOC_UNSIGNED, false, 3),
macho_r(A::Aarch64, macho::ARM64_RELOC_UNSIGNED, false, 3),
macho_r(A::PowerPc64, macho::PPC_RELOC_VANILLA, false, 3),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_ADDR64),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_ADDR64),
xcoff_r(A::PowerPc64, xcoff::R_POS, 63),
],
vec![],
),
(
(K::Relative, E::Generic, 8),
vec![
elf_r(A::I386, elf::R_386_PC8),
elf_r(A::X86_64, elf::R_X86_64_PC8),
],
vec![],
),
(
(K::Relative, E::Generic, 16),
vec![
elf_r(A::I386, elf::R_386_PC16),
elf_r(A::X86_64, elf::R_X86_64_PC16),
elf_r(A::Aarch64, elf::R_AARCH64_PREL16),
],
vec![],
),
(
(K::Relative, E::Generic, 32),
vec![
elf_r(A::I386, elf::R_386_PC32),
elf_r(A::X86_64, elf::R_X86_64_PC32),
elf_r(A::Aarch64, elf::R_AARCH64_PREL32),
macho_r(A::Aarch64, macho::ARM64_RELOC_UNSIGNED, false, 2),
coff_r(A::I386, pe::IMAGE_REL_I386_REL32),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_REL32),
coff_r(A::Arm, pe::IMAGE_REL_ARM_REL32),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_REL32),
xcoff_r(A::PowerPc, xcoff::R_REL, 31),
xcoff_r(A::PowerPc64, xcoff::R_REL, 31),
],
vec![
macho_r(A::X86_64, macho::X86_64_RELOC_SIGNED, true, 2),
],
),
(
(K::PltRelative, E::Generic, 32),
vec![elf_r(A::I386, elf::R_386_PLT32)],
vec![
elf_r(A::X86_64, elf::R_X86_64_PLT32),
macho_r(A::X86_64, macho::X86_64_RELOC_BRANCH, true, 2),
macho_r(A::Aarch64, macho::ARM64_RELOC_BRANCH26, true, 2),
coff_r(A::I386, pe::IMAGE_REL_I386_REL32),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_REL32),
coff_r(A::Arm, pe::IMAGE_REL_ARM_REL32),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_REL32),
],
),
(
(K::Relative, E::X86RipRelative, 32),
vec![macho_r(A::X86_64, macho::X86_64_RELOC_SIGNED, true, 2)],
vec![
elf_r(A::X86_64, elf::R_X86_64_PC32),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_REL32),
],
),
(
(K::Relative, E::X86Branch, 32),
vec![],
vec![
elf_r(A::X86_64, elf::R_X86_64_PLT32),
macho_r(A::X86_64, macho::X86_64_RELOC_BRANCH, true, 2),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_REL32),
],
),
(
(K::PltRelative, E::X86Branch, 32),
vec![
elf_r(A::X86_64, elf::R_X86_64_PLT32),
macho_r(A::X86_64, macho::X86_64_RELOC_BRANCH, true, 2),
],
vec![
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_REL32),
],
),
(
(K::Relative, E::AArch64Call, 26),
vec![coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_BRANCH26)],
vec![
elf_r(A::Aarch64, elf::R_AARCH64_CALL26),
macho_r(A::Aarch64, macho::ARM64_RELOC_BRANCH26, true, 2),
],
),
(
(K::PltRelative, E::AArch64Call, 26),
vec![
elf_r(A::Aarch64, elf::R_AARCH64_CALL26),
macho_r(A::Aarch64, macho::ARM64_RELOC_BRANCH26, true, 2),
],
vec![
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_BRANCH26),
],
),
(
(K::Got, E::Generic, 32),
vec![
elf_r(A::I386, elf::R_386_GOT32),
elf_r(A::X86_64, elf::R_X86_64_GOT32),
],
vec![],
),
(
(K::GotRelative, E::Generic, 32),
vec![
elf_r(A::X86_64, elf::R_X86_64_GOTPCREL),
macho_r(A::X86_64, macho::X86_64_RELOC_GOT, true, 2),
],
vec![],
),
(
(K::ImageOffset, E::Generic, 32),
vec![
coff_r(A::I386, pe::IMAGE_REL_I386_DIR32NB),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_ADDR32NB),
coff_r(A::Arm, pe::IMAGE_REL_ARM_ADDR32NB),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_ADDR32NB),
],
vec![],
),
(
(K::SectionOffset, E::Generic, 32),
vec![
coff_r(A::I386, pe::IMAGE_REL_I386_SECREL),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_SECREL),
coff_r(A::Arm, pe::IMAGE_REL_ARM_SECREL),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_SECREL),
],
vec![],
),
(
(K::SectionIndex, E::Generic, 16),
vec![
coff_r(A::I386, pe::IMAGE_REL_I386_SECTION),
coff_r(A::X86_64, pe::IMAGE_REL_AMD64_SECTION),
coff_r(A::Arm, pe::IMAGE_REL_ARM_SECTION),
coff_r(A::Aarch64, pe::IMAGE_REL_ARM64_SECTION),
],
vec![],
),
];
for ((kind, encoding, size), expected, expected_extra) in cases {
for (format, arch, expected_flags) in expected {
check_reloc(format, arch, kind, encoding, size, expected_flags, true);
}
for (format, arch, expected_flags) in expected_extra {
check_reloc(format, arch, kind, encoding, size, expected_flags, false);
}
}
}