1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Utilities for working with Faerie container formats.

use cretonne_codegen::binemit::Reloc;
use target_lexicon::{Architecture, BinaryFormat, Triple};

/// An object file format.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Format {
    /// The ELF object file format.
    ELF,
    /// The Mach-O object file format.
    MachO,
}

/// Translate from a Cretonne `Reloc` to a raw object-file-format-specific
/// relocation code and relocation-implied addend.
pub fn raw_relocation(reloc: Reloc, triple: &Triple) -> (u32, i64) {
    match triple.binary_format {
        BinaryFormat::Elf => {
            use goblin::elf;
            (
                match triple.architecture {
                    Architecture::X86_64 => {
                        match reloc {
                            Reloc::Abs4 => elf::reloc::R_X86_64_32,
                            Reloc::Abs8 => elf::reloc::R_X86_64_64,
                            Reloc::X86PCRel4 | Reloc::X86CallPCRel4 => elf::reloc::R_X86_64_PC32,
                            // TODO: Get Cretonne to tell us when we can use
                            // R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX.
                            Reloc::X86CallPLTRel4 => elf::reloc::R_X86_64_PLT32,
                            Reloc::X86GOTPCRel4 => elf::reloc::R_X86_64_GOTPCREL,
                            _ => unimplemented!(),
                        }
                    }
                    _ => unimplemented!("unsupported architecture: {}", triple),
                },
                // Most ELF relocations do not include an implicit addend.
                0,
            )
        }
        BinaryFormat::Macho => {
            use goblin::mach;
            match triple.architecture {
                Architecture::X86_64 => {
                    match reloc {
                        Reloc::Abs8 => (u32::from(mach::relocation::R_ABS), 0),
                        // Mach-O doesn't need us to distinguish between PC-relative calls
                        // and PLT calls, but it does need us to distinguish between calls
                        // and non-calls. And, it includes the 4-byte addend implicitly.
                        Reloc::X86PCRel4 => (u32::from(mach::relocation::X86_64_RELOC_SIGNED), 4),
                        Reloc::X86CallPCRel4 | Reloc::X86CallPLTRel4 => {
                            (u32::from(mach::relocation::X86_64_RELOC_BRANCH), 4)
                        }
                        Reloc::X86GOTPCRel4 => {
                            (u32::from(mach::relocation::X86_64_RELOC_GOT_LOAD), 4)
                        }
                        _ => unimplemented!("unsupported mach-o reloc: {}", reloc),
                    }
                }
                _ => unimplemented!("unsupported architecture: {}", triple),
            }
        }
        _ => unimplemented!("unsupported format"),
    }
}