diff --git a/examples/objcopy.rs b/examples/objcopy.rs index aa17d337..16c2bb56 100644 --- a/examples/objcopy.rs +++ b/examples/objcopy.rs @@ -2,7 +2,8 @@ use std::collections::HashMap; use std::{env, fs, process}; use object::{ - write, Object, ObjectSection, RelocationTarget, SectionKind, SymbolKind, SymbolSection, + write, Object, ObjectSection, RelocationTarget, SectionKind, SymbolFlags, SymbolKind, + SymbolSection, }; fn main() { @@ -40,7 +41,7 @@ fn main() { let mut out_object = write::Object::new(in_object.format(), in_object.architecture()); out_object.mangling = write::Mangling::None; - // TODO: copy MH_SUBSECTIONS_VIA_SYMBOLS + out_object.flags = in_object.flags(); let mut out_sections = HashMap::new(); for in_section in in_object.sections() { @@ -58,6 +59,7 @@ fn main() { } else { out_section.set_data(in_section.uncompressed_data().into(), in_section.align()); } + out_section.flags = in_section.flags(); out_sections.insert(in_section.index(), section_id); } @@ -76,6 +78,21 @@ fn main() { in_symbol.address() - in_object.section_by_index(index).unwrap().address(), ), }; + let flags = match in_symbol.flags() { + SymbolFlags::None => SymbolFlags::None, + SymbolFlags::Elf { st_info, st_other } => SymbolFlags::Elf { st_info, st_other }, + SymbolFlags::MachO { n_desc } => SymbolFlags::MachO { n_desc }, + SymbolFlags::CoffSection { + selection, + associative_section, + } => { + let associative_section = *out_sections.get(&associative_section).unwrap(); + SymbolFlags::CoffSection { + selection, + associative_section, + } + } + }; let out_symbol = write::Symbol { name: in_symbol.name().unwrap_or("").as_bytes().to_vec(), value, @@ -84,6 +101,7 @@ fn main() { scope: in_symbol.scope(), weak: in_symbol.is_weak(), section, + flags, }; let symbol_id = out_object.add_symbol(out_symbol); out_symbols.insert(symbol_index, symbol_id); diff --git a/src/common.rs b/src/common.rs index a90d89c4..a89fd5ec 100644 --- a/src/common.rs +++ b/src/common.rs @@ -196,3 +196,73 @@ pub enum RelocationEncoding { /// The `RelocationKind` must be PC relative. X86Branch, } + +/// File flags that are specific to each file format. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum FileFlags { + /// No file flags. + None, + /// ELF file flags. + Elf { + /// `e_flags` field in the ELF file header. + e_flags: u32, + }, + /// Mach-O file flags. + MachO { + /// `flags` field in the Mach-O file header. + flags: u32, + }, + /// COFF file flags. + Coff { + /// `Characteristics` field in the COFF file header. + characteristics: u16, + }, +} + +/// Section flags that are specific to each file format. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SectionFlags { + /// No section flags. + None, + /// ELF section flags. + Elf { + /// `sh_flags` field in the section header. + sh_flags: u64, + }, + /// Mach-O section flags. + MachO { + /// `flags` field in the section header. + flags: u32, + }, + /// COFF section flags. + Coff { + /// `Characteristics` field in the section header. + characteristics: u32, + }, +} + +/// Symbol flags that are specific to each file format. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum SymbolFlags
{ + /// No symbol flags. + None, + /// ELF symbol flags. + Elf { + /// `st_info` field in the ELF symbol. + st_info: u8, + /// `st_other` field in the ELF symbol. + st_other: u8, + }, + /// Mach-O symbol flags. + MachO { + /// `n_desc` field in the Mach-O symbol. + n_desc: u16, + }, + /// COFF flags for a section symbol. + CoffSection { + /// `Selection` field in the auxiliary symbol for the section. + selection: u8, + /// `Number` field in the auxiliary symbol for the section. + associative_section: Section, + }, +} diff --git a/src/read/any.rs b/src/read/any.rs index 74f03f73..fd08973a 100644 --- a/src/read/any.rs +++ b/src/read/any.rs @@ -7,8 +7,8 @@ use uuid::Uuid; use crate::read::wasm; use crate::read::{coff, elf, macho, pe}; use crate::read::{ - Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol, - SymbolIndex, SymbolMap, + FileFlags, Object, ObjectSection, ObjectSegment, Relocation, SectionFlags, SectionIndex, + SectionKind, Symbol, SymbolIndex, SymbolMap, }; /// Evaluate an expression on the contents of a file format enum. @@ -241,6 +241,10 @@ where fn entry(&self) -> u64 { with_inner!(self.inner, FileInternal, |x| x.entry()) } + + fn flags(&self) -> FileFlags { + with_inner!(self.inner, FileInternal, |x| x.flags()) + } } /// An iterator over the segments of a `File`. @@ -460,6 +464,10 @@ impl<'data, 'file> ObjectSection<'data> for Section<'data, 'file> { ), } } + + fn flags(&self) -> SectionFlags { + with_inner!(self.inner, SectionInternal, |x| x.flags()) + } } /// An iterator over symbol table entries. diff --git a/src/read/coff.rs b/src/read/coff.rs index af404cb9..30d75dd9 100644 --- a/src/read/coff.rs +++ b/src/read/coff.rs @@ -6,9 +6,9 @@ use std::{iter, slice}; use target_lexicon::Architecture; use crate::read::{ - self, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, RelocationKind, - RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolMap, - SymbolScope, SymbolSection, + self, FileFlags, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, + RelocationKind, RelocationTarget, SectionFlags, SectionIndex, SectionKind, Symbol, SymbolFlags, + SymbolIndex, SymbolKind, SymbolMap, SymbolScope, SymbolSection, }; /// A COFF object file. @@ -186,6 +186,12 @@ where fn entry(&self) -> u64 { 0 } + + fn flags(&self) -> FileFlags { + FileFlags::Coff { + characteristics: self.coff.header.characteristics, + } + } } impl<'data, 'file> Iterator for CoffSegmentIterator<'data, 'file> { @@ -272,9 +278,13 @@ impl<'data, 'file> Iterator for CoffSectionIterator<'data, 'file> { impl<'data, 'file> CoffSection<'data, 'file> { fn raw_data(&self) -> &'data [u8] { - let offset = self.section.pointer_to_raw_data as usize; - let size = self.section.size_of_raw_data as usize; - &self.file.data[offset..][..size] + if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 { + &[] + } else { + let offset = self.section.pointer_to_raw_data as usize; + let size = self.section.size_of_raw_data as usize; + &self.file.data[offset..][..size] + } } } @@ -304,10 +314,14 @@ impl<'data, 'file> ObjectSection<'data> for CoffSection<'data, 'file> { #[inline] fn file_range(&self) -> Option<(u64, u64)> { - Some(( - self.section.pointer_to_raw_data as u64, - self.section.size_of_raw_data as u64, - )) + if self.section.characteristics & pe::section_table::IMAGE_SCN_CNT_UNINITIALIZED_DATA != 0 { + None + } else { + Some(( + self.section.pointer_to_raw_data as u64, + self.section.size_of_raw_data as u64, + )) + } } fn data(&self) -> Cow<'data, [u8]> { @@ -366,6 +380,12 @@ impl<'data, 'file> ObjectSection<'data> for CoffSection<'data, 'file> { relocations: self.section.relocations(self.file.data).unwrap_or_default(), } } + + fn flags(&self) -> SectionFlags { + SectionFlags::Coff { + characteristics: self.section.characteristics, + } + } } impl<'data, 'file> fmt::Debug for CoffSymbolIterator<'data, 'file> { @@ -411,15 +431,19 @@ fn parse_symbol<'data>( } else { SymbolKind::Data }; + let mut flags = SymbolFlags::None; // FIXME: symbol.value is a section offset for non-absolute symbols, not an address let (kind, address, size) = match symbol.storage_class { pe::symbol::IMAGE_SYM_CLASS_STATIC => { if symbol.value == 0 && symbol.number_of_aux_symbols > 0 { - let size = coff - .symbols - .aux_section_definition(index + 1) - .map(|aux| u64::from(aux.length)) - .unwrap_or(0); + let mut size = 0; + if let Some(aux) = coff.symbols.aux_section_definition(index + 1) { + size = u64::from(aux.length); + flags = SymbolFlags::CoffSection { + selection: aux.selection, + associative_section: SectionIndex(aux.number as usize), + }; + } (SymbolKind::Section, 0, size) } else { (derived_kind, u64::from(symbol.value), 0) @@ -481,6 +505,7 @@ fn parse_symbol<'data>( section, weak, scope, + flags, } } diff --git a/src/read/elf.rs b/src/read/elf.rs index 8131a406..73b976cf 100644 --- a/src/read/elf.rs +++ b/src/read/elf.rs @@ -13,9 +13,9 @@ use std::{iter, slice}; use target_lexicon::{Aarch64Architecture, Architecture, ArmArchitecture}; use crate::read::{ - self, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, RelocationKind, - RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolMap, - SymbolScope, SymbolSection, + self, FileFlags, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, + RelocationKind, RelocationTarget, SectionFlags, SectionIndex, SectionKind, Symbol, SymbolFlags, + SymbolIndex, SymbolKind, SymbolMap, SymbolScope, SymbolSection, }; /// An ELF object file. @@ -224,6 +224,12 @@ where fn entry(&self) -> u64 { self.elf.entry } + + fn flags(&self) -> FileFlags { + FileFlags::Elf { + e_flags: self.elf.header.e_flags, + } + } } /// An iterator over the segments of an `ElfFile`. @@ -530,6 +536,12 @@ impl<'data, 'file> ObjectSection<'data> for ElfSection<'data, 'file> { relocations: None, } } + + fn flags(&self) -> SectionFlags { + SectionFlags::Elf { + sh_flags: self.section.sh_flags, + } + } } /// An iterator over the symbols of an `ElfFile`. @@ -597,6 +609,10 @@ fn parse_symbol<'data>( } _ => SymbolScope::Unknown, }; + let flags = SymbolFlags::Elf { + st_info: symbol.st_info, + st_other: symbol.st_other, + }; Symbol { name, address: symbol.st_value, @@ -605,6 +621,7 @@ fn parse_symbol<'data>( section, weak, scope, + flags, } } diff --git a/src/read/macho.rs b/src/read/macho.rs index 36e91768..0f1d1687 100644 --- a/src/read/macho.rs +++ b/src/read/macho.rs @@ -8,9 +8,9 @@ use target_lexicon::{Aarch64Architecture, Architecture, ArmArchitecture}; use uuid::Uuid; use crate::read::{ - self, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, RelocationKind, - RelocationTarget, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolMap, - SymbolScope, SymbolSection, + self, FileFlags, Object, ObjectSection, ObjectSegment, Relocation, RelocationEncoding, + RelocationKind, RelocationTarget, SectionFlags, SectionIndex, SectionKind, Symbol, SymbolFlags, + SymbolIndex, SymbolKind, SymbolMap, SymbolScope, SymbolSection, }; /// A Mach-O object file. @@ -173,6 +173,7 @@ where section: SymbolSection::Undefined, weak: false, scope: SymbolScope::Compilation, + flags: SymbolFlags::None, }); } @@ -226,6 +227,12 @@ where fn entry(&self) -> u64 { self.macho.entry } + + fn flags(&self) -> FileFlags { + FileFlags::MachO { + flags: self.macho.header.flags, + } + } } /// An iterator over the segments of a `MachOFile`. @@ -403,6 +410,12 @@ impl<'data, 'file> ObjectSection<'data> for MachOSection<'data, 'file> { .iter_relocations(self.file.data, self.file.ctx), } } + + fn flags(&self) -> SectionFlags { + SectionFlags::MachO { + flags: self.internal().section.flags, + } + } } #[derive(Debug)] @@ -509,6 +522,9 @@ fn parse_symbol<'data>( } else { SymbolScope::Dynamic }; + let flags = SymbolFlags::MachO { + n_desc: nlist.n_desc, + }; Some(Symbol { name: Some(name), address: nlist.n_value, @@ -518,6 +534,7 @@ fn parse_symbol<'data>( section, weak, scope, + flags, }) } diff --git a/src/read/mod.rs b/src/read/mod.rs index f9ff231b..2e045b41 100644 --- a/src/read/mod.rs +++ b/src/read/mod.rs @@ -1,7 +1,10 @@ //! Interface for reading object files. use crate::alloc::vec::Vec; -use crate::common::{RelocationEncoding, RelocationKind, SectionKind, SymbolKind, SymbolScope}; +use crate::common::{ + FileFlags, RelocationEncoding, RelocationKind, SectionFlags, SectionKind, SymbolFlags, + SymbolKind, SymbolScope, +}; mod any; pub use any::*; @@ -91,6 +94,7 @@ pub struct Symbol<'data> { section: SymbolSection, weak: bool, scope: SymbolScope, + flags: SymbolFlags, } impl<'data> Symbol<'data> { @@ -154,6 +158,12 @@ impl<'data> Symbol<'data> { self.scope } + /// Symbol flags that are specific to each file format. + #[inline] + pub fn flags(&self) -> SymbolFlags { + self.flags + } + /// The name of the symbol. #[inline] pub fn name(&self) -> Option<&'data str> { diff --git a/src/read/pe.rs b/src/read/pe.rs index f6a6bb93..e8efb76f 100644 --- a/src/read/pe.rs +++ b/src/read/pe.rs @@ -5,8 +5,9 @@ use std::{cmp, iter, slice}; use target_lexicon::Architecture; use crate::read::{ - self, Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol, - SymbolIndex, SymbolKind, SymbolMap, SymbolScope, SymbolSection, + self, FileFlags, Object, ObjectSection, ObjectSegment, Relocation, SectionFlags, SectionIndex, + SectionKind, Symbol, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap, SymbolScope, + SymbolSection, }; /// A PE object file. @@ -143,6 +144,12 @@ where fn entry(&self) -> u64 { self.pe.entry as u64 } + + fn flags(&self) -> FileFlags { + FileFlags::Coff { + characteristics: self.pe.header.coff_header.characteristics, + } + } } /// An iterator over the loadable sections of a `PeFile`. @@ -334,6 +341,12 @@ impl<'data, 'file> ObjectSection<'data> for PeSection<'data, 'file> { fn relocations(&self) -> PeRelocationIterator { PeRelocationIterator } + + fn flags(&self) -> SectionFlags { + SectionFlags::Coff { + characteristics: self.section.characteristics, + } + } } /// An iterator over the symbols of a `PeFile`. @@ -365,6 +378,7 @@ impl<'data, 'file> Iterator for PeSymbolIterator<'data, 'file> { section: SymbolSection::Unknown, weak: false, scope: SymbolScope::Dynamic, + flags: SymbolFlags::None, }, )); } @@ -385,6 +399,7 @@ impl<'data, 'file> Iterator for PeSymbolIterator<'data, 'file> { section: SymbolSection::Undefined, weak: false, scope: SymbolScope::Dynamic, + flags: SymbolFlags::None, }, )); } diff --git a/src/read/traits.rs b/src/read/traits.rs index e105c115..f8443848 100644 --- a/src/read/traits.rs +++ b/src/read/traits.rs @@ -1,5 +1,7 @@ use crate::alloc::borrow::Cow; -use crate::{Relocation, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap}; +use crate::{ + FileFlags, Relocation, SectionFlags, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap, +}; use target_lexicon::{Architecture, Endianness}; use uuid::Uuid; @@ -135,6 +137,9 @@ pub trait Object<'data, 'file> { fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> { None } + + /// File flags that are specific to each file format. + fn flags(&self) -> FileFlags; } /// A loadable segment defined in an object file. @@ -217,4 +222,7 @@ pub trait ObjectSection<'data> { /// Get the relocations for this section. fn relocations(&self) -> Self::RelocationIterator; + + /// Section flags that are specific to each file format. + fn flags(&self) -> SectionFlags; } diff --git a/src/read/wasm.rs b/src/read/wasm.rs index e13343e5..99edddff 100644 --- a/src/read/wasm.rs +++ b/src/read/wasm.rs @@ -5,8 +5,8 @@ use std::{iter, slice}; use target_lexicon::Architecture; use crate::read::{ - Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol, - SymbolIndex, SymbolMap, + FileFlags, Object, ObjectSection, ObjectSegment, Relocation, SectionFlags, SectionIndex, + SectionKind, Symbol, SymbolIndex, SymbolMap, }; /// A WebAssembly object file. @@ -106,6 +106,10 @@ impl<'file> Object<'static, 'file> for WasmFile { _ => false, }) } + + fn flags(&self) -> FileFlags { + FileFlags::None + } } /// An iterator over the segments of an `WasmFile`. @@ -286,6 +290,10 @@ impl<'file> ObjectSection<'static> for WasmSection<'file> { fn relocations(&self) -> WasmRelocationIterator { WasmRelocationIterator } + + fn flags(&self) -> SectionFlags { + SectionFlags::None + } } /// An iterator over the symbols of an `WasmFile`. diff --git a/src/write/coff.rs b/src/write/coff.rs index 23077974..cf90a192 100644 --- a/src/write/coff.rs +++ b/src/write/coff.rs @@ -93,7 +93,7 @@ impl Object { Architecture::X86_64 => match relocation.kind { RelocationKind::Relative => { // IMAGE_REL_AMD64_REL32 through to IMAGE_REL_AMD64_REL32_5 - if relocation.addend >= -4 && relocation.addend <= -9 { + if relocation.addend <= -4 && relocation.addend >= -9 { 0 } else { relocation.addend + 4 @@ -137,6 +137,7 @@ impl Object { scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Section(section_id), + flags: SymbolFlags::None, }); self.stub_symbols.insert(symbol_id, stub_id); @@ -240,14 +241,22 @@ impl Object { pointer_to_symbol_table: symtab_offset as u32, number_of_symbol_table: symtab_count as u32, size_of_optional_header: 0, - characteristics: 0, + characteristics: match self.flags { + FileFlags::Coff { characteristics } => characteristics, + _ => 0, + }, }; buffer.iowrite_with(header, ctx).unwrap(); // Write section headers. for (index, section) in self.sections.iter().enumerate() { // TODO: IMAGE_SCN_LNK_COMDAT - let characteristics = match section.kind { + let characteristics = match section.flags { + SectionFlags::Coff { + characteristics, .. + } => characteristics, + _ => 0, + } | match section.kind { SectionKind::Text => { coff::IMAGE_SCN_CNT_CODE | coff::IMAGE_SCN_MEM_EXECUTE @@ -280,8 +289,7 @@ impl Object { | SectionKind::Metadata => { return Err(format!("unimplemented section {:?}", section.kind)) } - }; - let align = match section.align { + } | match section.align { 1 => coff::IMAGE_SCN_ALIGN_1BYTES, 2 => coff::IMAGE_SCN_ALIGN_2BYTES, 4 => coff::IMAGE_SCN_ALIGN_4BYTES, @@ -301,13 +309,9 @@ impl Object { let mut coff_section = coff::SectionTable { name: [0; 8], real_name: None, - virtual_size: if section.data.is_empty() { - section.size as u32 - } else { - 0 - }, + virtual_size: 0, virtual_address: 0, - size_of_raw_data: section.data.len() as u32, + size_of_raw_data: section.size as u32, pointer_to_raw_data: if section.data.is_empty() { 0 } else { @@ -317,7 +321,7 @@ impl Object { pointer_to_linenumbers: 0, number_of_relocations: section.relocations.len() as u16, number_of_linenumbers: 0, - characteristics: characteristics | align, + characteristics, }; if section.name.len() <= 8 { coff_section.name[..section.name.len()].copy_from_slice(§ion.name); @@ -463,6 +467,7 @@ impl Object { } buffer.iowrite_with(coff_symbol, ctx).unwrap(); + // Write auxiliary symbols. match symbol.kind { SymbolKind::File => { let aux_len = number_of_aux_symbols as usize * coff::COFF_SYMBOL_SIZE; @@ -473,17 +478,22 @@ impl Object { SymbolKind::Section => { debug_assert_eq!(number_of_aux_symbols, 1); let section = &self.sections[symbol.section.id().unwrap().0]; + let (selection, number) = match symbol.flags { + SymbolFlags::CoffSection { + selection, + associative_section, + } => (selection, associative_section.0 as u16), + _ => (0, 0), + }; buffer .iowrite_with( coff::AuxSectionDefinition { - length: section.data.len() as u32, + length: section.size as u32, number_of_relocations: section.relocations.len() as u16, number_of_line_numbers: 0, checksum: checksum(§ion.data), - // TODO: only for COMDAT - number: section_number as u16, - // TODO: COMDAT - selection: 0, + number, + selection, unused: [0; 3], }, ctx, diff --git a/src/write/elf.rs b/src/write/elf.rs index d302eef4..60da0384 100644 --- a/src/write/elf.rs +++ b/src/write/elf.rs @@ -318,6 +318,11 @@ impl Object { )) } }; + let e_flags = if let FileFlags::Elf { e_flags } = self.flags { + e_flags + } else { + 0 + }; let mut header = elf::Header { e_ident: [0; 16], e_type: elf::ET_REL, @@ -326,7 +331,7 @@ impl Object { e_entry: 0, e_phoff: 0, e_shoff: e_shoff as u64, - e_flags: 0, + e_flags, e_ehsize: e_ehsize as u16, e_phentsize: 0, e_phnum: 0, @@ -389,39 +394,46 @@ impl Object { symtab_shndx.iowrite_with(0, ctx.le).unwrap(); } let mut write_symbol = |index: usize, symbol: &Symbol| { - let st_type = match symbol.kind { - SymbolKind::Unknown | SymbolKind::Null => elf::STT_NOTYPE, - SymbolKind::Text => { - if symbol.is_undefined() { - elf::STT_NOTYPE - } else { - elf::STT_FUNC + let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags { + st_info + } else { + let st_type = match symbol.kind { + SymbolKind::Unknown | SymbolKind::Null => elf::STT_NOTYPE, + SymbolKind::Text => { + if symbol.is_undefined() { + elf::STT_NOTYPE + } else { + elf::STT_FUNC + } } - } - SymbolKind::Data => { - if symbol.is_undefined() { - elf::STT_NOTYPE - } else if symbol.is_common() { - elf::STT_COMMON - } else { - elf::STT_OBJECT + SymbolKind::Data => { + if symbol.is_undefined() { + elf::STT_NOTYPE + } else if symbol.is_common() { + elf::STT_COMMON + } else { + elf::STT_OBJECT + } } - } - SymbolKind::Section => elf::STT_SECTION, - SymbolKind::File => elf::STT_FILE, - SymbolKind::Tls => elf::STT_TLS, - SymbolKind::Label => elf::STT_NOTYPE, - }; - let st_bind = if symbol.is_undefined() { - elf::STB_GLOBAL - } else if symbol.is_local() { - elf::STB_LOCAL - } else if symbol.weak { - elf::STB_WEAK - } else { - elf::STB_GLOBAL + SymbolKind::Section => elf::STT_SECTION, + SymbolKind::File => elf::STT_FILE, + SymbolKind::Tls => elf::STT_TLS, + SymbolKind::Label => elf::STT_NOTYPE, + }; + let st_bind = if symbol.is_undefined() { + elf::STB_GLOBAL + } else if symbol.is_local() { + elf::STB_LOCAL + } else if symbol.weak { + elf::STB_WEAK + } else { + elf::STB_GLOBAL + }; + (st_bind << 4) + st_type }; - let st_other = if symbol.scope == SymbolScope::Linkage { + let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags { + st_other + } else if symbol.scope == SymbolScope::Linkage { elf::STV_HIDDEN } else { elf::STV_DEFAULT @@ -455,7 +467,7 @@ impl Object { .iowrite_with( elf::Sym { st_name, - st_info: (st_bind << 4) + st_type, + st_info, st_other, st_shndx: st_shndx as usize, st_value: symbol.value, @@ -591,23 +603,30 @@ impl Object { SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS, _ => elf::SHT_PROGBITS, }; - let sh_flags = match section.kind { - SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR, - SectionKind::Data => elf::SHF_ALLOC | elf::SHF_WRITE, - SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, - SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE, - SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, - SectionKind::ReadOnlyData => elf::SHF_ALLOC, - SectionKind::ReadOnlyString => elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE, - SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE, - SectionKind::Other - | SectionKind::Debug - | SectionKind::Unknown - | SectionKind::Metadata - | SectionKind::Linker => 0, - SectionKind::Common | SectionKind::TlsVariables => { - return Err(format!("unimplemented section {:?}", section.kind)) + let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags { + sh_flags + } else { + match section.kind { + SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR, + SectionKind::Data => elf::SHF_ALLOC | elf::SHF_WRITE, + SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, + SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE, + SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, + SectionKind::ReadOnlyData => elf::SHF_ALLOC, + SectionKind::ReadOnlyString => { + elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE + } + SectionKind::OtherString => elf::SHF_STRINGS | elf::SHF_MERGE, + SectionKind::Other + | SectionKind::Debug + | SectionKind::Unknown + | SectionKind::Metadata + | SectionKind::Linker => 0, + SectionKind::Common | SectionKind::TlsVariables => { + return Err(format!("unimplemented section {:?}", section.kind)) + } } + .into() }; // TODO: not sure if this is correct, maybe user should determine this let sh_entsize = match section.kind { @@ -623,7 +642,7 @@ impl Object { elf::SectionHeader { sh_name, sh_type, - sh_flags: sh_flags.into(), + sh_flags, sh_addr: 0, sh_offset: section_offsets[index].offset as u64, sh_size: section.size, diff --git a/src/write/macho.rs b/src/write/macho.rs index 93f312ec..2d0254ca 100644 --- a/src/write/macho.rs +++ b/src/write/macho.rs @@ -32,6 +32,16 @@ struct SymbolOffsets { } impl Object { + pub(crate) fn macho_set_subsections_via_symbols(&mut self) { + let flags = match self.flags { + FileFlags::MachO { flags } => flags, + _ => 0, + }; + self.flags = FileFlags::MachO { + flags: flags | mach::MH_SUBSECTIONS_VIA_SYMBOLS, + }; + } + pub(crate) fn macho_segment_name(&self, segment: StandardSegment) -> &'static [u8] { match segment { StandardSegment::Text => &b"__TEXT"[..], @@ -90,6 +100,7 @@ impl Object { scope: SymbolScope::Dynamic, weak: false, section: SymbolSection::Undefined, + flags: SymbolFlags::None, }); self.tlv_bootstrap = Some(id); id @@ -122,6 +133,7 @@ impl Object { scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Undefined, + flags: SymbolFlags::None, }); // Add the tlv entry. @@ -308,6 +320,10 @@ impl Object { } }; + let flags = match self.flags { + FileFlags::MachO { flags } => flags, + _ => 0, + }; let header = mach::Header { magic: if ctx.is_big() { mach::MH_MAGIC_64 @@ -319,11 +335,7 @@ impl Object { filetype: mach::MH_OBJECT, ncmds, sizeofcmds: sizeofcmds as u32, - flags: if self.subsection_via_symbols { - mach::MH_SUBSECTIONS_VIA_SYMBOLS - } else { - 0 - }, + flags, reserved: 0, }; buffer.iowrite_with(header, ctx).unwrap(); @@ -354,23 +366,27 @@ impl Object { sectname.pwrite(&*section.name, 0).unwrap(); let mut segname = [0; 16]; segname.pwrite(&*section.segment, 0).unwrap(); - let flags = match section.kind { - SectionKind::Text => { - mach::S_ATTR_PURE_INSTRUCTIONS | mach::S_ATTR_SOME_INSTRUCTIONS + let flags = if let SectionFlags::MachO { flags } = section.flags { + flags + } else { + match section.kind { + SectionKind::Text => { + mach::S_ATTR_PURE_INSTRUCTIONS | mach::S_ATTR_SOME_INSTRUCTIONS + } + SectionKind::Data => 0, + SectionKind::ReadOnlyData => 0, + SectionKind::ReadOnlyString => mach::S_CSTRING_LITERALS, + SectionKind::UninitializedData | SectionKind::Common => mach::S_ZEROFILL, + SectionKind::Tls => mach::S_THREAD_LOCAL_REGULAR, + SectionKind::UninitializedTls => mach::S_THREAD_LOCAL_ZEROFILL, + SectionKind::TlsVariables => mach::S_THREAD_LOCAL_VARIABLES, + SectionKind::Debug => mach::S_ATTR_DEBUG, + SectionKind::OtherString => mach::S_CSTRING_LITERALS, + SectionKind::Other + | SectionKind::Unknown + | SectionKind::Linker + | SectionKind::Metadata => 0, } - SectionKind::Data => 0, - SectionKind::ReadOnlyData => 0, - SectionKind::ReadOnlyString => mach::S_CSTRING_LITERALS, - SectionKind::UninitializedData | SectionKind::Common => mach::S_ZEROFILL, - SectionKind::Tls => mach::S_THREAD_LOCAL_REGULAR, - SectionKind::UninitializedTls => mach::S_THREAD_LOCAL_ZEROFILL, - SectionKind::TlsVariables => mach::S_THREAD_LOCAL_VARIABLES, - SectionKind::Debug => mach::S_ATTR_DEBUG, - SectionKind::OtherString => mach::S_CSTRING_LITERALS, - SectionKind::Other - | SectionKind::Unknown - | SectionKind::Linker - | SectionKind::Metadata => 0, }; buffer .iowrite_with( @@ -447,14 +463,19 @@ impl Object { } } - let mut n_desc = 0; - if symbol.weak { - if symbol.is_undefined() { - n_desc |= mach::N_WEAK_REF; - } else { - n_desc |= mach::N_WEAK_DEF; + let n_desc = if let SymbolFlags::MachO { n_desc } = symbol.flags { + n_desc + } else { + let mut n_desc = 0; + if symbol.weak { + if symbol.is_undefined() { + n_desc |= mach::N_WEAK_REF; + } else { + n_desc |= mach::N_WEAK_DEF; + } } - } + n_desc + }; let n_value = match symbol.section.id() { Some(section) => section_offsets[section.0].address + symbol.value, diff --git a/src/write/mod.rs b/src/write/mod.rs index bc2a492f..e75096b2 100644 --- a/src/write/mod.rs +++ b/src/write/mod.rs @@ -10,7 +10,10 @@ use std::string::String; use crate::alloc::vec::Vec; use crate::target_lexicon::{Architecture, BinaryFormat, Endianness, PointerWidth}; -use crate::{RelocationEncoding, RelocationKind, SectionKind, SymbolKind, SymbolScope}; +use crate::{ + FileFlags, RelocationEncoding, RelocationKind, SectionFlags, SectionKind, SymbolFlags, + SymbolKind, SymbolScope, +}; mod coff; mod elf; @@ -28,7 +31,8 @@ pub struct Object { symbols: Vec, symbol_map: HashMap, SymbolId>, stub_symbols: HashMap, - subsection_via_symbols: bool, + /// File flags that are specific to each file format. + pub flags: FileFlags, /// The symbol name mangling scheme. pub mangling: Mangling, /// Mach-O "_tlv_bootstrap" symbol. @@ -46,7 +50,7 @@ impl Object { symbols: Vec::new(), symbol_map: HashMap::new(), stub_symbols: HashMap::new(), - subsection_via_symbols: false, + flags: FileFlags::None, mangling: Mangling::default(format, architecture), tlv_bootstrap: None, } @@ -136,6 +140,7 @@ impl Object { data: Vec::new(), relocations: Vec::new(), symbol: None, + flags: SectionFlags::None, }); // Add to self.standard_sections if required. This may match multiple standard sections. @@ -172,8 +177,8 @@ impl Object { data: &[u8], align: u64, ) -> (SectionId, u64) { - let section_id = if self.has_subsection_via_symbols() { - self.subsection_via_symbols = true; + let section_id = if self.has_subsections_via_symbols() { + self.set_subsections_via_symbols(); self.section_id(section) } else { let (segment, name, kind) = self.subsection_info(section, name); @@ -183,7 +188,7 @@ impl Object { (section_id, offset) } - fn has_subsection_via_symbols(&self) -> bool { + fn has_subsections_via_symbols(&self) -> bool { match self.format { BinaryFormat::Elf | BinaryFormat::Coff => false, BinaryFormat::Macho => true, @@ -191,6 +196,13 @@ impl Object { } } + fn set_subsections_via_symbols(&mut self) { + match self.format { + BinaryFormat::Macho => self.macho_set_subsections_via_symbols(), + _ => unimplemented!(), + } + } + fn subsection_info( &self, section: StandardSection, @@ -202,7 +214,7 @@ impl Object { } fn subsection_name(&self, section: &[u8], value: &[u8]) -> Vec { - debug_assert!(!self.has_subsection_via_symbols()); + debug_assert!(!self.has_subsections_via_symbols()); match self.format { BinaryFormat::Elf => self.elf_subsection_name(section, value), BinaryFormat::Coff => self.coff_subsection_name(section, value), @@ -232,7 +244,13 @@ impl Object { // Defined symbols must have a scope. debug_assert!(symbol.is_undefined() || symbol.scope != SymbolScope::Unknown); if symbol.kind == SymbolKind::Section { - return self.section_symbol(symbol.section.id().unwrap()); + // There can only be one section symbol, but update its flags, since + // the automatically generated section symbol will have none. + let symbol_id = self.section_symbol(symbol.section.id().unwrap()); + if symbol.flags != SymbolFlags::None { + self.symbol_mut(symbol_id).flags = symbol.flags; + } + return symbol_id; } if !symbol.name.is_empty() && (symbol.kind == SymbolKind::Text @@ -295,6 +313,7 @@ impl Object { scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Undefined, + flags: SymbolFlags::None, }) } @@ -318,6 +337,7 @@ impl Object { scope: SymbolScope::Compilation, weak: false, section: SymbolSection::Section(section_id), + flags: SymbolFlags::None, }); section.symbol = Some(symbol_id); symbol_id @@ -543,6 +563,8 @@ pub struct Section { data: Vec, relocations: Vec, symbol: Option, + /// Section flags that are specific to each file format. + pub flags: SectionFlags, } impl Section { @@ -653,6 +675,8 @@ pub struct Symbol { pub weak: bool, /// The section containing the symbol. pub section: SymbolSection, + /// Symbol flags that are specific to each file format. + pub flags: SymbolFlags, } impl Symbol { diff --git a/tests/bss.rs b/tests/bss.rs new file mode 100644 index 00000000..ad952348 --- /dev/null +++ b/tests/bss.rs @@ -0,0 +1,254 @@ +#![cfg(all(feature = "read", feature = "write"))] + +use object::read::{Object, ObjectSection}; +use object::{read, write}; +use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope}; +use target_lexicon::{Architecture, BinaryFormat}; + +#[test] +fn coff_x86_64_bss() { + let mut object = write::Object::new(BinaryFormat::Coff, Architecture::X86_64); + + let section = object.section_id(write::StandardSection::UninitializedData); + + let symbol = object.add_symbol(write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 18, 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 34, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"bss.o", &bytes).unwrap(); + + let object = read::File::parse(&bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Coff); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let bss = sections.next().unwrap(); + println!("{:?}", bss); + let bss_index = bss.index(); + assert_eq!(bss.name(), Some(".bss")); + assert_eq!(bss.kind(), SectionKind::UninitializedData); + assert_eq!(bss.size(), 58); + assert_eq!(&*bss.data(), &[]); + + let section = sections.next(); + assert!( + section.is_none(), + format!("unexpected section {:?}", section) + ); + + let mut symbols = object.symbols(); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 0); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 24); + + let symbol = symbols.next(); + assert!(symbol.is_none(), format!("unexpected symbol {:?}", symbol)); +} + +#[test] +fn elf_x86_64_bss() { + let mut object = write::Object::new(BinaryFormat::Elf, Architecture::X86_64); + + let section = object.section_id(write::StandardSection::UninitializedData); + + let symbol = object.add_symbol(write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 18, 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 34, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"bss.o", &bytes).unwrap(); + + let object = read::File::parse(&bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Elf); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let section = sections.next().unwrap(); + println!("{:?}", section); + assert_eq!(section.name(), Some("")); + assert_eq!(section.kind(), SectionKind::Metadata); + assert_eq!(section.address(), 0); + assert_eq!(section.size(), 0); + + let bss = sections.next().unwrap(); + println!("{:?}", bss); + let bss_index = bss.index(); + assert_eq!(bss.name(), Some(".bss")); + assert_eq!(bss.kind(), SectionKind::UninitializedData); + assert_eq!(bss.size(), 58); + assert_eq!(&*bss.data(), &[]); + + let mut symbols = object.symbols(); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("")); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 0); + assert_eq!(symbol.size(), 18); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 24); + assert_eq!(symbol.size(), 34); + + let symbol = symbols.next(); + assert!(symbol.is_none(), format!("unexpected symbol {:?}", symbol)); +} + +#[test] +fn macho_x86_64_bss() { + let mut object = write::Object::new(BinaryFormat::Macho, Architecture::X86_64); + + let section = object.section_id(write::StandardSection::UninitializedData); + + let symbol = object.add_symbol(write::Symbol { + name: b"v1".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 18, 4); + + let symbol = object.add_symbol(write::Symbol { + name: b"v2".to_vec(), + value: 0, + size: 0, + kind: SymbolKind::Data, + scope: SymbolScope::Linkage, + weak: false, + section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, + }); + object.add_symbol_bss(symbol, section, 34, 8); + + let bytes = object.write().unwrap(); + + //std::fs::write(&"bss.o", &bytes).unwrap(); + + let object = read::File::parse(&bytes).unwrap(); + assert_eq!(object.format(), BinaryFormat::Macho); + assert_eq!(object.architecture(), Architecture::X86_64); + + let mut sections = object.sections(); + + let bss = sections.next().unwrap(); + println!("{:?}", bss); + let bss_index = bss.index(); + assert_eq!(bss.name(), Some("__bss")); + assert_eq!(bss.segment_name(), Some("__DATA")); + assert_eq!(bss.kind(), SectionKind::UninitializedData); + assert_eq!(bss.size(), 58); + assert_eq!(&*bss.data(), &[]); + + let section = sections.next(); + assert!( + section.is_none(), + format!("unexpected section {:?}", section) + ); + + let mut symbols = object.symbols(); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("_v1")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 0); + + let (_, symbol) = symbols.next().unwrap(); + println!("{:?}", symbol); + assert_eq!(symbol.name(), Some("_v2")); + assert_eq!(symbol.kind(), SymbolKind::Data); + assert_eq!(symbol.section_index(), Some(bss_index)); + assert_eq!(symbol.scope(), SymbolScope::Linkage); + assert_eq!(symbol.is_weak(), false); + assert_eq!(symbol.is_undefined(), false); + assert_eq!(symbol.address(), 24); + + let symbol = symbols.next(); + assert!(symbol.is_none(), format!("unexpected symbol {:?}", symbol)); +} diff --git a/tests/common.rs b/tests/common.rs index d6877881..61ff751c 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -2,7 +2,7 @@ use object::read::{Object, ObjectSection}; use object::{read, write}; -use object::{SectionKind, SymbolKind, SymbolScope}; +use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope}; use target_lexicon::{Architecture, BinaryFormat}; #[test] @@ -17,6 +17,7 @@ fn coff_x86_64_common() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }; object.add_common_symbol(symbol, 4, 4); @@ -28,6 +29,7 @@ fn coff_x86_64_common() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }; object.add_common_symbol(symbol, 8, 8); @@ -79,6 +81,7 @@ fn elf_x86_64_common() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }; object.add_common_symbol(symbol, 4, 4); @@ -90,6 +93,7 @@ fn elf_x86_64_common() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }; object.add_common_symbol(symbol, 8, 8); @@ -145,6 +149,7 @@ fn macho_x86_64_common() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }; object.add_common_symbol(symbol, 4, 4); @@ -156,6 +161,7 @@ fn macho_x86_64_common() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }; object.add_common_symbol(symbol, 8, 8); diff --git a/tests/round_trip.rs b/tests/round_trip.rs index 1de8c41b..f73441e6 100644 --- a/tests/round_trip.rs +++ b/tests/round_trip.rs @@ -2,7 +2,9 @@ use object::read::{Object, ObjectSection}; use object::{read, write}; -use object::{RelocationEncoding, RelocationKind, SectionKind, SymbolKind, SymbolScope}; +use object::{ + RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind, SymbolScope, +}; use target_lexicon::{Architecture, BinaryFormat}; #[test] @@ -22,6 +24,7 @@ fn coff_x86_64() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, }); object .add_relocation( @@ -98,6 +101,7 @@ fn elf_x86_64() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, }); object .add_relocation( @@ -191,6 +195,7 @@ fn macho_x86_64() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Section(text), + flags: SymbolFlags::None, }); object .add_relocation( diff --git a/tests/tls.rs b/tests/tls.rs index 8d5a5489..0342da36 100644 --- a/tests/tls.rs +++ b/tests/tls.rs @@ -2,7 +2,9 @@ use object::read::{Object, ObjectSection}; use object::{read, write}; -use object::{RelocationEncoding, RelocationKind, SectionKind, SymbolKind, SymbolScope}; +use object::{ + RelocationEncoding, RelocationKind, SectionKind, SymbolFlags, SymbolKind, SymbolScope, +}; use target_lexicon::{Architecture, BinaryFormat}; #[test] @@ -18,6 +20,7 @@ fn macho_x86_64_tls() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }); object.add_symbol_data(symbol, section, &[1; 30], 4); @@ -30,6 +33,7 @@ fn macho_x86_64_tls() { scope: SymbolScope::Linkage, weak: false, section: write::SymbolSection::Undefined, + flags: SymbolFlags::None, }); object.add_symbol_bss(symbol, section, 31, 4);