| 1 | use core::mem; |
| 2 | |
| 3 | use crate::endian::{BigEndian as BE, I16, U16, U32}; |
| 4 | use crate::write::string::*; |
| 5 | use crate::write::util::*; |
| 6 | use crate::write::*; |
| 7 | |
| 8 | use crate::xcoff; |
| 9 | |
| 10 | #[derive (Default, Clone, Copy)] |
| 11 | struct SectionOffsets { |
| 12 | address: u64, |
| 13 | data_offset: usize, |
| 14 | reloc_offset: usize, |
| 15 | } |
| 16 | |
| 17 | #[derive (Default, Clone, Copy)] |
| 18 | struct SymbolOffsets { |
| 19 | index: usize, |
| 20 | str_id: Option<StringId>, |
| 21 | aux_count: u8, |
| 22 | storage_class: u8, |
| 23 | } |
| 24 | |
| 25 | impl<'a> Object<'a> { |
| 26 | pub(crate) fn xcoff_section_info( |
| 27 | &self, |
| 28 | section: StandardSection, |
| 29 | ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { |
| 30 | match section { |
| 31 | StandardSection::Text => (&[], &b".text" [..], SectionKind::Text, SectionFlags::None), |
| 32 | StandardSection::Data => (&[], &b".data" [..], SectionKind::Data, SectionFlags::None), |
| 33 | StandardSection::ReadOnlyData |
| 34 | | StandardSection::ReadOnlyDataWithRel |
| 35 | | StandardSection::ReadOnlyString => ( |
| 36 | &[], |
| 37 | &b".rdata" [..], |
| 38 | SectionKind::ReadOnlyData, |
| 39 | SectionFlags::None, |
| 40 | ), |
| 41 | StandardSection::UninitializedData => ( |
| 42 | &[], |
| 43 | &b".bss" [..], |
| 44 | SectionKind::UninitializedData, |
| 45 | SectionFlags::None, |
| 46 | ), |
| 47 | StandardSection::Tls => (&[], &b".tdata" [..], SectionKind::Tls, SectionFlags::None), |
| 48 | StandardSection::UninitializedTls => ( |
| 49 | &[], |
| 50 | &b".tbss" [..], |
| 51 | SectionKind::UninitializedTls, |
| 52 | SectionFlags::None, |
| 53 | ), |
| 54 | StandardSection::TlsVariables => { |
| 55 | // Unsupported section. |
| 56 | (&[], &[], SectionKind::TlsVariables, SectionFlags::None) |
| 57 | } |
| 58 | StandardSection::Common => { |
| 59 | // Unsupported section. |
| 60 | (&[], &[], SectionKind::Common, SectionFlags::None) |
| 61 | } |
| 62 | StandardSection::GnuProperty => { |
| 63 | // Unsupported section. |
| 64 | (&[], &[], SectionKind::Note, SectionFlags::None) |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | pub(crate) fn xcoff_translate_relocation(&mut self, reloc: &mut Relocation) -> Result<()> { |
| 70 | let (kind, _encoding, size) = if let RelocationFlags::Generic { |
| 71 | kind, |
| 72 | encoding, |
| 73 | size, |
| 74 | } = reloc.flags |
| 75 | { |
| 76 | (kind, encoding, size) |
| 77 | } else { |
| 78 | return Ok(()); |
| 79 | }; |
| 80 | |
| 81 | let r_rtype = match kind { |
| 82 | RelocationKind::Absolute => xcoff::R_POS, |
| 83 | RelocationKind::Relative => xcoff::R_REL, |
| 84 | RelocationKind::Got => xcoff::R_TOC, |
| 85 | _ => { |
| 86 | return Err(Error(format!("unimplemented relocation {:?}" , reloc))); |
| 87 | } |
| 88 | }; |
| 89 | let r_rsize = size - 1; |
| 90 | reloc.flags = RelocationFlags::Xcoff { r_rtype, r_rsize }; |
| 91 | Ok(()) |
| 92 | } |
| 93 | |
| 94 | pub(crate) fn xcoff_adjust_addend(&mut self, relocation: &mut Relocation) -> Result<bool> { |
| 95 | let r_rtype = if let RelocationFlags::Xcoff { r_rtype, .. } = relocation.flags { |
| 96 | r_rtype |
| 97 | } else { |
| 98 | return Err(Error(format!("invalid relocation flags {:?}" , relocation))); |
| 99 | }; |
| 100 | if r_rtype == xcoff::R_REL { |
| 101 | relocation.addend += 4; |
| 102 | } |
| 103 | Ok(true) |
| 104 | } |
| 105 | |
| 106 | pub(crate) fn xcoff_relocation_size(&self, reloc: &Relocation) -> Result<u8> { |
| 107 | let r_rsize = if let RelocationFlags::Xcoff { r_rsize, .. } = reloc.flags { |
| 108 | r_rsize |
| 109 | } else { |
| 110 | return Err(Error(format!("unexpected relocation {:?}" , reloc))); |
| 111 | }; |
| 112 | Ok(r_rsize + 1) |
| 113 | } |
| 114 | |
| 115 | pub(crate) fn xcoff_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { |
| 116 | let is_64 = match self.architecture.address_size().unwrap() { |
| 117 | AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, |
| 118 | AddressSize::U64 => true, |
| 119 | }; |
| 120 | |
| 121 | let (hdr_size, sechdr_size, rel_size, sym_size) = if is_64 { |
| 122 | ( |
| 123 | mem::size_of::<xcoff::FileHeader64>(), |
| 124 | mem::size_of::<xcoff::SectionHeader64>(), |
| 125 | mem::size_of::<xcoff::Rel64>(), |
| 126 | mem::size_of::<xcoff::Symbol64>(), |
| 127 | ) |
| 128 | } else { |
| 129 | ( |
| 130 | mem::size_of::<xcoff::FileHeader32>(), |
| 131 | mem::size_of::<xcoff::SectionHeader32>(), |
| 132 | mem::size_of::<xcoff::Rel32>(), |
| 133 | mem::size_of::<xcoff::Symbol32>(), |
| 134 | ) |
| 135 | }; |
| 136 | |
| 137 | // Calculate offsets and build strtab. |
| 138 | let mut offset = 0; |
| 139 | let mut strtab = StringTable::default(); |
| 140 | // We place the shared address 0 immediately after the section header table. |
| 141 | let mut address = 0; |
| 142 | |
| 143 | // XCOFF file header. |
| 144 | offset += hdr_size; |
| 145 | // Section headers. |
| 146 | offset += self.sections.len() * sechdr_size; |
| 147 | |
| 148 | // Calculate size of section data. |
| 149 | let mut section_offsets = vec![SectionOffsets::default(); self.sections.len()]; |
| 150 | for (index, section) in self.sections.iter().enumerate() { |
| 151 | let len = section.data.len(); |
| 152 | let sectype = section.kind; |
| 153 | // Section address should be 0 for all sections except the .text, .data, and .bss sections. |
| 154 | if sectype == SectionKind::Data |
| 155 | || sectype == SectionKind::Text |
| 156 | || sectype == SectionKind::UninitializedData |
| 157 | { |
| 158 | section_offsets[index].address = address as u64; |
| 159 | address += len; |
| 160 | address = align(address, 4); |
| 161 | } else { |
| 162 | section_offsets[index].address = 0; |
| 163 | } |
| 164 | if len != 0 { |
| 165 | // Set the default section alignment as 4. |
| 166 | offset = align(offset, 4); |
| 167 | section_offsets[index].data_offset = offset; |
| 168 | offset += len; |
| 169 | } else { |
| 170 | section_offsets[index].data_offset = 0; |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | // Calculate size of relocations. |
| 175 | for (index, section) in self.sections.iter().enumerate() { |
| 176 | let count = section.relocations.len(); |
| 177 | if count != 0 { |
| 178 | section_offsets[index].reloc_offset = offset; |
| 179 | offset += count * rel_size; |
| 180 | } else { |
| 181 | section_offsets[index].reloc_offset = 0; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | // Calculate size of symbols. |
| 186 | let mut file_str_id = None; |
| 187 | let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; |
| 188 | let mut symtab_count = 0; |
| 189 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 190 | symbol_offsets[index].index = symtab_count; |
| 191 | symtab_count += 1; |
| 192 | |
| 193 | let storage_class = if let SymbolFlags::Xcoff { n_sclass, .. } = symbol.flags { |
| 194 | n_sclass |
| 195 | } else { |
| 196 | match symbol.kind { |
| 197 | SymbolKind::File => xcoff::C_FILE, |
| 198 | SymbolKind::Text | SymbolKind::Data | SymbolKind::Tls => { |
| 199 | if symbol.is_local() { |
| 200 | xcoff::C_STAT |
| 201 | } else if symbol.weak { |
| 202 | xcoff::C_WEAKEXT |
| 203 | } else { |
| 204 | xcoff::C_EXT |
| 205 | } |
| 206 | } |
| 207 | SymbolKind::Section | SymbolKind::Label | SymbolKind::Unknown => { |
| 208 | return Err(Error(format!( |
| 209 | "unimplemented symbol ` {}` kind {:?}" , |
| 210 | symbol.name().unwrap_or("" ), |
| 211 | symbol.kind |
| 212 | ))); |
| 213 | } |
| 214 | } |
| 215 | }; |
| 216 | symbol_offsets[index].storage_class = storage_class; |
| 217 | |
| 218 | if storage_class == xcoff::C_FILE { |
| 219 | if is_64 && file_str_id.is_none() { |
| 220 | file_str_id = Some(strtab.add(b".file" )); |
| 221 | } |
| 222 | if symbol.name.len() > 8 { |
| 223 | symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); |
| 224 | } |
| 225 | } else if is_64 || symbol.name.len() > 8 { |
| 226 | symbol_offsets[index].str_id = Some(strtab.add(&symbol.name)); |
| 227 | } |
| 228 | |
| 229 | symbol_offsets[index].aux_count = 0; |
| 230 | match storage_class { |
| 231 | xcoff::C_FILE => { |
| 232 | symbol_offsets[index].aux_count = 1; |
| 233 | symtab_count += 1; |
| 234 | } |
| 235 | xcoff::C_EXT | xcoff::C_WEAKEXT | xcoff::C_HIDEXT => { |
| 236 | symbol_offsets[index].aux_count = 1; |
| 237 | symtab_count += 1; |
| 238 | } |
| 239 | // TODO: support auxiliary entry for other types of symbol. |
| 240 | _ => {} |
| 241 | } |
| 242 | } |
| 243 | let symtab_offset = offset; |
| 244 | let symtab_len = symtab_count * sym_size; |
| 245 | offset += symtab_len; |
| 246 | |
| 247 | // Calculate size of strtab. |
| 248 | let strtab_offset = offset; |
| 249 | let mut strtab_data = Vec::new(); |
| 250 | // First 4 bytes of strtab are the length. |
| 251 | strtab.write(4, &mut strtab_data); |
| 252 | let strtab_len = strtab_data.len() + 4; |
| 253 | offset += strtab_len; |
| 254 | |
| 255 | // Start writing. |
| 256 | buffer |
| 257 | .reserve(offset) |
| 258 | .map_err(|_| Error(String::from("Cannot allocate buffer" )))?; |
| 259 | |
| 260 | // Write file header. |
| 261 | if is_64 { |
| 262 | let header = xcoff::FileHeader64 { |
| 263 | f_magic: U16::new(BE, xcoff::MAGIC_64), |
| 264 | f_nscns: U16::new(BE, self.sections.len() as u16), |
| 265 | f_timdat: U32::new(BE, 0), |
| 266 | f_symptr: U64::new(BE, symtab_offset as u64), |
| 267 | f_nsyms: U32::new(BE, symtab_count as u32), |
| 268 | f_opthdr: U16::new(BE, 0), |
| 269 | f_flags: match self.flags { |
| 270 | FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags), |
| 271 | _ => U16::default(), |
| 272 | }, |
| 273 | }; |
| 274 | buffer.write(&header); |
| 275 | } else { |
| 276 | let header = xcoff::FileHeader32 { |
| 277 | f_magic: U16::new(BE, xcoff::MAGIC_32), |
| 278 | f_nscns: U16::new(BE, self.sections.len() as u16), |
| 279 | f_timdat: U32::new(BE, 0), |
| 280 | f_symptr: U32::new(BE, symtab_offset as u32), |
| 281 | f_nsyms: U32::new(BE, symtab_count as u32), |
| 282 | f_opthdr: U16::new(BE, 0), |
| 283 | f_flags: match self.flags { |
| 284 | FileFlags::Xcoff { f_flags } => U16::new(BE, f_flags), |
| 285 | _ => U16::default(), |
| 286 | }, |
| 287 | }; |
| 288 | buffer.write(&header); |
| 289 | } |
| 290 | |
| 291 | // Write section headers. |
| 292 | for (index, section) in self.sections.iter().enumerate() { |
| 293 | let mut sectname = [0; 8]; |
| 294 | sectname |
| 295 | .get_mut(..section.name.len()) |
| 296 | .ok_or_else(|| { |
| 297 | Error(format!( |
| 298 | "section name ` {}` is too long" , |
| 299 | section.name().unwrap_or("" ), |
| 300 | )) |
| 301 | })? |
| 302 | .copy_from_slice(§ion.name); |
| 303 | let flags = if let SectionFlags::Xcoff { s_flags } = section.flags { |
| 304 | s_flags |
| 305 | } else { |
| 306 | match section.kind { |
| 307 | SectionKind::Text |
| 308 | | SectionKind::ReadOnlyData |
| 309 | | SectionKind::ReadOnlyString |
| 310 | | SectionKind::ReadOnlyDataWithRel => xcoff::STYP_TEXT, |
| 311 | SectionKind::Data => xcoff::STYP_DATA, |
| 312 | SectionKind::UninitializedData => xcoff::STYP_BSS, |
| 313 | SectionKind::Tls => xcoff::STYP_TDATA, |
| 314 | SectionKind::UninitializedTls => xcoff::STYP_TBSS, |
| 315 | SectionKind::OtherString => xcoff::STYP_INFO, |
| 316 | SectionKind::Debug | SectionKind::DebugString => xcoff::STYP_DEBUG, |
| 317 | SectionKind::Other | SectionKind::Metadata => 0, |
| 318 | SectionKind::Note |
| 319 | | SectionKind::Linker |
| 320 | | SectionKind::Common |
| 321 | | SectionKind::Unknown |
| 322 | | SectionKind::TlsVariables |
| 323 | | SectionKind::Elf(_) => { |
| 324 | return Err(Error(format!( |
| 325 | "unimplemented section ` {}` kind {:?}" , |
| 326 | section.name().unwrap_or("" ), |
| 327 | section.kind |
| 328 | ))); |
| 329 | } |
| 330 | } |
| 331 | .into() |
| 332 | }; |
| 333 | if is_64 { |
| 334 | let section_header = xcoff::SectionHeader64 { |
| 335 | s_name: sectname, |
| 336 | s_paddr: U64::new(BE, section_offsets[index].address), |
| 337 | // This field has the same value as the s_paddr field. |
| 338 | s_vaddr: U64::new(BE, section_offsets[index].address), |
| 339 | s_size: U64::new(BE, section.data.len() as u64), |
| 340 | s_scnptr: U64::new(BE, section_offsets[index].data_offset as u64), |
| 341 | s_relptr: U64::new(BE, section_offsets[index].reloc_offset as u64), |
| 342 | s_lnnoptr: U64::new(BE, 0), |
| 343 | s_nreloc: U32::new(BE, section.relocations.len() as u32), |
| 344 | s_nlnno: U32::new(BE, 0), |
| 345 | s_flags: U32::new(BE, flags), |
| 346 | s_reserve: U32::new(BE, 0), |
| 347 | }; |
| 348 | buffer.write(§ion_header); |
| 349 | } else { |
| 350 | let section_header = xcoff::SectionHeader32 { |
| 351 | s_name: sectname, |
| 352 | s_paddr: U32::new(BE, section_offsets[index].address as u32), |
| 353 | // This field has the same value as the s_paddr field. |
| 354 | s_vaddr: U32::new(BE, section_offsets[index].address as u32), |
| 355 | s_size: U32::new(BE, section.data.len() as u32), |
| 356 | s_scnptr: U32::new(BE, section_offsets[index].data_offset as u32), |
| 357 | s_relptr: U32::new(BE, section_offsets[index].reloc_offset as u32), |
| 358 | s_lnnoptr: U32::new(BE, 0), |
| 359 | // TODO: If more than 65,534 relocation entries are required, the field |
| 360 | // value will be 65535, and an STYP_OVRFLO section header will contain |
| 361 | // the actual count of relocation entries in the s_paddr field. |
| 362 | s_nreloc: U16::new(BE, section.relocations.len() as u16), |
| 363 | s_nlnno: U16::new(BE, 0), |
| 364 | s_flags: U32::new(BE, flags), |
| 365 | }; |
| 366 | buffer.write(§ion_header); |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | // Write section data. |
| 371 | for (index, section) in self.sections.iter().enumerate() { |
| 372 | let len = section.data.len(); |
| 373 | if len != 0 { |
| 374 | write_align(buffer, 4); |
| 375 | debug_assert_eq!(section_offsets[index].data_offset, buffer.len()); |
| 376 | buffer.write_bytes(§ion.data); |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | // Write relocations. |
| 381 | for (index, section) in self.sections.iter().enumerate() { |
| 382 | if !section.relocations.is_empty() { |
| 383 | debug_assert_eq!(section_offsets[index].reloc_offset, buffer.len()); |
| 384 | for reloc in §ion.relocations { |
| 385 | let (r_rtype, r_rsize) = |
| 386 | if let RelocationFlags::Xcoff { r_rtype, r_rsize } = reloc.flags { |
| 387 | (r_rtype, r_rsize) |
| 388 | } else { |
| 389 | return Err(Error("invalid relocation flags" .into())); |
| 390 | }; |
| 391 | if is_64 { |
| 392 | let xcoff_rel = xcoff::Rel64 { |
| 393 | r_vaddr: U64::new(BE, reloc.offset), |
| 394 | r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32), |
| 395 | r_rsize, |
| 396 | r_rtype, |
| 397 | }; |
| 398 | buffer.write(&xcoff_rel); |
| 399 | } else { |
| 400 | let xcoff_rel = xcoff::Rel32 { |
| 401 | r_vaddr: U32::new(BE, reloc.offset as u32), |
| 402 | r_symndx: U32::new(BE, symbol_offsets[reloc.symbol.0].index as u32), |
| 403 | r_rsize, |
| 404 | r_rtype, |
| 405 | }; |
| 406 | buffer.write(&xcoff_rel); |
| 407 | } |
| 408 | } |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | // Write symbols. |
| 413 | debug_assert_eq!(symtab_offset, buffer.len()); |
| 414 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 415 | let (n_value, section_kind) = if let SymbolSection::Section(id) = symbol.section { |
| 416 | ( |
| 417 | section_offsets[id.0].address + symbol.value, |
| 418 | self.sections[id.0].kind, |
| 419 | ) |
| 420 | } else { |
| 421 | (symbol.value, SectionKind::Unknown) |
| 422 | }; |
| 423 | let n_scnum = match symbol.section { |
| 424 | SymbolSection::None => { |
| 425 | debug_assert_eq!(symbol.kind, SymbolKind::File); |
| 426 | xcoff::N_DEBUG |
| 427 | } |
| 428 | SymbolSection::Undefined | SymbolSection::Common => xcoff::N_UNDEF, |
| 429 | SymbolSection::Absolute => xcoff::N_ABS, |
| 430 | SymbolSection::Section(id) => id.0 as i16 + 1, |
| 431 | }; |
| 432 | let n_sclass = symbol_offsets[index].storage_class; |
| 433 | let n_type = if (symbol.scope == SymbolScope::Linkage) |
| 434 | && (n_sclass == xcoff::C_EXT |
| 435 | || n_sclass == xcoff::C_WEAKEXT |
| 436 | || n_sclass == xcoff::C_HIDEXT) |
| 437 | { |
| 438 | xcoff::SYM_V_HIDDEN |
| 439 | } else { |
| 440 | 0 |
| 441 | }; |
| 442 | let n_numaux = symbol_offsets[index].aux_count; |
| 443 | if is_64 { |
| 444 | let str_id = if n_sclass == xcoff::C_FILE { |
| 445 | file_str_id.unwrap() |
| 446 | } else { |
| 447 | symbol_offsets[index].str_id.unwrap() |
| 448 | }; |
| 449 | let xcoff_sym = xcoff::Symbol64 { |
| 450 | n_value: U64::new(BE, n_value), |
| 451 | n_offset: U32::new(BE, strtab.get_offset(str_id) as u32), |
| 452 | n_scnum: I16::new(BE, n_scnum), |
| 453 | n_type: U16::new(BE, n_type), |
| 454 | n_sclass, |
| 455 | n_numaux, |
| 456 | }; |
| 457 | buffer.write(&xcoff_sym); |
| 458 | } else { |
| 459 | let mut sym_name = [0; 8]; |
| 460 | if n_sclass == xcoff::C_FILE { |
| 461 | sym_name[..5].copy_from_slice(b".file" ); |
| 462 | } else if symbol.name.len() <= 8 { |
| 463 | sym_name[..symbol.name.len()].copy_from_slice(&symbol.name[..]); |
| 464 | } else { |
| 465 | let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); |
| 466 | sym_name[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32)); |
| 467 | } |
| 468 | let xcoff_sym = xcoff::Symbol32 { |
| 469 | n_name: sym_name, |
| 470 | n_value: U32::new(BE, n_value as u32), |
| 471 | n_scnum: I16::new(BE, n_scnum), |
| 472 | n_type: U16::new(BE, n_type), |
| 473 | n_sclass, |
| 474 | n_numaux, |
| 475 | }; |
| 476 | buffer.write(&xcoff_sym); |
| 477 | } |
| 478 | // Generate auxiliary entries. |
| 479 | if n_sclass == xcoff::C_FILE { |
| 480 | debug_assert_eq!(n_numaux, 1); |
| 481 | let mut x_fname = [0; 8]; |
| 482 | if symbol.name.len() <= 8 { |
| 483 | x_fname[..symbol.name.len()].copy_from_slice(&symbol.name[..]); |
| 484 | } else { |
| 485 | let str_offset = strtab.get_offset(symbol_offsets[index].str_id.unwrap()); |
| 486 | x_fname[4..8].copy_from_slice(&u32::to_be_bytes(str_offset as u32)); |
| 487 | } |
| 488 | if is_64 { |
| 489 | let file_aux = xcoff::FileAux64 { |
| 490 | x_fname, |
| 491 | x_fpad: Default::default(), |
| 492 | x_ftype: xcoff::XFT_FN, |
| 493 | x_freserve: Default::default(), |
| 494 | x_auxtype: xcoff::AUX_FILE, |
| 495 | }; |
| 496 | buffer.write(&file_aux); |
| 497 | } else { |
| 498 | let file_aux = xcoff::FileAux32 { |
| 499 | x_fname, |
| 500 | x_fpad: Default::default(), |
| 501 | x_ftype: xcoff::XFT_FN, |
| 502 | x_freserve: Default::default(), |
| 503 | }; |
| 504 | buffer.write(&file_aux); |
| 505 | } |
| 506 | } else if n_sclass == xcoff::C_EXT |
| 507 | || n_sclass == xcoff::C_WEAKEXT |
| 508 | || n_sclass == xcoff::C_HIDEXT |
| 509 | { |
| 510 | debug_assert_eq!(n_numaux, 1); |
| 511 | let (x_smtyp, x_smclas) = if let SymbolFlags::Xcoff { |
| 512 | x_smtyp, x_smclas, .. |
| 513 | } = symbol.flags |
| 514 | { |
| 515 | (x_smtyp, x_smclas) |
| 516 | } else { |
| 517 | match symbol.kind { |
| 518 | SymbolKind::Text => (xcoff::XTY_SD, xcoff::XMC_PR), |
| 519 | SymbolKind::Data => { |
| 520 | if section_kind == SectionKind::UninitializedData { |
| 521 | (xcoff::XTY_CM, xcoff::XMC_BS) |
| 522 | } else if section_kind == SectionKind::ReadOnlyData { |
| 523 | (xcoff::XTY_SD, xcoff::XMC_RO) |
| 524 | } else { |
| 525 | (xcoff::XTY_SD, xcoff::XMC_RW) |
| 526 | } |
| 527 | } |
| 528 | SymbolKind::Tls => { |
| 529 | if section_kind == SectionKind::UninitializedTls { |
| 530 | (xcoff::XTY_CM, xcoff::XMC_UL) |
| 531 | } else { |
| 532 | (xcoff::XTY_SD, xcoff::XMC_TL) |
| 533 | } |
| 534 | } |
| 535 | _ => { |
| 536 | return Err(Error(format!( |
| 537 | "unimplemented symbol ` {}` kind {:?}" , |
| 538 | symbol.name().unwrap_or("" ), |
| 539 | symbol.kind |
| 540 | ))); |
| 541 | } |
| 542 | } |
| 543 | }; |
| 544 | let scnlen = if let SymbolFlags::Xcoff { |
| 545 | containing_csect: Some(containing_csect), |
| 546 | .. |
| 547 | } = symbol.flags |
| 548 | { |
| 549 | symbol_offsets[containing_csect.0].index as u64 |
| 550 | } else { |
| 551 | symbol.size |
| 552 | }; |
| 553 | if is_64 { |
| 554 | let csect_aux = xcoff::CsectAux64 { |
| 555 | x_scnlen_lo: U32::new(BE, (scnlen & 0xFFFFFFFF) as u32), |
| 556 | x_scnlen_hi: U32::new(BE, ((scnlen >> 32) & 0xFFFFFFFF) as u32), |
| 557 | x_parmhash: U32::new(BE, 0), |
| 558 | x_snhash: U16::new(BE, 0), |
| 559 | x_smtyp, |
| 560 | x_smclas, |
| 561 | pad: 0, |
| 562 | x_auxtype: xcoff::AUX_CSECT, |
| 563 | }; |
| 564 | buffer.write(&csect_aux); |
| 565 | } else { |
| 566 | let csect_aux = xcoff::CsectAux32 { |
| 567 | x_scnlen: U32::new(BE, scnlen as u32), |
| 568 | x_parmhash: U32::new(BE, 0), |
| 569 | x_snhash: U16::new(BE, 0), |
| 570 | x_smtyp, |
| 571 | x_smclas, |
| 572 | x_stab: U32::new(BE, 0), |
| 573 | x_snstab: U16::new(BE, 0), |
| 574 | }; |
| 575 | buffer.write(&csect_aux); |
| 576 | } |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | // Write string table. |
| 581 | debug_assert_eq!(strtab_offset, buffer.len()); |
| 582 | buffer.write_bytes(&u32::to_be_bytes(strtab_len as u32)); |
| 583 | buffer.write_bytes(&strtab_data); |
| 584 | |
| 585 | debug_assert_eq!(offset, buffer.len()); |
| 586 | Ok(()) |
| 587 | } |
| 588 | } |
| 589 | |