Skip to content

Commit

Permalink
Merge pull request m4b#21 from pchickey/pch/optional_reloc_type
Browse files Browse the repository at this point in the history
Add `Artifact::link_with` API to optionally override ELF relocation type
  • Loading branch information
m4b authored Dec 6, 2017
2 parents 0501514 + b5f03d5 commit 65051c7
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 14 deletions.
26 changes: 23 additions & 3 deletions src/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ use std::collections::BTreeSet;

use {Target, Data};

type Relocation = (String, String, usize);
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
pub struct RelocOverride {
pub elftype: u32,
pub addend: u32,
}

type Relocation = (String, String, usize, Option<RelocOverride>);

/// The kinds of errors that can befall someone creating an Artifact
#[derive(Fail, Debug)]
Expand Down Expand Up @@ -90,6 +96,7 @@ pub(crate) struct LinkAndDecl<'a> {
pub from: Binding<'a>,
pub to: Binding<'a>,
pub at: usize,
pub reloc: Option<RelocOverride>,
}

/// A definition of a symbol with its properties the various backends receive
Expand Down Expand Up @@ -205,14 +212,15 @@ impl Artifact {
}
/// Get this artifacts relocations
pub(crate) fn links<'a>(&'a self) -> Box<Iterator<Item = LinkAndDecl<'a>> + 'a> {
Box::new(self.links.iter().map(move |&(ref from, ref to, ref at)| {
Box::new(self.links.iter().map(move |&(ref from, ref to, ref at, ref reloc)| {
// FIXME: I think its safe to unwrap since the links are only ever constructed by us and we
// ensure it has a declaration
let (ref from_decl, ref to_decl) = (self.declarations.get(from).unwrap(), self.declarations.get(to).unwrap());
LinkAndDecl {
from: Binding { name: from, decl: from_decl},
to: Binding { name: to, decl: to_decl},
at: *at,
reloc: *reloc,
}
}))
}
Expand Down Expand Up @@ -278,12 +286,22 @@ impl Artifact {
/// **NB**: If either `link.from` or `link.to` is undeclared, then this will return an error.
/// If `link.from` is an import you previously declared, this will also return an error.
pub fn link<'a>(&mut self, link: Link<'a>) -> Result<(), Error> {
self.link_aux(link, None)
}
/// A variant of `link` with a RelocOverride provided. Has all of the same invariants as
/// `link`.
pub fn link_with<'a>(&mut self, link: Link<'a>, reloc: RelocOverride) -> Result<(), Error> {
self.link_aux(link, Some(reloc))
}

/// Shared implementation of `link` and `link_with`.
fn link_aux<'a>(&mut self, link: Link<'a>, reloc: Option<RelocOverride>) -> Result<(), Error> {
match (self.declarations.get(link.from), self.declarations.get(link.to)) {
(Some(ref from_type), Some(_)) => {
if from_type.is_import() {
return Err(ArtifactError::RelocateImport(link.from.to_string()).into());
}
let link = (link.from.to_string(), link.to.to_string(), link.at);
let link = (link.from.to_string(), link.to.to_string(), link.at, reloc);
self.links.push(link.clone());
},
(None, _) => {
Expand All @@ -294,7 +312,9 @@ impl Artifact {
}
}
Ok(())

}

/// Emit a blob of bytes that represents this object file
pub fn emit<O: Object>(&self) -> Result<Vec<u8>, Error> {
O::to_bytes(self)
Expand Down
32 changes: 22 additions & 10 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use goblin;
use failure::Error;
use {artifact, Artifact, Decl, Object, Target, Ctx, ImportKind};
use {artifact, Artifact, Decl, Object, Target, Ctx, ImportKind, RelocOverride};

use std::collections::HashMap;
use std::fmt;
Expand Down Expand Up @@ -437,23 +437,35 @@ impl<'a> Elf<'a> {
self.imports.insert(idx, kind.clone());
self.symbols.insert(idx, symbol);
}
pub fn link(&mut self, from: &str, to: &str, offset: usize, to_type: &Decl) {
pub fn link(&mut self, from: &str, to: &str, offset: usize, to_type: &Decl, reloctype: Option<RelocOverride>) {
let (from_idx, to_idx) = {
let to_idx = self.strings.intern(to).unwrap();
let from_idx = self.strings.intern(from).unwrap();
let (to_idx, _, _) = self.symbols.get_pair_index(&to_idx).unwrap();
let (from_idx, _, _) = self.symbols.get_pair_index(&from_idx).unwrap();
(from_idx, to_idx)
};
let (reloc, addend, sym_idx) = match *to_type {
// NB: this now forces _all_ function references, whether local or not, through the PLT
// although we're not in the worst company here: https://github.com/ocaml/ocaml/pull/1330
Decl::Function {..} => (reloc::R_X86_64_PLT32, -4, to_idx + 2), // +2 for NOTYPE and FILE symbols
Decl::Data {..} => (reloc::R_X86_64_PC32, 0, to_idx + 2),

let (reloc, addend) = if let Some(ovr) = reloctype {
(ovr.elftype, ovr.addend as isize)
} else {
match *to_type {
// NB: this now forces _all_ function references, whether local or not, through the PLT
// although we're not in the worst company here: https://github.com/ocaml/ocaml/pull/1330
Decl::Function {..} => (reloc::R_X86_64_PLT32, -4),
Decl::Data {..} => (reloc::R_X86_64_PC32, 0),
Decl::FunctionImport => (reloc::R_X86_64_PLT32, -4),
Decl::DataImport => (reloc::R_X86_64_GOTPCREL, -4),
}
};

let sym_idx = match *to_type {
Decl::Function {..} | Decl::Data {..} => to_idx + 2,
// +2 for NOTYPE and FILE symbols
Decl::FunctionImport | Decl::DataImport => to_idx + self.section_symbols.len(),
// + section_symbols.len() because this is where the import symbols begin
Decl::FunctionImport => (reloc::R_X86_64_PLT32, -4, to_idx + self.section_symbols.len()),
Decl::DataImport => (reloc::R_X86_64_GOTPCREL, -4, to_idx + self.section_symbols.len()),
};

let reloc = RelocationBuilder::new(reloc).sym(sym_idx).offset(offset).addend(addend).create();
self.add_reloc(from, reloc, from_idx)
}
Expand Down Expand Up @@ -633,7 +645,7 @@ impl<'a> Object for Elf<'a> {
elf.import(import.to_string(), kind);
}
for link in artifact.links() {
elf.link(link.from.name, link.to.name, link.at, link.to.decl);
elf.link(link.from.name, link.to.name, link.at, link.to.decl, link.reloc);
}
let mut buffer = Cursor::new(Vec::new());
elf.write(&mut buffer)?;
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub mod mach;
pub use mach::Mach;

pub mod artifact;
pub use artifact::{Object, Artifact, ArtifactBuilder, Link, ImportKind, Decl};
pub use artifact::{Object, Artifact, ArtifactBuilder, Link, ImportKind, Decl, RelocOverride};

#[cfg(test)]
mod tests {
Expand Down

0 comments on commit 65051c7

Please sign in to comment.