1 //! Reading of the rustc metadata for rlibs and dylibs
2
3 use std::fs::File;
4 use std::io::Write;
5 use std::path::Path;
6
7 use object::write::{self, StandardSegment, Symbol, SymbolSection};
8 use object::{
9 elf, pe, xcoff, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
10 ObjectSymbol, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
11 };
12
13 use snap::write::FrameEncoder;
14
15 use object::elf::NT_GNU_PROPERTY_TYPE_0;
16 use rustc_data_structures::memmap::Mmap;
17 use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
18 use rustc_metadata::fs::METADATA_FILENAME;
19 use rustc_metadata::EncodedMetadata;
20 use rustc_session::cstore::MetadataLoader;
21 use rustc_session::Session;
22 use rustc_target::abi::Endian;
23 use rustc_target::spec::{ef_avr_arch, RelocModel, Target};
24
25 /// The default metadata loader. This is used by cg_llvm and cg_clif.
26 ///
27 /// # Metadata location
28 ///
29 /// <dl>
30 /// <dt>rlib</dt>
31 /// <dd>The metadata can be found in the `lib.rmeta` file inside of the ar archive.</dd>
32 /// <dt>dylib</dt>
33 /// <dd>The metadata can be found in the `.rustc` section of the shared library.</dd>
34 /// </dl>
35 #[derive(Debug)]
36 pub struct DefaultMetadataLoader;
37
38 static AIX_METADATA_SYMBOL_NAME: &'static str = "__aix_rust_metadata";
39
load_metadata_with( path: &Path, f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, ) -> Result<OwnedSlice, String>40 fn load_metadata_with(
41 path: &Path,
42 f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
43 ) -> Result<OwnedSlice, String> {
44 let file =
45 File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
46
47 unsafe { Mmap::map(file) }
48 .map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))
49 .and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap)))
50 }
51
52 impl MetadataLoader for DefaultMetadataLoader {
get_rlib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String>53 fn get_rlib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
54 load_metadata_with(path, |data| {
55 let archive = object::read::archive::ArchiveFile::parse(&*data)
56 .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
57
58 for entry_result in archive.members() {
59 let entry = entry_result
60 .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
61 if entry.name() == METADATA_FILENAME.as_bytes() {
62 let data = entry
63 .data(data)
64 .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
65 if target.is_like_aix {
66 return get_metadata_xcoff(path, data);
67 } else {
68 return search_for_section(path, data, ".rmeta");
69 }
70 }
71 }
72
73 Err(format!("metadata not found in rlib '{}'", path.display()))
74 })
75 }
76
get_dylib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String>77 fn get_dylib_metadata(&self, target: &Target, path: &Path) -> Result<OwnedSlice, String> {
78 if target.is_like_aix {
79 load_metadata_with(path, |data| get_metadata_xcoff(path, data))
80 } else {
81 load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
82 }
83 }
84 }
85
search_for_section<'a>( path: &Path, bytes: &'a [u8], section: &str, ) -> Result<&'a [u8], String>86 pub(super) fn search_for_section<'a>(
87 path: &Path,
88 bytes: &'a [u8],
89 section: &str,
90 ) -> Result<&'a [u8], String> {
91 let Ok(file) = object::File::parse(bytes) else {
92 // The parse above could fail for odd reasons like corruption, but for
93 // now we just interpret it as this target doesn't support metadata
94 // emission in object files so the entire byte slice itself is probably
95 // a metadata file. Ideally though if necessary we could at least check
96 // the prefix of bytes to see if it's an actual metadata object and if
97 // not forward the error along here.
98 return Ok(bytes);
99 };
100 file.section_by_name(section)
101 .ok_or_else(|| format!("no `{}` section in '{}'", section, path.display()))?
102 .data()
103 .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
104 }
105
add_gnu_property_note( file: &mut write::Object<'static>, architecture: Architecture, binary_format: BinaryFormat, endianness: Endianness, )106 fn add_gnu_property_note(
107 file: &mut write::Object<'static>,
108 architecture: Architecture,
109 binary_format: BinaryFormat,
110 endianness: Endianness,
111 ) {
112 // check bti protection
113 if binary_format != BinaryFormat::Elf
114 || !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64)
115 {
116 return;
117 }
118
119 let section = file.add_section(
120 file.segment_name(StandardSegment::Data).to_vec(),
121 b".note.gnu.property".to_vec(),
122 SectionKind::Note,
123 );
124 let mut data: Vec<u8> = Vec::new();
125 let n_namsz: u32 = 4; // Size of the n_name field
126 let n_descsz: u32 = 16; // Size of the n_desc field
127 let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
128 let header_values = [n_namsz, n_descsz, n_type];
129 header_values.iter().for_each(|v| {
130 data.extend_from_slice(&match endianness {
131 Endianness::Little => v.to_le_bytes(),
132 Endianness::Big => v.to_be_bytes(),
133 })
134 });
135 data.extend_from_slice(b"GNU\0"); // Owner of the program property note
136 let pr_type: u32 = match architecture {
137 Architecture::X86_64 => 0xc0000002,
138 Architecture::Aarch64 => 0xc0000000,
139 _ => unreachable!(),
140 };
141 let pr_datasz: u32 = 4; //size of the pr_data field
142 let pr_data: u32 = 3; //program property descriptor
143 let pr_padding: u32 = 0;
144 let property_values = [pr_type, pr_datasz, pr_data, pr_padding];
145 property_values.iter().for_each(|v| {
146 data.extend_from_slice(&match endianness {
147 Endianness::Little => v.to_le_bytes(),
148 Endianness::Big => v.to_be_bytes(),
149 })
150 });
151 file.append_section_data(section, &data, 8);
152 }
153
get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a [u8], String>154 pub(super) fn get_metadata_xcoff<'a>(path: &Path, data: &'a [u8]) -> Result<&'a [u8], String> {
155 let Ok(file) = object::File::parse(data) else {
156 return Ok(data);
157 };
158 let info_data = search_for_section(path, data, ".info")?;
159 if let Some(metadata_symbol) =
160 file.symbols().find(|sym| sym.name() == Ok(AIX_METADATA_SYMBOL_NAME))
161 {
162 let offset = metadata_symbol.address() as usize;
163 if offset < 4 {
164 return Err(format!("Invalid metadata symbol offset: {}", offset));
165 }
166 // The offset specifies the location of rustc metadata in the comment section.
167 // The metadata is preceded by a 4-byte length field.
168 let len = u32::from_be_bytes(info_data[(offset - 4)..offset].try_into().unwrap()) as usize;
169 if offset + len > (info_data.len() as usize) {
170 return Err(format!(
171 "Metadata at offset {} with size {} is beyond .info section",
172 offset, len
173 ));
174 }
175 return Ok(&info_data[offset..(offset + len)]);
176 } else {
177 return Err(format!("Unable to find symbol {}", AIX_METADATA_SYMBOL_NAME));
178 };
179 }
180
create_object_file(sess: &Session) -> Option<write::Object<'static>>181 pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
182 let endianness = match sess.target.options.endian {
183 Endian::Little => Endianness::Little,
184 Endian::Big => Endianness::Big,
185 };
186 let architecture = match &sess.target.arch[..] {
187 "arm" => Architecture::Arm,
188 "aarch64" => {
189 if sess.target.pointer_width == 32 {
190 Architecture::Aarch64_Ilp32
191 } else {
192 Architecture::Aarch64
193 }
194 }
195 "x86" => Architecture::I386,
196 "s390x" => Architecture::S390x,
197 "mips" => Architecture::Mips,
198 "mips64" => Architecture::Mips64,
199 "x86_64" => {
200 if sess.target.pointer_width == 32 {
201 Architecture::X86_64_X32
202 } else {
203 Architecture::X86_64
204 }
205 }
206 "powerpc" => Architecture::PowerPc,
207 "powerpc64" => Architecture::PowerPc64,
208 "riscv32" => Architecture::Riscv32,
209 "riscv64" => Architecture::Riscv64,
210 "sparc64" => Architecture::Sparc64,
211 "avr" => Architecture::Avr,
212 "msp430" => Architecture::Msp430,
213 "hexagon" => Architecture::Hexagon,
214 "bpf" => Architecture::Bpf,
215 "loongarch64" => Architecture::LoongArch64,
216 // Unsupported architecture.
217 _ => return None,
218 };
219 let binary_format = if sess.target.is_like_osx {
220 BinaryFormat::MachO
221 } else if sess.target.is_like_windows {
222 BinaryFormat::Coff
223 } else if sess.target.is_like_aix {
224 BinaryFormat::Xcoff
225 } else {
226 BinaryFormat::Elf
227 };
228
229 let mut file = write::Object::new(binary_format, architecture, endianness);
230 if sess.target.is_like_osx {
231 if let Some(build_version) = macho_object_build_version_for_target(&sess.target) {
232 file.set_macho_build_version(build_version)
233 }
234 }
235 let e_flags = match architecture {
236 Architecture::Mips => {
237 let arch = match sess.target.options.cpu.as_ref() {
238 "mips1" => elf::EF_MIPS_ARCH_1,
239 "mips2" => elf::EF_MIPS_ARCH_2,
240 "mips3" => elf::EF_MIPS_ARCH_3,
241 "mips4" => elf::EF_MIPS_ARCH_4,
242 "mips5" => elf::EF_MIPS_ARCH_5,
243 s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
244 _ => elf::EF_MIPS_ARCH_32R2,
245 };
246 // The only ABI LLVM supports for 32-bit MIPS CPUs is o32.
247 let mut e_flags = elf::EF_MIPS_CPIC | elf::EF_MIPS_ABI_O32 | arch;
248 if sess.target.options.relocation_model != RelocModel::Static {
249 e_flags |= elf::EF_MIPS_PIC;
250 }
251 if sess.target.options.cpu.contains("r6") {
252 e_flags |= elf::EF_MIPS_NAN2008;
253 }
254 e_flags
255 }
256 Architecture::Mips64 => {
257 // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
258 let e_flags = elf::EF_MIPS_CPIC
259 | elf::EF_MIPS_PIC
260 | if sess.target.options.cpu.contains("r6") {
261 elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
262 } else {
263 elf::EF_MIPS_ARCH_64R2
264 };
265 e_flags
266 }
267 Architecture::Riscv32 | Architecture::Riscv64 => {
268 // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
269 let mut e_flags: u32 = 0x0;
270 let features = &sess.target.options.features;
271 // Check if compressed is enabled
272 if features.contains("+c") {
273 e_flags |= elf::EF_RISCV_RVC;
274 }
275
276 // Select the appropriate floating-point ABI
277 if features.contains("+d") {
278 e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
279 } else if features.contains("+f") {
280 e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
281 } else {
282 e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
283 }
284 e_flags
285 }
286 Architecture::LoongArch64 => {
287 // Source: https://github.com/loongson/la-abi-specs/blob/release/laelf.adoc#e_flags-identifies-abi-type-and-version
288 let mut e_flags: u32 = elf::EF_LARCH_OBJABI_V1;
289 let features = &sess.target.options.features;
290
291 // Select the appropriate floating-point ABI
292 if features.contains("+d") {
293 e_flags |= elf::EF_LARCH_ABI_DOUBLE_FLOAT;
294 } else if features.contains("+f") {
295 e_flags |= elf::EF_LARCH_ABI_SINGLE_FLOAT;
296 } else {
297 e_flags |= elf::EF_LARCH_ABI_SOFT_FLOAT;
298 }
299 e_flags
300 }
301 Architecture::Avr => {
302 // Resolve the ISA revision and set
303 // the appropriate EF_AVR_ARCH flag.
304 ef_avr_arch(&sess.target.options.cpu)
305 }
306 _ => 0,
307 };
308 // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI`
309 let os_abi = match sess.target.options.os.as_ref() {
310 "hermit" => elf::ELFOSABI_STANDALONE,
311 "freebsd" => elf::ELFOSABI_FREEBSD,
312 "solaris" => elf::ELFOSABI_SOLARIS,
313 _ => elf::ELFOSABI_NONE,
314 };
315 let abi_version = 0;
316 add_gnu_property_note(&mut file, architecture, binary_format, endianness);
317 file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
318 Some(file)
319 }
320
321 /// Apple's LD, when linking for Mac Catalyst, requires object files to
322 /// contain information about what they were built for (LC_BUILD_VERSION):
323 /// the platform (macOS/watchOS etc), minimum OS version, and SDK version.
324 /// This returns a `MachOBuildVersion` if necessary for the target.
macho_object_build_version_for_target( target: &Target, ) -> Option<object::write::MachOBuildVersion>325 fn macho_object_build_version_for_target(
326 target: &Target,
327 ) -> Option<object::write::MachOBuildVersion> {
328 if !target.llvm_target.ends_with("-macabi") {
329 return None;
330 }
331 /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
332 /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
333 fn pack_version((major, minor): (u32, u32)) -> u32 {
334 (major << 16) | (minor << 8)
335 }
336
337 let platform = object::macho::PLATFORM_MACCATALYST;
338 let min_os = (14, 0);
339 let sdk = (16, 2);
340
341 let mut build_version = object::write::MachOBuildVersion::default();
342 build_version.platform = platform;
343 build_version.minos = pack_version(min_os);
344 build_version.sdk = pack_version(sdk);
345 Some(build_version)
346 }
347
348 pub enum MetadataPosition {
349 First,
350 Last,
351 }
352
353 /// For rlibs we "pack" rustc metadata into a dummy object file.
354 ///
355 /// Historically it was needed because rustc linked rlibs as whole-archive in some cases.
356 /// In that case linkers try to include all files located in an archive, so if metadata is stored
357 /// in an archive then it needs to be of a form that the linker is able to process.
358 /// Now it's not clear whether metadata still needs to be wrapped into an object file or not.
359 ///
360 /// Note, though, that we don't actually want this metadata to show up in any
361 /// final output of the compiler. Instead this is purely for rustc's own
362 /// metadata tracking purposes.
363 ///
364 /// With the above in mind, each "flavor" of object format gets special
365 /// handling here depending on the target:
366 ///
367 /// * MachO - macos-like targets will insert the metadata into a section that
368 /// is sort of fake dwarf debug info. Inspecting the source of the macos
369 /// linker this causes these sections to be skipped automatically because
370 /// it's not in an allowlist of otherwise well known dwarf section names to
371 /// go into the final artifact.
372 ///
373 /// * WebAssembly - we actually don't have any container format for this
374 /// target. WebAssembly doesn't support the `dylib` crate type anyway so
375 /// there's no need for us to support this at this time. Consequently the
376 /// metadata bytes are simply stored as-is into an rlib.
377 ///
378 /// * COFF - Windows-like targets create an object with a section that has
379 /// the `IMAGE_SCN_LNK_REMOVE` flag set which ensures that if the linker
380 /// ever sees the section it doesn't process it and it's removed.
381 ///
382 /// * ELF - All other targets are similar to Windows in that there's a
383 /// `SHF_EXCLUDE` flag we can set on sections in an object file to get
384 /// automatically removed from the final output.
create_wrapper_file( sess: &Session, section_name: Vec<u8>, data: &[u8], ) -> (Vec<u8>, MetadataPosition)385 pub fn create_wrapper_file(
386 sess: &Session,
387 section_name: Vec<u8>,
388 data: &[u8],
389 ) -> (Vec<u8>, MetadataPosition) {
390 let Some(mut file) = create_object_file(sess) else {
391 // This is used to handle all "other" targets. This includes targets
392 // in two categories:
393 //
394 // * Some targets don't have support in the `object` crate just yet
395 // to write an object file. These targets are likely to get filled
396 // out over time.
397 //
398 // * Targets like WebAssembly don't support dylibs, so the purpose
399 // of putting metadata in object files, to support linking rlibs
400 // into dylibs, is moot.
401 //
402 // In both of these cases it means that linking into dylibs will
403 // not be supported by rustc. This doesn't matter for targets like
404 // WebAssembly and for targets not supported by the `object` crate
405 // yet it means that work will need to be done in the `object` crate
406 // to add a case above.
407 return (data.to_vec(), MetadataPosition::Last);
408 };
409 let section = if file.format() == BinaryFormat::Xcoff {
410 file.add_section(Vec::new(), b".info".to_vec(), SectionKind::Debug)
411 } else {
412 file.add_section(
413 file.segment_name(StandardSegment::Debug).to_vec(),
414 section_name,
415 SectionKind::Debug,
416 )
417 };
418 match file.format() {
419 BinaryFormat::Coff => {
420 file.section_mut(section).flags =
421 SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE };
422 }
423 BinaryFormat::Elf => {
424 file.section_mut(section).flags =
425 SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 };
426 }
427 BinaryFormat::Xcoff => {
428 // AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss.
429 file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text);
430 file.section_mut(section).flags =
431 SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 };
432
433 let len = data.len() as u32;
434 let offset = file.append_section_data(section, &len.to_be_bytes(), 1);
435 // Add a symbol referring to the data in .info section.
436 file.add_symbol(Symbol {
437 name: AIX_METADATA_SYMBOL_NAME.into(),
438 value: offset + 4,
439 size: 0,
440 kind: SymbolKind::Unknown,
441 scope: SymbolScope::Compilation,
442 weak: false,
443 section: SymbolSection::Section(section),
444 flags: SymbolFlags::Xcoff {
445 n_sclass: xcoff::C_INFO,
446 x_smtyp: xcoff::C_HIDEXT,
447 x_smclas: xcoff::C_HIDEXT,
448 containing_csect: None,
449 },
450 });
451 }
452 _ => {}
453 };
454 file.append_section_data(section, data, 1);
455 (file.write().unwrap(), MetadataPosition::First)
456 }
457
458 // Historical note:
459 //
460 // When using link.exe it was seen that the section name `.note.rustc`
461 // was getting shortened to `.note.ru`, and according to the PE and COFF
462 // specification:
463 //
464 // > Executable images do not use a string table and do not support
465 // > section names longer than 8 characters
466 //
467 // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
468 //
469 // As a result, we choose a slightly shorter name! As to why
470 // `.note.rustc` works on MinGW, see
471 // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
create_compressed_metadata_file( sess: &Session, metadata: &EncodedMetadata, symbol_name: &str, ) -> Vec<u8>472 pub fn create_compressed_metadata_file(
473 sess: &Session,
474 metadata: &EncodedMetadata,
475 symbol_name: &str,
476 ) -> Vec<u8> {
477 let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
478 // Our length will be backfilled once we're done writing
479 compressed.write_all(&[0; 4]).unwrap();
480 FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
481 let meta_len = rustc_metadata::METADATA_HEADER.len();
482 let data_len = (compressed.len() - meta_len - 4) as u32;
483 compressed[meta_len..meta_len + 4].copy_from_slice(&data_len.to_be_bytes());
484
485 let Some(mut file) = create_object_file(sess) else {
486 return compressed.to_vec();
487 };
488 if file.format() == BinaryFormat::Xcoff {
489 return create_compressed_metadata_file_for_xcoff(file, &compressed, symbol_name);
490 }
491 let section = file.add_section(
492 file.segment_name(StandardSegment::Data).to_vec(),
493 b".rustc".to_vec(),
494 SectionKind::ReadOnlyData,
495 );
496 match file.format() {
497 BinaryFormat::Elf => {
498 // Explicitly set no flags to avoid SHF_ALLOC default for data section.
499 file.section_mut(section).flags = SectionFlags::Elf { sh_flags: 0 };
500 }
501 _ => {}
502 };
503 let offset = file.append_section_data(section, &compressed, 1);
504
505 // For MachO and probably PE this is necessary to prevent the linker from throwing away the
506 // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
507 file.add_symbol(Symbol {
508 name: symbol_name.as_bytes().to_vec(),
509 value: offset,
510 size: compressed.len() as u64,
511 kind: SymbolKind::Data,
512 scope: SymbolScope::Dynamic,
513 weak: false,
514 section: SymbolSection::Section(section),
515 flags: SymbolFlags::None,
516 });
517
518 file.write().unwrap()
519 }
520
521 /// * Xcoff - On AIX, custom sections are merged into predefined sections,
522 /// so custom .rustc section is not preserved during linking.
523 /// For this reason, we store metadata in predefined .info section, and
524 /// define a symbol to reference the metadata. To preserve metadata during
525 /// linking on AIX, we have to
526 /// 1. Create an empty .text section, a empty .data section.
527 /// 2. Define an empty symbol named `symbol_name` inside .data section.
528 /// 3. Define an symbol named `AIX_METADATA_SYMBOL_NAME` referencing
529 /// data inside .info section.
530 /// From XCOFF's view, (2) creates a csect entry in the symbol table, the
531 /// symbol created by (3) is a info symbol for the preceding csect. Thus
532 /// two symbols are preserved during linking and we can use the second symbol
533 /// to reference the metadata.
create_compressed_metadata_file_for_xcoff( mut file: write::Object<'_>, data: &[u8], symbol_name: &str, ) -> Vec<u8>534 pub fn create_compressed_metadata_file_for_xcoff(
535 mut file: write::Object<'_>,
536 data: &[u8],
537 symbol_name: &str,
538 ) -> Vec<u8> {
539 assert!(file.format() == BinaryFormat::Xcoff);
540 // AIX system linker may aborts if it meets a valid XCOFF file in archive with no .text, no .data and no .bss.
541 file.add_section(Vec::new(), b".text".to_vec(), SectionKind::Text);
542 let data_section = file.add_section(Vec::new(), b".data".to_vec(), SectionKind::Data);
543 let section = file.add_section(Vec::new(), b".info".to_vec(), SectionKind::Debug);
544 file.add_file_symbol("lib.rmeta".into());
545 file.section_mut(section).flags = SectionFlags::Xcoff { s_flags: xcoff::STYP_INFO as u32 };
546 // Add a global symbol to data_section.
547 file.add_symbol(Symbol {
548 name: symbol_name.as_bytes().into(),
549 value: 0,
550 size: 0,
551 kind: SymbolKind::Data,
552 scope: SymbolScope::Dynamic,
553 weak: true,
554 section: SymbolSection::Section(data_section),
555 flags: SymbolFlags::None,
556 });
557 let len = data.len() as u32;
558 let offset = file.append_section_data(section, &len.to_be_bytes(), 1);
559 // Add a symbol referring to the rustc metadata.
560 file.add_symbol(Symbol {
561 name: AIX_METADATA_SYMBOL_NAME.into(),
562 value: offset + 4, // The metadata is preceded by a 4-byte length field.
563 size: 0,
564 kind: SymbolKind::Unknown,
565 scope: SymbolScope::Dynamic,
566 weak: false,
567 section: SymbolSection::Section(section),
568 flags: SymbolFlags::Xcoff {
569 n_sclass: xcoff::C_INFO,
570 x_smtyp: xcoff::C_HIDEXT,
571 x_smclas: xcoff::C_HIDEXT,
572 containing_csect: None,
573 },
574 });
575 file.append_section_data(section, data, 1);
576 file.write().unwrap()
577 }
578