| 1 | use alloc::vec::Vec; |
| 2 | |
| 3 | use crate::pe as coff; |
| 4 | use crate::write::coff::writer; |
| 5 | use crate::write::util::*; |
| 6 | use crate::write::*; |
| 7 | |
| 8 | #[derive (Default, Clone, Copy)] |
| 9 | struct SectionOffsets { |
| 10 | name: writer::Name, |
| 11 | offset: u32, |
| 12 | reloc_offset: u32, |
| 13 | selection: u8, |
| 14 | associative_section: u32, |
| 15 | } |
| 16 | |
| 17 | #[derive (Default, Clone, Copy)] |
| 18 | struct SymbolOffsets { |
| 19 | name: writer::Name, |
| 20 | index: u32, |
| 21 | aux_count: u8, |
| 22 | } |
| 23 | |
| 24 | /// Internal format to use for the `.drectve` section containing linker |
| 25 | /// directives for symbol exports. |
| 26 | #[derive (Clone, Copy, Debug, PartialEq, Eq)] |
| 27 | pub enum CoffExportStyle { |
| 28 | /// MSVC format supported by link.exe and LLD. |
| 29 | Msvc, |
| 30 | /// Gnu format supported by GNU LD and LLD. |
| 31 | Gnu, |
| 32 | } |
| 33 | |
| 34 | impl<'a> Object<'a> { |
| 35 | pub(crate) fn coff_section_info( |
| 36 | &self, |
| 37 | section: StandardSection, |
| 38 | ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { |
| 39 | match section { |
| 40 | StandardSection::Text => (&[], &b".text" [..], SectionKind::Text, SectionFlags::None), |
| 41 | StandardSection::Data => (&[], &b".data" [..], SectionKind::Data, SectionFlags::None), |
| 42 | StandardSection::ReadOnlyData |
| 43 | | StandardSection::ReadOnlyDataWithRel |
| 44 | | StandardSection::ReadOnlyString => ( |
| 45 | &[], |
| 46 | &b".rdata" [..], |
| 47 | SectionKind::ReadOnlyData, |
| 48 | SectionFlags::None, |
| 49 | ), |
| 50 | StandardSection::UninitializedData => ( |
| 51 | &[], |
| 52 | &b".bss" [..], |
| 53 | SectionKind::UninitializedData, |
| 54 | SectionFlags::None, |
| 55 | ), |
| 56 | // TLS sections are data sections with a special name. |
| 57 | StandardSection::Tls => (&[], &b".tls$" [..], SectionKind::Data, SectionFlags::None), |
| 58 | StandardSection::UninitializedTls => { |
| 59 | // Unsupported section. |
| 60 | (&[], &[], SectionKind::UninitializedTls, SectionFlags::None) |
| 61 | } |
| 62 | StandardSection::TlsVariables => { |
| 63 | // Unsupported section. |
| 64 | (&[], &[], SectionKind::TlsVariables, SectionFlags::None) |
| 65 | } |
| 66 | StandardSection::Common => { |
| 67 | // Unsupported section. |
| 68 | (&[], &[], SectionKind::Common, SectionFlags::None) |
| 69 | } |
| 70 | StandardSection::GnuProperty => { |
| 71 | // Unsupported section. |
| 72 | (&[], &[], SectionKind::Note, SectionFlags::None) |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | pub(crate) fn coff_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> { |
| 78 | let mut name = section.to_vec(); |
| 79 | if !value.is_empty() { |
| 80 | name.push(b'$' ); |
| 81 | name.extend_from_slice(value); |
| 82 | } |
| 83 | name |
| 84 | } |
| 85 | |
| 86 | pub(crate) fn coff_translate_relocation(&mut self, reloc: &mut Relocation) -> Result<()> { |
| 87 | use RelocationEncoding as E; |
| 88 | use RelocationKind as K; |
| 89 | |
| 90 | let (mut kind, encoding, size) = if let RelocationFlags::Generic { |
| 91 | kind, |
| 92 | encoding, |
| 93 | size, |
| 94 | } = reloc.flags |
| 95 | { |
| 96 | (kind, encoding, size) |
| 97 | } else { |
| 98 | return Ok(()); |
| 99 | }; |
| 100 | if kind == K::GotRelative { |
| 101 | // Use a stub symbol for the relocation instead. |
| 102 | // This isn't really a GOT, but it's a similar purpose. |
| 103 | // TODO: need to handle DLL imports differently? |
| 104 | kind = K::Relative; |
| 105 | reloc.symbol = self.coff_add_stub_symbol(reloc.symbol)?; |
| 106 | } else if kind == K::PltRelative { |
| 107 | // Windows doesn't need a separate relocation type for |
| 108 | // references to functions in import libraries. |
| 109 | // For convenience, treat this the same as Relative. |
| 110 | kind = K::Relative; |
| 111 | } |
| 112 | |
| 113 | let unsupported_reloc = || Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
| 114 | let typ = match self.architecture { |
| 115 | Architecture::I386 => match (kind, size) { |
| 116 | (K::Absolute, 16) => coff::IMAGE_REL_I386_DIR16, |
| 117 | (K::Relative, 16) => coff::IMAGE_REL_I386_REL16, |
| 118 | (K::Absolute, 32) => coff::IMAGE_REL_I386_DIR32, |
| 119 | (K::ImageOffset, 32) => coff::IMAGE_REL_I386_DIR32NB, |
| 120 | (K::SectionIndex, 16) => coff::IMAGE_REL_I386_SECTION, |
| 121 | (K::SectionOffset, 32) => coff::IMAGE_REL_I386_SECREL, |
| 122 | (K::SectionOffset, 7) => coff::IMAGE_REL_I386_SECREL7, |
| 123 | (K::Relative, 32) => coff::IMAGE_REL_I386_REL32, |
| 124 | _ => return unsupported_reloc(), |
| 125 | }, |
| 126 | Architecture::X86_64 => match (kind, size) { |
| 127 | (K::Absolute, 64) => coff::IMAGE_REL_AMD64_ADDR64, |
| 128 | (K::Absolute, 32) => coff::IMAGE_REL_AMD64_ADDR32, |
| 129 | (K::ImageOffset, 32) => coff::IMAGE_REL_AMD64_ADDR32NB, |
| 130 | (K::Relative, 32) => match reloc.addend { |
| 131 | -5 => coff::IMAGE_REL_AMD64_REL32_1, |
| 132 | -6 => coff::IMAGE_REL_AMD64_REL32_2, |
| 133 | -7 => coff::IMAGE_REL_AMD64_REL32_3, |
| 134 | -8 => coff::IMAGE_REL_AMD64_REL32_4, |
| 135 | -9 => coff::IMAGE_REL_AMD64_REL32_5, |
| 136 | _ => coff::IMAGE_REL_AMD64_REL32, |
| 137 | }, |
| 138 | (K::SectionIndex, 16) => coff::IMAGE_REL_AMD64_SECTION, |
| 139 | (K::SectionOffset, 32) => coff::IMAGE_REL_AMD64_SECREL, |
| 140 | (K::SectionOffset, 7) => coff::IMAGE_REL_AMD64_SECREL7, |
| 141 | _ => return unsupported_reloc(), |
| 142 | }, |
| 143 | Architecture::Arm => match (kind, size) { |
| 144 | (K::Absolute, 32) => coff::IMAGE_REL_ARM_ADDR32, |
| 145 | (K::ImageOffset, 32) => coff::IMAGE_REL_ARM_ADDR32NB, |
| 146 | (K::Relative, 32) => coff::IMAGE_REL_ARM_REL32, |
| 147 | (K::SectionIndex, 16) => coff::IMAGE_REL_ARM_SECTION, |
| 148 | (K::SectionOffset, 32) => coff::IMAGE_REL_ARM_SECREL, |
| 149 | _ => return unsupported_reloc(), |
| 150 | }, |
| 151 | Architecture::Aarch64 => match (kind, encoding, size) { |
| 152 | (K::Absolute, _, 32) => coff::IMAGE_REL_ARM64_ADDR32, |
| 153 | (K::ImageOffset, _, 32) => coff::IMAGE_REL_ARM64_ADDR32NB, |
| 154 | (K::SectionIndex, _, 16) => coff::IMAGE_REL_ARM64_SECTION, |
| 155 | (K::SectionOffset, _, 32) => coff::IMAGE_REL_ARM64_SECREL, |
| 156 | (K::Absolute, _, 64) => coff::IMAGE_REL_ARM64_ADDR64, |
| 157 | (K::Relative, _, 32) => coff::IMAGE_REL_ARM64_REL32, |
| 158 | (K::Relative, E::AArch64Call, 26) => coff::IMAGE_REL_ARM64_BRANCH26, |
| 159 | _ => return unsupported_reloc(), |
| 160 | }, |
| 161 | _ => { |
| 162 | return Err(Error(format!( |
| 163 | "unimplemented architecture {:?}" , |
| 164 | self.architecture |
| 165 | ))); |
| 166 | } |
| 167 | }; |
| 168 | reloc.flags = RelocationFlags::Coff { typ }; |
| 169 | Ok(()) |
| 170 | } |
| 171 | |
| 172 | pub(crate) fn coff_adjust_addend(&self, relocation: &mut Relocation) -> Result<bool> { |
| 173 | let typ = if let RelocationFlags::Coff { typ } = relocation.flags { |
| 174 | typ |
| 175 | } else { |
| 176 | return Err(Error(format!("invalid relocation flags {:?}" , relocation))); |
| 177 | }; |
| 178 | let offset = match self.architecture { |
| 179 | Architecture::Arm => { |
| 180 | if typ == coff::IMAGE_REL_ARM_REL32 { |
| 181 | 4 |
| 182 | } else { |
| 183 | 0 |
| 184 | } |
| 185 | } |
| 186 | Architecture::Aarch64 => { |
| 187 | if typ == coff::IMAGE_REL_ARM64_REL32 { |
| 188 | 4 |
| 189 | } else { |
| 190 | 0 |
| 191 | } |
| 192 | } |
| 193 | Architecture::I386 => { |
| 194 | if typ == coff::IMAGE_REL_I386_REL32 { |
| 195 | 4 |
| 196 | } else { |
| 197 | 0 |
| 198 | } |
| 199 | } |
| 200 | Architecture::X86_64 => match typ { |
| 201 | coff::IMAGE_REL_AMD64_REL32 => 4, |
| 202 | coff::IMAGE_REL_AMD64_REL32_1 => 5, |
| 203 | coff::IMAGE_REL_AMD64_REL32_2 => 6, |
| 204 | coff::IMAGE_REL_AMD64_REL32_3 => 7, |
| 205 | coff::IMAGE_REL_AMD64_REL32_4 => 8, |
| 206 | coff::IMAGE_REL_AMD64_REL32_5 => 9, |
| 207 | _ => 0, |
| 208 | }, |
| 209 | _ => return Err(Error(format!("unimplemented relocation {:?}" , relocation))), |
| 210 | }; |
| 211 | relocation.addend += offset; |
| 212 | Ok(true) |
| 213 | } |
| 214 | |
| 215 | pub(crate) fn coff_relocation_size(&self, reloc: &Relocation) -> Result<u8> { |
| 216 | let typ = if let RelocationFlags::Coff { typ } = reloc.flags { |
| 217 | typ |
| 218 | } else { |
| 219 | return Err(Error(format!("unexpected relocation for size {:?}" , reloc))); |
| 220 | }; |
| 221 | let size = match self.architecture { |
| 222 | Architecture::I386 => match typ { |
| 223 | coff::IMAGE_REL_I386_DIR16 |
| 224 | | coff::IMAGE_REL_I386_REL16 |
| 225 | | coff::IMAGE_REL_I386_SECTION => Some(16), |
| 226 | coff::IMAGE_REL_I386_DIR32 |
| 227 | | coff::IMAGE_REL_I386_DIR32NB |
| 228 | | coff::IMAGE_REL_I386_SECREL |
| 229 | | coff::IMAGE_REL_I386_TOKEN |
| 230 | | coff::IMAGE_REL_I386_REL32 => Some(32), |
| 231 | _ => None, |
| 232 | }, |
| 233 | Architecture::X86_64 => match typ { |
| 234 | coff::IMAGE_REL_AMD64_SECTION => Some(16), |
| 235 | coff::IMAGE_REL_AMD64_ADDR32 |
| 236 | | coff::IMAGE_REL_AMD64_ADDR32NB |
| 237 | | coff::IMAGE_REL_AMD64_REL32 |
| 238 | | coff::IMAGE_REL_AMD64_REL32_1 |
| 239 | | coff::IMAGE_REL_AMD64_REL32_2 |
| 240 | | coff::IMAGE_REL_AMD64_REL32_3 |
| 241 | | coff::IMAGE_REL_AMD64_REL32_4 |
| 242 | | coff::IMAGE_REL_AMD64_REL32_5 |
| 243 | | coff::IMAGE_REL_AMD64_SECREL |
| 244 | | coff::IMAGE_REL_AMD64_TOKEN => Some(32), |
| 245 | coff::IMAGE_REL_AMD64_ADDR64 => Some(64), |
| 246 | _ => None, |
| 247 | }, |
| 248 | Architecture::Arm => match typ { |
| 249 | coff::IMAGE_REL_ARM_SECTION => Some(16), |
| 250 | coff::IMAGE_REL_ARM_ADDR32 |
| 251 | | coff::IMAGE_REL_ARM_ADDR32NB |
| 252 | | coff::IMAGE_REL_ARM_TOKEN |
| 253 | | coff::IMAGE_REL_ARM_REL32 |
| 254 | | coff::IMAGE_REL_ARM_SECREL => Some(32), |
| 255 | _ => None, |
| 256 | }, |
| 257 | Architecture::Aarch64 => match typ { |
| 258 | coff::IMAGE_REL_ARM64_SECTION => Some(16), |
| 259 | coff::IMAGE_REL_ARM64_ADDR32 |
| 260 | | coff::IMAGE_REL_ARM64_ADDR32NB |
| 261 | | coff::IMAGE_REL_ARM64_SECREL |
| 262 | | coff::IMAGE_REL_ARM64_TOKEN |
| 263 | | coff::IMAGE_REL_ARM64_REL32 => Some(32), |
| 264 | coff::IMAGE_REL_ARM64_ADDR64 => Some(64), |
| 265 | _ => None, |
| 266 | }, |
| 267 | _ => None, |
| 268 | }; |
| 269 | size.ok_or_else(|| Error(format!("unsupported relocation for size {:?}" , reloc))) |
| 270 | } |
| 271 | |
| 272 | fn coff_add_stub_symbol(&mut self, symbol_id: SymbolId) -> Result<SymbolId> { |
| 273 | if let Some(stub_id) = self.stub_symbols.get(&symbol_id) { |
| 274 | return Ok(*stub_id); |
| 275 | } |
| 276 | let stub_size = self.architecture.address_size().unwrap().bytes(); |
| 277 | |
| 278 | let name = b".rdata$.refptr" .to_vec(); |
| 279 | let section_id = self.add_section(Vec::new(), name, SectionKind::ReadOnlyData); |
| 280 | let section = self.section_mut(section_id); |
| 281 | section.set_data(vec![0; stub_size as usize], u64::from(stub_size)); |
| 282 | self.add_relocation( |
| 283 | section_id, |
| 284 | Relocation { |
| 285 | offset: 0, |
| 286 | symbol: symbol_id, |
| 287 | addend: 0, |
| 288 | flags: RelocationFlags::Generic { |
| 289 | kind: RelocationKind::Absolute, |
| 290 | encoding: RelocationEncoding::Generic, |
| 291 | size: stub_size * 8, |
| 292 | }, |
| 293 | }, |
| 294 | )?; |
| 295 | |
| 296 | let mut name = b".refptr." .to_vec(); |
| 297 | name.extend_from_slice(&self.symbol(symbol_id).name); |
| 298 | let stub_id = self.add_raw_symbol(Symbol { |
| 299 | name, |
| 300 | value: 0, |
| 301 | size: u64::from(stub_size), |
| 302 | kind: SymbolKind::Data, |
| 303 | scope: SymbolScope::Compilation, |
| 304 | weak: false, |
| 305 | section: SymbolSection::Section(section_id), |
| 306 | flags: SymbolFlags::None, |
| 307 | }); |
| 308 | self.stub_symbols.insert(symbol_id, stub_id); |
| 309 | |
| 310 | Ok(stub_id) |
| 311 | } |
| 312 | |
| 313 | /// Appends linker directives to the `.drectve` section to tell the linker |
| 314 | /// to export all symbols with `SymbolScope::Dynamic`. |
| 315 | /// |
| 316 | /// This must be called after all symbols have been defined. |
| 317 | pub fn add_coff_exports(&mut self, style: CoffExportStyle) { |
| 318 | assert_eq!(self.format, BinaryFormat::Coff); |
| 319 | |
| 320 | let mut directives = vec![]; |
| 321 | for symbol in &self.symbols { |
| 322 | if symbol.scope == SymbolScope::Dynamic { |
| 323 | match style { |
| 324 | CoffExportStyle::Msvc => directives.extend(b" /EXPORT: \"" ), |
| 325 | CoffExportStyle::Gnu => directives.extend(b" -export: \"" ), |
| 326 | } |
| 327 | directives.extend(&symbol.name); |
| 328 | directives.extend(b" \"" ); |
| 329 | if symbol.kind != SymbolKind::Text { |
| 330 | match style { |
| 331 | CoffExportStyle::Msvc => directives.extend(b",DATA" ), |
| 332 | CoffExportStyle::Gnu => directives.extend(b",data" ), |
| 333 | } |
| 334 | } |
| 335 | } |
| 336 | } |
| 337 | let drectve = self.add_section(vec![], b".drectve" .to_vec(), SectionKind::Linker); |
| 338 | self.append_section_data(drectve, &directives, 1); |
| 339 | } |
| 340 | |
| 341 | pub(crate) fn coff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { |
| 342 | let mut writer = writer::Writer::new(buffer); |
| 343 | |
| 344 | // Add section strings to strtab. |
| 345 | let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; |
| 346 | for (index, section) in self.sections.iter().enumerate() { |
| 347 | section_offsets[index].name = writer.add_name(§ion.name); |
| 348 | } |
| 349 | |
| 350 | // Set COMDAT flags. |
| 351 | for comdat in &self.comdats { |
| 352 | let symbol = &self.symbols[comdat.symbol.0]; |
| 353 | let comdat_section = match symbol.section { |
| 354 | SymbolSection::Section(id) => id.0, |
| 355 | _ => { |
| 356 | return Err(Error(format!( |
| 357 | "unsupported COMDAT symbol ` {}` section {:?}" , |
| 358 | symbol.name().unwrap_or("" ), |
| 359 | symbol.section |
| 360 | ))); |
| 361 | } |
| 362 | }; |
| 363 | section_offsets[comdat_section].selection = match comdat.kind { |
| 364 | ComdatKind::NoDuplicates => coff::IMAGE_COMDAT_SELECT_NODUPLICATES, |
| 365 | ComdatKind::Any => coff::IMAGE_COMDAT_SELECT_ANY, |
| 366 | ComdatKind::SameSize => coff::IMAGE_COMDAT_SELECT_SAME_SIZE, |
| 367 | ComdatKind::ExactMatch => coff::IMAGE_COMDAT_SELECT_EXACT_MATCH, |
| 368 | ComdatKind::Largest => coff::IMAGE_COMDAT_SELECT_LARGEST, |
| 369 | ComdatKind::Newest => coff::IMAGE_COMDAT_SELECT_NEWEST, |
| 370 | ComdatKind::Unknown => { |
| 371 | return Err(Error(format!( |
| 372 | "unsupported COMDAT symbol ` {}` kind {:?}" , |
| 373 | symbol.name().unwrap_or("" ), |
| 374 | comdat.kind |
| 375 | ))); |
| 376 | } |
| 377 | }; |
| 378 | for id in &comdat.sections { |
| 379 | let section = &self.sections[id.0]; |
| 380 | if section.symbol.is_none() { |
| 381 | return Err(Error(format!( |
| 382 | "missing symbol for COMDAT section ` {}`" , |
| 383 | section.name().unwrap_or("" ), |
| 384 | ))); |
| 385 | } |
| 386 | if id.0 != comdat_section { |
| 387 | section_offsets[id.0].selection = coff::IMAGE_COMDAT_SELECT_ASSOCIATIVE; |
| 388 | section_offsets[id.0].associative_section = comdat_section as u32 + 1; |
| 389 | } |
| 390 | } |
| 391 | } |
| 392 | |
| 393 | // Reserve symbol indices and add symbol strings to strtab. |
| 394 | let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; |
| 395 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 396 | symbol_offsets[index].index = writer.reserve_symbol_index(); |
| 397 | let mut name = &*symbol.name; |
| 398 | match symbol.kind { |
| 399 | SymbolKind::File => { |
| 400 | // Name goes in auxiliary symbol records. |
| 401 | symbol_offsets[index].aux_count = writer.reserve_aux_file_name(&symbol.name); |
| 402 | name = b".file" ; |
| 403 | } |
| 404 | SymbolKind::Section if symbol.section.id().is_some() => { |
| 405 | symbol_offsets[index].aux_count = writer.reserve_aux_section(); |
| 406 | } |
| 407 | _ => {} |
| 408 | }; |
| 409 | symbol_offsets[index].name = writer.add_name(name); |
| 410 | } |
| 411 | |
| 412 | // Reserve file ranges. |
| 413 | writer.reserve_file_header(); |
| 414 | writer.reserve_section_headers(self.sections.len() as u16); |
| 415 | for (index, section) in self.sections.iter().enumerate() { |
| 416 | section_offsets[index].offset = writer.reserve_section(section.data.len()); |
| 417 | section_offsets[index].reloc_offset = |
| 418 | writer.reserve_relocations(section.relocations.len()); |
| 419 | } |
| 420 | writer.reserve_symtab_strtab(); |
| 421 | |
| 422 | // Start writing. |
| 423 | writer.write_file_header(writer::FileHeader { |
| 424 | machine: match (self.architecture, self.sub_architecture) { |
| 425 | (Architecture::Arm, None) => coff::IMAGE_FILE_MACHINE_ARMNT, |
| 426 | (Architecture::Aarch64, None) => coff::IMAGE_FILE_MACHINE_ARM64, |
| 427 | (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)) => { |
| 428 | coff::IMAGE_FILE_MACHINE_ARM64EC |
| 429 | } |
| 430 | (Architecture::I386, None) => coff::IMAGE_FILE_MACHINE_I386, |
| 431 | (Architecture::X86_64, None) => coff::IMAGE_FILE_MACHINE_AMD64, |
| 432 | _ => { |
| 433 | return Err(Error(format!( |
| 434 | "unimplemented architecture {:?} with sub-architecture {:?}" , |
| 435 | self.architecture, self.sub_architecture |
| 436 | ))); |
| 437 | } |
| 438 | }, |
| 439 | time_date_stamp: 0, |
| 440 | characteristics: match self.flags { |
| 441 | FileFlags::Coff { characteristics } => characteristics, |
| 442 | _ => 0, |
| 443 | }, |
| 444 | })?; |
| 445 | |
| 446 | // Write section headers. |
| 447 | for (index, section) in self.sections.iter().enumerate() { |
| 448 | let mut characteristics = if let SectionFlags::Coff { |
| 449 | characteristics, .. |
| 450 | } = section.flags |
| 451 | { |
| 452 | characteristics |
| 453 | } else { |
| 454 | match section.kind { |
| 455 | SectionKind::Text => { |
| 456 | coff::IMAGE_SCN_CNT_CODE |
| 457 | | coff::IMAGE_SCN_MEM_EXECUTE |
| 458 | | coff::IMAGE_SCN_MEM_READ |
| 459 | } |
| 460 | SectionKind::Data => { |
| 461 | coff::IMAGE_SCN_CNT_INITIALIZED_DATA |
| 462 | | coff::IMAGE_SCN_MEM_READ |
| 463 | | coff::IMAGE_SCN_MEM_WRITE |
| 464 | } |
| 465 | SectionKind::UninitializedData => { |
| 466 | coff::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
| 467 | | coff::IMAGE_SCN_MEM_READ |
| 468 | | coff::IMAGE_SCN_MEM_WRITE |
| 469 | } |
| 470 | SectionKind::ReadOnlyData |
| 471 | | SectionKind::ReadOnlyDataWithRel |
| 472 | | SectionKind::ReadOnlyString => { |
| 473 | coff::IMAGE_SCN_CNT_INITIALIZED_DATA | coff::IMAGE_SCN_MEM_READ |
| 474 | } |
| 475 | SectionKind::Debug |
| 476 | | SectionKind::DebugString |
| 477 | | SectionKind::Other |
| 478 | | SectionKind::OtherString => { |
| 479 | coff::IMAGE_SCN_CNT_INITIALIZED_DATA |
| 480 | | coff::IMAGE_SCN_MEM_READ |
| 481 | | coff::IMAGE_SCN_MEM_DISCARDABLE |
| 482 | } |
| 483 | SectionKind::Linker => coff::IMAGE_SCN_LNK_INFO | coff::IMAGE_SCN_LNK_REMOVE, |
| 484 | SectionKind::Common |
| 485 | | SectionKind::Tls |
| 486 | | SectionKind::UninitializedTls |
| 487 | | SectionKind::TlsVariables |
| 488 | | SectionKind::Note |
| 489 | | SectionKind::Unknown |
| 490 | | SectionKind::Metadata |
| 491 | | SectionKind::Elf(_) => { |
| 492 | return Err(Error(format!( |
| 493 | "unimplemented section ` {}` kind {:?}" , |
| 494 | section.name().unwrap_or("" ), |
| 495 | section.kind |
| 496 | ))); |
| 497 | } |
| 498 | } |
| 499 | }; |
| 500 | if section_offsets[index].selection != 0 { |
| 501 | characteristics |= coff::IMAGE_SCN_LNK_COMDAT; |
| 502 | }; |
| 503 | if section.relocations.len() > 0xffff { |
| 504 | characteristics |= coff::IMAGE_SCN_LNK_NRELOC_OVFL; |
| 505 | } |
| 506 | characteristics |= match section.align { |
| 507 | 1 => coff::IMAGE_SCN_ALIGN_1BYTES, |
| 508 | 2 => coff::IMAGE_SCN_ALIGN_2BYTES, |
| 509 | 4 => coff::IMAGE_SCN_ALIGN_4BYTES, |
| 510 | 8 => coff::IMAGE_SCN_ALIGN_8BYTES, |
| 511 | 16 => coff::IMAGE_SCN_ALIGN_16BYTES, |
| 512 | 32 => coff::IMAGE_SCN_ALIGN_32BYTES, |
| 513 | 64 => coff::IMAGE_SCN_ALIGN_64BYTES, |
| 514 | 128 => coff::IMAGE_SCN_ALIGN_128BYTES, |
| 515 | 256 => coff::IMAGE_SCN_ALIGN_256BYTES, |
| 516 | 512 => coff::IMAGE_SCN_ALIGN_512BYTES, |
| 517 | 1024 => coff::IMAGE_SCN_ALIGN_1024BYTES, |
| 518 | 2048 => coff::IMAGE_SCN_ALIGN_2048BYTES, |
| 519 | 4096 => coff::IMAGE_SCN_ALIGN_4096BYTES, |
| 520 | 8192 => coff::IMAGE_SCN_ALIGN_8192BYTES, |
| 521 | _ => { |
| 522 | return Err(Error(format!( |
| 523 | "unimplemented section ` {}` align {}" , |
| 524 | section.name().unwrap_or("" ), |
| 525 | section.align |
| 526 | ))); |
| 527 | } |
| 528 | }; |
| 529 | writer.write_section_header(writer::SectionHeader { |
| 530 | name: section_offsets[index].name, |
| 531 | size_of_raw_data: section.size as u32, |
| 532 | pointer_to_raw_data: section_offsets[index].offset, |
| 533 | pointer_to_relocations: section_offsets[index].reloc_offset, |
| 534 | pointer_to_linenumbers: 0, |
| 535 | number_of_relocations: section.relocations.len() as u32, |
| 536 | number_of_linenumbers: 0, |
| 537 | characteristics, |
| 538 | }); |
| 539 | } |
| 540 | |
| 541 | // Write section data and relocations. |
| 542 | for section in &self.sections { |
| 543 | writer.write_section(§ion.data); |
| 544 | |
| 545 | if !section.relocations.is_empty() { |
| 546 | //debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); |
| 547 | writer.write_relocations_count(section.relocations.len()); |
| 548 | for reloc in §ion.relocations { |
| 549 | let typ = if let RelocationFlags::Coff { typ } = reloc.flags { |
| 550 | typ |
| 551 | } else { |
| 552 | return Err(Error("invalid relocation flags" .into())); |
| 553 | }; |
| 554 | writer.write_relocation(writer::Relocation { |
| 555 | virtual_address: reloc.offset as u32, |
| 556 | symbol: symbol_offsets[reloc.symbol.0].index, |
| 557 | typ, |
| 558 | }); |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | // Write symbols. |
| 564 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 565 | let section_number = match symbol.section { |
| 566 | SymbolSection::None => { |
| 567 | debug_assert_eq!(symbol.kind, SymbolKind::File); |
| 568 | coff::IMAGE_SYM_DEBUG as u16 |
| 569 | } |
| 570 | SymbolSection::Undefined => coff::IMAGE_SYM_UNDEFINED as u16, |
| 571 | SymbolSection::Absolute => coff::IMAGE_SYM_ABSOLUTE as u16, |
| 572 | SymbolSection::Common => coff::IMAGE_SYM_UNDEFINED as u16, |
| 573 | SymbolSection::Section(id) => id.0 as u16 + 1, |
| 574 | }; |
| 575 | let typ = if symbol.kind == SymbolKind::Text { |
| 576 | coff::IMAGE_SYM_DTYPE_FUNCTION << coff::IMAGE_SYM_DTYPE_SHIFT |
| 577 | } else { |
| 578 | coff::IMAGE_SYM_TYPE_NULL |
| 579 | }; |
| 580 | let storage_class = match symbol.kind { |
| 581 | SymbolKind::File => coff::IMAGE_SYM_CLASS_FILE, |
| 582 | SymbolKind::Section => { |
| 583 | if symbol.section.id().is_some() { |
| 584 | coff::IMAGE_SYM_CLASS_STATIC |
| 585 | } else { |
| 586 | coff::IMAGE_SYM_CLASS_SECTION |
| 587 | } |
| 588 | } |
| 589 | SymbolKind::Label => coff::IMAGE_SYM_CLASS_LABEL, |
| 590 | SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => { |
| 591 | match symbol.section { |
| 592 | SymbolSection::None => { |
| 593 | return Err(Error(format!( |
| 594 | "missing section for symbol ` {}`" , |
| 595 | symbol.name().unwrap_or("" ) |
| 596 | ))); |
| 597 | } |
| 598 | SymbolSection::Undefined | SymbolSection::Common => { |
| 599 | coff::IMAGE_SYM_CLASS_EXTERNAL |
| 600 | } |
| 601 | SymbolSection::Absolute | SymbolSection::Section(_) => { |
| 602 | match symbol.scope { |
| 603 | // TODO: does this need aux symbol records too? |
| 604 | _ if symbol.weak => coff::IMAGE_SYM_CLASS_WEAK_EXTERNAL, |
| 605 | SymbolScope::Unknown => { |
| 606 | return Err(Error(format!( |
| 607 | "unimplemented symbol ` {}` scope {:?}" , |
| 608 | symbol.name().unwrap_or("" ), |
| 609 | symbol.scope |
| 610 | ))); |
| 611 | } |
| 612 | SymbolScope::Compilation => coff::IMAGE_SYM_CLASS_STATIC, |
| 613 | SymbolScope::Linkage | SymbolScope::Dynamic => { |
| 614 | coff::IMAGE_SYM_CLASS_EXTERNAL |
| 615 | } |
| 616 | } |
| 617 | } |
| 618 | } |
| 619 | } |
| 620 | SymbolKind::Unknown => { |
| 621 | return Err(Error(format!( |
| 622 | "unimplemented symbol ` {}` kind {:?}" , |
| 623 | symbol.name().unwrap_or("" ), |
| 624 | symbol.kind |
| 625 | ))); |
| 626 | } |
| 627 | }; |
| 628 | let number_of_aux_symbols = symbol_offsets[index].aux_count; |
| 629 | let value = if symbol.section == SymbolSection::Common { |
| 630 | symbol.size as u32 |
| 631 | } else { |
| 632 | symbol.value as u32 |
| 633 | }; |
| 634 | writer.write_symbol(writer::Symbol { |
| 635 | name: symbol_offsets[index].name, |
| 636 | value, |
| 637 | section_number, |
| 638 | typ, |
| 639 | storage_class, |
| 640 | number_of_aux_symbols, |
| 641 | }); |
| 642 | |
| 643 | // Write auxiliary symbols. |
| 644 | match symbol.kind { |
| 645 | SymbolKind::File => { |
| 646 | writer.write_aux_file_name(&symbol.name, number_of_aux_symbols); |
| 647 | } |
| 648 | SymbolKind::Section if symbol.section.id().is_some() => { |
| 649 | debug_assert_eq!(number_of_aux_symbols, 1); |
| 650 | let section_index = symbol.section.id().unwrap().0; |
| 651 | let section = &self.sections[section_index]; |
| 652 | writer.write_aux_section(writer::AuxSymbolSection { |
| 653 | length: section.size as u32, |
| 654 | number_of_relocations: section.relocations.len() as u32, |
| 655 | number_of_linenumbers: 0, |
| 656 | check_sum: if section.is_bss() { |
| 657 | 0 |
| 658 | } else { |
| 659 | checksum(section.data()) |
| 660 | }, |
| 661 | number: section_offsets[section_index].associative_section, |
| 662 | selection: section_offsets[section_index].selection, |
| 663 | }); |
| 664 | } |
| 665 | _ => { |
| 666 | debug_assert_eq!(number_of_aux_symbols, 0); |
| 667 | } |
| 668 | } |
| 669 | } |
| 670 | |
| 671 | writer.write_strtab(); |
| 672 | |
| 673 | debug_assert_eq!(writer.reserved_len(), writer.len()); |
| 674 | |
| 675 | Ok(()) |
| 676 | } |
| 677 | } |
| 678 | |
| 679 | // JamCRC |
| 680 | fn checksum(data: &[u8]) -> u32 { |
| 681 | let mut hasher: Hasher = crc32fast::Hasher::new_with_initial(init:0xffff_ffff); |
| 682 | hasher.update(buf:data); |
| 683 | !hasher.finalize() |
| 684 | } |
| 685 | |