#![allow(dead_code)]
use crate::{
artifact::{
self, Artifact, Data, DataType, Decl, DefinedDecl, ImportKind, LinkAndDecl, Reloc, Scope,
Visibility,
},
target::make_ctx,
Ctx,
};
use goblin;
use indexmap::IndexMap;
use scroll::{IOwrite, Pwrite};
use std::collections::{hash_map, HashMap};
use std::fmt;
use std::io::SeekFrom::*;
use std::io::{BufWriter, Cursor, Seek, Write};
use string_interner::StringInterner;
use target_lexicon::Architecture;
use goblin::elf::header::{self, Header};
use goblin::elf::reloc;
use goblin::elf::section_header::{self, SectionHeader};
type StringIndex = usize;
type Offset = usize;
type Relocation = goblin::elf::reloc::Reloc;
type Symbol = goblin::elf::sym::Sym;
type Section = SectionHeader;
struct MachineTag(u16);
impl From<Architecture> for MachineTag {
fn from(architecture: Architecture) -> MachineTag {
use goblin::elf::header::*;
use target_lexicon::Architecture::*;
MachineTag(match architecture {
X86_64 => EM_X86_64,
X86_32(_) => EM_386,
Aarch64(_) => EM_AARCH64,
Arm(_) => EM_ARM,
Mips32(_) | Mips64(_) => EM_MIPS,
Powerpc => EM_PPC,
Powerpc64 | Powerpc64le => EM_PPC64,
Riscv32(_) | Riscv64(_) => EM_RISCV,
S390x => EM_S390,
Sparc => EM_SPARC,
Sparc64 | Sparcv9 => EM_SPARCV9,
Msp430 => EM_MSP430,
Unknown => EM_NONE,
Hexagon => panic!("goblin does not have EM_HEXAGON yet"),
Nvptx64 => panic!("nvptx64 does not exist in ELF"),
AmdGcn => panic!("amdgcn does not exist in ELF"),
Asmjs => panic!("asm.js does not exist in ELF"),
Wasm32 => panic!("wasm32 does not exist in ELF"),
arch => panic!(format!("Unknown architecture: {}", arch)),
})
}
}
enum SymbolType<'a> {
Decl(&'a DefinedDecl),
Import,
Section,
File,
None,
}
struct SymbolBuilder<'a> {
name_offset: usize,
size: u64,
typ: SymbolType<'a>,
shndx: usize,
value: u64,
}
impl<'a> SymbolBuilder<'a> {
pub fn new(typ: SymbolType<'a>) -> Self {
SymbolBuilder {
name_offset: 0,
typ,
size: 0,
shndx: 0,
value: 0,
}
}
pub fn from_decl(decl: &'a DefinedDecl) -> Self {
SymbolBuilder::new(SymbolType::Decl(decl))
}
pub fn size(mut self, size: usize) -> Self {
self.size = size as u64;
self
}
pub fn name_offset(mut self, name_offset: usize) -> Self {
self.name_offset = name_offset;
self
}
pub fn section_index(mut self, shndx: usize) -> Self {
debug_assert!(shndx < u32::max_value() as usize);
self.shndx = shndx;
self
}
pub fn value(mut self, value: u64) -> Self {
self.value = value;
self
}
pub fn create(self) -> Symbol {
use goblin::elf::section_header::SHN_ABS;
use goblin::elf::sym::{
STB_GLOBAL, STB_LOCAL, STB_WEAK, STT_FILE, STT_FUNC, STT_NOTYPE, STT_OBJECT,
STT_SECTION, STV_DEFAULT, STV_HIDDEN, STV_PROTECTED,
};
let mut st_shndx = self.shndx;
let mut st_info = 0;
let mut st_other = 0;
let st_value = self.value;
fn scope_stb_flags(s: Scope) -> u8 {
let flag = match s {
Scope::Local => STB_LOCAL,
Scope::Global => STB_GLOBAL,
Scope::Weak => STB_WEAK,
};
flag << 4
}
fn vis_stother_flags(v: Visibility) -> u8 {
match v {
Visibility::Default => STV_DEFAULT,
Visibility::Hidden => STV_HIDDEN,
Visibility::Protected => STV_PROTECTED,
}
}
match self.typ {
SymbolType::Decl(DefinedDecl::Function(d)) => {
st_info |= STT_FUNC;
st_info |= scope_stb_flags(d.get_scope());
st_other |= vis_stother_flags(d.get_visibility());
}
SymbolType::Decl(DefinedDecl::Data(d)) => {
st_info |= STT_OBJECT;
st_info |= scope_stb_flags(d.get_scope());
st_other |= vis_stother_flags(d.get_visibility());
}
SymbolType::Import => {
st_info = STT_NOTYPE;
st_info |= STB_GLOBAL << 4;
}
SymbolType::Decl(DefinedDecl::Section(_)) | SymbolType::Section => {
st_info |= STT_SECTION;
st_info |= STB_LOCAL << 4;
}
SymbolType::File => {
st_info = STT_FILE;
st_shndx = SHN_ABS as usize;
}
SymbolType::None => st_info = STT_NOTYPE,
}
Symbol {
st_name: self.name_offset,
st_other,
st_size: self.size,
st_info,
st_shndx,
st_value,
}
}
}
enum SectionType {
NoBits, Bits,
Data,
String,
StrTab,
SymTab,
Relocation,
SymTabShndx,
None,
}
struct SectionBuilder {
typ: SectionType,
exec: bool,
write: bool,
alloc: bool,
size: u64,
name_offset: usize,
align: Option<u64>,
}
impl SectionBuilder {
pub fn new(size: u64) -> Self {
SectionBuilder {
typ: SectionType::None,
exec: false,
write: false,
alloc: false,
name_offset: 0,
size,
align: None,
}
}
pub fn exec(mut self, executable: bool) -> Self {
self.exec = executable;
self
}
pub fn alloc(mut self) -> Self {
self.alloc = true;
self
}
pub fn writable(mut self, writable: bool) -> Self {
self.write = writable;
self
}
pub fn align(mut self, align: Option<u64>) -> Self {
self.align = align;
self
}
pub fn name_offset(mut self, name_offset: usize) -> Self {
self.name_offset = name_offset;
self
}
fn section_type(mut self, typ: SectionType) -> Self {
self.typ = typ;
self
}
pub fn create(self, ctx: &Ctx) -> Section {
use goblin::elf::section_header::*;
let mut shdr = Section::default();
shdr.sh_flags = 0u64;
shdr.sh_size = self.size;
shdr.sh_name = self.name_offset;
if self.exec {
shdr.sh_flags |= SHF_EXECINSTR as u64
}
if self.write {
shdr.sh_flags |= SHF_WRITE as u64
}
if self.alloc {
shdr.sh_flags |= SHF_ALLOC as u64
}
let align = if let Some(align) = self.align {
align as u64
} else if self.exec {
0x10
} else if self.write {
0x8
} else {
1
};
match self.typ {
SectionType::Bits => {
shdr.sh_addralign = align;
shdr.sh_type = SHT_PROGBITS;
}
SectionType::String => {
shdr.sh_addralign = align;
shdr.sh_type = SHT_PROGBITS;
shdr.sh_flags |= (SHF_MERGE | SHF_STRINGS) as u64;
}
SectionType::Data => {
shdr.sh_addralign = align;
shdr.sh_type = SHT_PROGBITS;
}
SectionType::StrTab => {
shdr.sh_addralign = 0x1;
shdr.sh_type = SHT_STRTAB;
}
SectionType::SymTab => {
shdr.sh_entsize = Symbol::size(ctx.container) as u64;
shdr.sh_addralign = 0x8;
shdr.sh_type = SHT_SYMTAB;
}
SectionType::Relocation => {
shdr.sh_entsize = Relocation::size(true, *ctx) as u64;
shdr.sh_addralign = 0x8;
shdr.sh_flags = 0;
shdr.sh_type = SHT_RELA
}
SectionType::SymTabShndx => {
shdr.sh_entsize = 4;
shdr.sh_addralign = 4;
shdr.sh_type = SHT_SYMTAB_SHNDX;
}
SectionType::NoBits => {
shdr.sh_type = SHT_NOBITS;
shdr.sh_flags |= u64::from(SHF_WRITE | SHF_ALLOC);
}
SectionType::None => shdr.sh_type = SHT_NULL,
}
shdr
}
}
#[derive(Debug)]
struct SectionInfo {
header: Section,
symbol: Symbol,
name: StringIndex,
}
struct RelocationBuilder {
addend: Option<i64>,
sym_idx: usize,
offset: u64,
typ: u32,
}
impl RelocationBuilder {
pub fn new(typ: u32) -> Self {
RelocationBuilder {
addend: Some(0),
offset: 0,
sym_idx: 0,
typ,
}
}
pub fn rel(mut self) -> Self {
self.addend = None;
self
}
pub fn addend(mut self, addend: i64) -> Self {
self.addend = Some(addend);
self
}
pub fn offset(mut self, offset: u64) -> Self {
self.offset = offset;
self
}
pub fn sym(mut self, sym_idx: usize) -> Self {
self.sym_idx = sym_idx;
self
}
pub fn create(self) -> Relocation {
Relocation {
r_offset: self.offset,
r_addend: self.addend,
r_sym: self.sym_idx,
r_type: self.typ,
}
}
}
struct Elf<'a> {
name: &'a str,
code: IndexMap<StringIndex, &'a [u8]>,
relocations: IndexMap<StringIndex, (Section, Vec<Relocation>)>,
symbols: IndexMap<StringIndex, Symbol>,
special_symbols: Vec<Symbol>,
imports: HashMap<StringIndex, ImportKind>,
sections: IndexMap<StringIndex, SectionInfo>,
offsets: HashMap<StringIndex, Offset>,
sizeof_strtab: Offset,
strings: StringInterner<StringIndex>,
sizeof_bits: Offset,
nsections: u32,
ctx: Ctx,
architecture: Architecture,
nlocals: usize,
}
impl<'a> fmt::Debug for Elf<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
writeln!(fmt, "{}", self.name)?;
writeln!(fmt, "{:?}", self.code)?;
writeln!(fmt, "{:#?}", self.relocations)?;
writeln!(fmt, "{:?}", self.imports)?;
writeln!(fmt, "{:?}", self.sections)?;
writeln!(fmt, "{:?}", self.offsets)?;
writeln!(fmt, "SizeofStrtab: {:?}", self.sizeof_strtab)?;
writeln!(fmt, "SizeofBits: {:?}", self.sizeof_bits)?;
writeln!(fmt, "Strings: {:?}", self.strings.len())?;
writeln!(fmt, "{:?}", self.ctx)
}
}
const STRTAB_LINK: u16 = 1;
const SYMTAB_LINK: u16 = 2;
impl<'a> Elf<'a> {
pub fn new(artifact: &'a Artifact) -> Self {
let ctx = make_ctx(&artifact.target);
let mut offsets = HashMap::new();
let mut strings: StringInterner<usize> = StringInterner::new();
let mut special_symbols = Vec::new();
let mut sizeof_strtab = 1;
{
let mut push_strtab = |name: &str| {
let name = name.to_owned();
let size = name.len() + 1;
let idx = strings.get_or_intern(name);
let offset = sizeof_strtab;
offsets.insert(idx, offset);
sizeof_strtab += size;
offset
};
push_strtab(".strtab");
push_strtab(".symtab");
let offset = push_strtab(&artifact.name);
special_symbols.push(Symbol::default());
special_symbols.push(
SymbolBuilder::new(SymbolType::File)
.name_offset(offset)
.create(),
);
}
let sizeof_bits = Header::size(ctx);
Elf {
name: &artifact.name,
code: IndexMap::new(),
relocations: IndexMap::new(),
imports: HashMap::new(),
symbols: IndexMap::new(),
special_symbols,
sections: IndexMap::new(),
nsections: 4,
offsets,
strings,
sizeof_strtab,
sizeof_bits,
ctx,
architecture: artifact.target.architecture,
nlocals: 0,
}
}
fn new_string(&mut self, name: String) -> (StringIndex, usize) {
let size = name.len() + 1;
let idx = self.strings.get_or_intern(name);
match self.offsets.entry(idx) {
hash_map::Entry::Occupied(entry) => (idx, *entry.get()),
hash_map::Entry::Vacant(entry) => {
let offset = self.sizeof_strtab;
self.sizeof_strtab += size;
(idx, *entry.insert(offset))
}
}
}
fn section_type_for_data(typ: DataType, is_zero_init: bool) -> SectionType {
if is_zero_init {
return SectionType::NoBits;
}
match typ {
DataType::Bytes => SectionType::Data,
DataType::String => SectionType::String,
}
}
pub fn add_definition(&mut self, def: artifact::Definition<'a>) {
let name = def.name;
let decl = def.decl;
let def_size = def.data.file_size();
let section_name = match (def.data, decl) {
(Data::Blob(_), DefinedDecl::Function(_)) => format!(".text.{}", name),
(Data::ZeroInit(_), DefinedDecl::Function(_)) => {
unreachable!("cannot define function as zero-init")
}
(Data::Blob(_), DefinedDecl::Data(decl)) => format!(
".{}.{}",
if decl.is_writable() { "data" } else { "rodata" },
name
),
(Data::ZeroInit(_), DefinedDecl::Data(_)) => format!(".bss.{}", name),
(_, DefinedDecl::Section(_)) => name.to_owned(),
};
let section = match decl {
DefinedDecl::Function(d) => SectionBuilder::new(def_size as u64)
.section_type(SectionType::Bits)
.alloc()
.writable(false)
.exec(true)
.align(d.get_align()),
DefinedDecl::Data(d) => SectionBuilder::new(def_size as u64)
.section_type(Self::section_type_for_data(
d.get_datatype(),
def.data.is_zero_init(),
))
.alloc()
.writable(d.is_writable())
.exec(false)
.align(d.get_align()),
DefinedDecl::Section(d) => SectionBuilder::new(def_size as u64)
.section_type(
if name == ".debug_str" || name == ".debug_line_str" {
SectionType::String
} else {
Self::section_type_for_data(d.get_datatype(), def.data.is_zero_init())
},
)
.align(d.get_align()),
};
let shndx = match def.data {
Data::Blob(bytes) => self.add_progbits(section_name, section, bytes),
Data::ZeroInit(_) => self.add_section(section_name, section).1,
};
match decl {
DefinedDecl::Function(_) | DefinedDecl::Data(_) => {
let (idx, offset) = self.new_string(name.to_string());
debug!(
"idx: {:?} @ {:#x} - new strtab offset: {:#x}",
idx, offset, self.sizeof_strtab
);
let symbol = SymbolBuilder::from_decl(decl)
.size(def_size)
.name_offset(offset)
.section_index(shndx)
.create();
self.symbols.insert(idx, symbol);
if !decl.is_global() {
self.nlocals += 1;
}
}
DefinedDecl::Section(_) => {
for (symbol, symbol_dst_offset) in def.symbols {
let (idx, offset) = self.new_string(symbol.clone());
debug!(
"idx: {:?} @ {:#x} - new strtab offset: {:#x}",
idx, offset, self.sizeof_strtab
);
let symbol = SymbolBuilder::new(SymbolType::None)
.name_offset(offset)
.section_index(shndx)
.value(*symbol_dst_offset)
.create();
self.symbols.insert(idx, symbol);
}
}
}
}
fn add_progbits(&mut self, name: String, section: SectionBuilder, data: &'a [u8]) -> usize {
let (idx, shndx) = self.add_section(name, section);
self.sizeof_bits += data.len();
self.code.insert(idx, data);
shndx
}
fn add_section(&mut self, name: String, section: SectionBuilder) -> (usize, usize) {
let (idx, offset) = self.new_string(name);
debug!(
"idx: {:?} @ {:#x} - new strtab offset: {:#x}",
idx, offset, self.sizeof_strtab
);
let shndx = self.sections.len() + 3; let section_symbol = SymbolBuilder::new(SymbolType::Section)
.section_index(shndx)
.create();
let mut section = section.name_offset(offset).create(&self.ctx);
section.sh_offset = self.sizeof_bits as u64;
self.sections.insert(
idx,
SectionInfo {
header: section,
symbol: section_symbol,
name: idx,
},
);
self.nsections += 1;
(idx, shndx)
}
pub fn import(&mut self, import: String, kind: &ImportKind) {
let (idx, offset) = self.new_string(import);
let symbol = SymbolBuilder::new(SymbolType::Import)
.name_offset(offset)
.create();
self.imports.insert(idx, kind.clone());
self.symbols.insert(idx, symbol);
}
pub fn link(&mut self, l: &LinkAndDecl) {
debug!("Link: {:?}", l);
let (to_idx, to_shndx) = {
let to_idx = self.strings.get_or_intern(l.to.name);
if l.to.decl.is_section() {
let (to_idx, _, _) = self
.sections
.get_full(&to_idx)
.expect("to_idx present in sections");
(to_idx + self.special_symbols.len(), to_idx + 3)
} else {
let (to_idx, _, symbol) = self
.symbols
.get_full(&to_idx)
.expect("to_idx present in symbols");
(
to_idx + self.special_symbols.len() + self.sections.len(),
symbol.st_shndx,
)
}
};
let (from_idx, from_shndx) = {
let from_idx = self.strings.get_or_intern(l.from.name);
if l.from.decl.is_section() {
let (from_idx, _, _) = self
.sections
.get_full(&from_idx)
.expect("from_idx present in sections");
(from_idx + self.special_symbols.len(), from_idx + 3)
} else {
let (from_idx, _, symbol) = self
.symbols
.get_full(&from_idx)
.expect("from_idx present in symbols");
(
from_idx + self.special_symbols.len() + self.sections.len(),
symbol.st_shndx,
)
}
};
let (reloc, addend) = match l.reloc {
Reloc::Auto => {
match *l.from.decl {
Decl::Defined(DefinedDecl::Function { .. }) => {
match *l.to.decl {
Decl::Defined(DefinedDecl::Function { .. })
| Decl::Import(ImportKind::Function) => (reloc::R_X86_64_PLT32, -4),
Decl::Defined(DefinedDecl::Data { .. }) => (reloc::R_X86_64_PC32, -4),
Decl::Import(ImportKind::Data) => (reloc::R_X86_64_GOTPCREL, -4),
_ => panic!("unsupported relocation {:?}", l),
}
}
Decl::Defined(DefinedDecl::Data { .. }) => {
if self.ctx.is_big() {
(reloc::R_X86_64_64, 0)
} else {
(reloc::R_X86_64_32, 0)
}
}
_ => panic!("unsupported relocation {:?}", l),
}
}
Reloc::Raw { reloc, addend } => (reloc, addend),
Reloc::Debug { size, addend } => match size {
4 => (reloc::R_X86_64_32, addend),
8 => (reloc::R_X86_64_64, addend),
_ => panic!("unsupported relocation {:?}", l),
},
};
let addend = i64::from(addend);
let sym_idx = match *l.to.decl {
Decl::Defined(_) => {
(to_shndx - 3) + self.special_symbols.len()
}
Decl::Import(_) => to_idx,
};
let reloc = RelocationBuilder::new(reloc)
.sym(sym_idx)
.offset(l.at)
.addend(addend)
.create();
self.add_reloc(l.from.name, reloc, from_idx, from_shndx)
}
fn add_reloc(&mut self, relocee: &str, reloc: Relocation, idx: usize, shndx: usize) {
debug!(
"add reloc for symbol {} section {} - reloc: {:?}",
idx, shndx, &reloc
);
let reloc_size = Relocation::size(reloc.r_addend.is_some(), self.ctx) as u64;
if self.relocations.contains_key(&shndx) {
debug!("{} has relocs", relocee);
let &mut (ref mut section, ref mut relocs) = self.relocations.get_mut(&shndx).unwrap();
section.sh_size += section.sh_entsize;
relocs.push(reloc);
} else {
debug!("{} does NOT have relocs", relocee);
let reloc_name = {
let (_, section) = self
.sections
.get_index(shndx - 3)
.expect("shndx present in sections");
let section_name = self
.strings
.resolve(section.name)
.expect("section name in strings");
format!(".rela{}", section_name)
};
let (_reloc_idx, reloc_section_offset) = self.new_string(reloc_name);
let mut reloc_section = SectionBuilder::new(reloc_size)
.name_offset(reloc_section_offset)
.section_type(SectionType::Relocation)
.create(&self.ctx);
reloc_section.sh_link = SYMTAB_LINK as u32;
reloc_section.sh_info = shndx as u32;
reloc_section.sh_flags |= section_header::SHF_INFO_LINK as u64;
self.relocations.insert(shndx, (reloc_section, vec![reloc]));
self.nsections += 1;
}
}
fn align(offset: &mut u64, sizeof_t: u64) {
let alignment = *offset % sizeof_t;
if alignment != 0 {
*offset += sizeof_t - alignment;
}
}
pub fn write<T: Write + Seek>(mut self, file: T) -> goblin::error::Result<()> {
use goblin::elf::section_header::{SHN_LORESERVE, SHN_XINDEX};
let mut file = BufWriter::new(file);
let symbol_count = self.symbols.len() + self.special_symbols.len() + self.sections.len();
let sizeof_symtab = symbol_count * Symbol::size(self.ctx.container);
let mut sizeof_symtab_shndx = 0;
let mut symtab_shndx_name_offset = 0;
let mut need_symtab_shndx = false;
if self.nsections >= SHN_LORESERVE.into() {
self.nsections += 1;
sizeof_symtab_shndx = symbol_count as u64 * 4;
symtab_shndx_name_offset = self.new_string(".symtab_shndx".into()).1;
need_symtab_shndx = true;
};
let sizeof_relocs = self
.relocations
.iter()
.fold(0, |acc, (_, &(ref _shdr, ref rels))| rels.len() + acc)
* Relocation::size(true, self.ctx);
let nonexec_stack_note_name_offset = self.new_string(".note.GNU-stack".into()).1;
let strtab_offset = self.sizeof_bits as u64;
let mut symtab_offset = strtab_offset + self.sizeof_strtab as u64;
let symtab_align = self.ctx.size() as u64;
Self::align(&mut symtab_offset, symtab_align);
let mut symtab_shndx_offset = symtab_offset + sizeof_symtab as u64;
let symtab_shndx_align = 4;
if need_symtab_shndx {
Self::align(&mut symtab_shndx_offset, symtab_shndx_align);
}
let mut reloc_offset = symtab_shndx_offset + sizeof_symtab_shndx;
let reloc_align = self.ctx.size() as u64;
Self::align(&mut reloc_offset, reloc_align);
let mut sh_offset = reloc_offset + sizeof_relocs as u64;
let shdr_align = self.ctx.size() as u64;
Self::align(&mut sh_offset, shdr_align);
info!(
"strtab: {:#x} symtab {:#x} relocs {:#x} sh_offset {:#x}",
strtab_offset, symtab_offset, reloc_offset, sh_offset
);
let mut header = Header::new(self.ctx);
let machine: MachineTag = self.architecture.into();
header.e_machine = machine.0;
header.e_type = header::ET_REL;
header.e_shoff = sh_offset;
header.e_shnum = if self.nsections >= SHN_LORESERVE.into() {
0
} else {
self.nsections as u16
};
header.e_shstrndx = STRTAB_LINK;
file.iowrite_with(header, self.ctx)?;
let after_header = file.seek(Current(0))?;
debug!("after_header {:#x}", after_header);
assert_eq!(after_header, Header::size(self.ctx) as u64);
for (_idx, bytes) in self.code.drain(..) {
file.write_all(bytes)?;
}
let after_code = file.seek(Current(0))?;
debug!("after_code {:#x}", after_code);
assert_eq!(after_code, strtab_offset);
let mut section_headers = vec![SectionHeader::default()];
if self.nsections >= SHN_LORESERVE.into() {
section_headers[0].sh_size = self.nsections as u64;
}
let mut strtab = {
let offset = *(self.offsets.get(&0).unwrap());
SectionBuilder::new(self.sizeof_strtab as u64)
.name_offset(offset)
.section_type(SectionType::StrTab)
.create(&self.ctx)
};
strtab.sh_offset = strtab_offset;
section_headers.push(strtab);
let mut symtab = {
let offset = *(self.offsets.get(&1).unwrap());
SectionBuilder::new(sizeof_symtab as u64)
.name_offset(offset)
.section_type(SectionType::SymTab)
.create(&self.ctx)
};
symtab.sh_offset = symtab_offset;
symtab.sh_link = 1; symtab.sh_info = (self.special_symbols.len() + self.sections.len() + self.nlocals) as u32;
section_headers.push(symtab);
file.seek(Start(strtab_offset))?;
file.iowrite(0u8)?; for (_id, string) in &self.strings {
debug!("String: {:?}", string);
file.write_all(string.as_bytes())?;
file.iowrite(0u8)?;
}
{
let mut after_strtab = file.seek(Current(0))?;
Self::align(&mut after_strtab, symtab_align);
debug!("after_strtab {:#x}", after_strtab);
assert_eq!(after_strtab, symtab_offset);
}
let mut symtab_shndx_data: Vec<u8> = if need_symtab_shndx {
vec![0; symbol_count * 4]
} else {
Vec::new()
};
let mut offset = 0;
file.seek(Start(symtab_offset))?;
for symbol in self.special_symbols.into_iter() {
debug!("Special Symbol: {:?}", symbol);
if need_symtab_shndx {
symtab_shndx_data
.gwrite_with(symbol.st_shndx as u32, &mut offset, self.ctx.le)
.expect("preallocated shndx vector has enough space for special symbols");
}
file.iowrite_with(symbol, self.ctx)?;
}
for (_id, section) in self.sections.into_iter() {
debug!("Section Symbol: {:?}", section.symbol);
let mut sym = section.symbol.clone();
if need_symtab_shndx {
symtab_shndx_data
.gwrite_with(sym.st_shndx as u32, &mut offset, self.ctx.le)
.expect("preallocated shndx vector has enough space for sections");
}
if sym.st_shndx >= SHN_LORESERVE as usize {
sym.st_shndx = SHN_XINDEX as usize;
}
file.iowrite_with(sym, self.ctx)?;
section_headers.push(section.header);
}
for (_id, symbol) in self.symbols.into_iter() {
debug!("Symbol: {:?}", symbol);
let mut sym = symbol.clone();
if need_symtab_shndx {
symtab_shndx_data
.gwrite_with(sym.st_shndx as u32, &mut offset, self.ctx.le)
.expect("preallocated shndx vector has enough space for symbols");
}
if sym.st_shndx >= SHN_LORESERVE as usize {
sym.st_shndx = SHN_XINDEX as usize;
}
file.iowrite_with(sym, self.ctx)?;
}
if need_symtab_shndx {
{
let mut after_symtab = file.seek(Current(0))?;
Self::align(&mut after_symtab, symtab_shndx_align);
debug!("after_symtab {:#x}", after_symtab);
assert_eq!(after_symtab, symtab_shndx_offset);
}
file.seek(Start(symtab_shndx_offset))?;
file.write_all(&symtab_shndx_data)?;
let mut section = SectionBuilder::new(sizeof_symtab_shndx)
.name_offset(symtab_shndx_name_offset)
.section_type(SectionType::SymTabShndx)
.create(&self.ctx);
section.sh_link = 2;
section.sh_offset = symtab_shndx_offset;
section_headers.push(section);
}
{
let mut after_symtab_shndx = file.seek(Current(0))?;
Self::align(&mut after_symtab_shndx, reloc_align);
debug!(
"after_symtab_shndx {:#x} - shdr_size {}",
after_symtab_shndx,
Section::size(self.ctx)
);
assert_eq!(after_symtab_shndx, reloc_offset);
}
file.seek(Start(reloc_offset))?;
let mut roffset = reloc_offset;
for (_, (mut section, mut relocations)) in self.relocations.into_iter() {
section.sh_offset = roffset;
roffset += section.sh_size;
section_headers.push(section);
for relocation in relocations.drain(..) {
debug!("Relocation: {:?}", relocation);
file.iowrite_with(relocation, (relocation.r_addend.is_some(), self.ctx))?;
}
}
{
let mut after_relocs = file.seek(Current(0))?;
Self::align(&mut after_relocs, shdr_align);
debug!("after_relocs {:#x}", after_relocs);
assert_eq!(after_relocs, sh_offset);
}
let nonexec_stack = SectionBuilder::new(0)
.name_offset(nonexec_stack_note_name_offset)
.section_type(SectionType::Bits)
.create(&self.ctx);
section_headers.push(nonexec_stack);
let sizeof_shdr = Section::size(self.ctx) as u64;
let shdr_size = section_headers.len() as u64 * sizeof_shdr;
file.seek(Start(sh_offset))?;
for shdr in section_headers {
debug!("Section: {:?}", shdr);
file.iowrite_with(shdr, self.ctx)?;
}
{
let after_shdrs = file.seek(Current(0))?;
let expected = sh_offset + shdr_size;
debug!("after_shdrs {:#x}", after_shdrs);
assert_eq!(after_shdrs, expected);
}
debug!("done");
Ok(())
}
}
pub fn to_bytes(artifact: &Artifact) -> goblin::error::Result<Vec<u8>> {
let mut elf = Elf::new(&artifact);
for def in artifact.definitions() {
debug!("Def: {:?}", def);
elf.add_definition(def);
}
for (ref import, ref kind) in artifact.imports() {
debug!("Import: {:?} -> {:?}", import, kind);
elf.import(import.to_string(), kind);
}
for link in artifact.links() {
elf.link(&link);
}
let mut buffer = Cursor::new(Vec::new());
elf.write(&mut buffer)?;
Ok(buffer.into_inner())
}