1// Derived from code in LLVM, which is:
2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3// See https://llvm.org/LICENSE.txt for license information.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5
6//! Default implementation of [crate::ObjectReader] that uses the `object` crate.
7
8use std::{io, mem::offset_of};
9
10use object::{pe::ImportObjectHeader, xcoff, Object, ObjectSymbol};
11
12use crate::coff_import_file;
13
14fn is_archive_symbol(sym: &object::read::Symbol<'_, '_>) -> bool {
15 // FIXME Use a better equivalent of LLVM's SymbolRef::SF_FormatSpecific
16 if sym.kind() == object::SymbolKind::File || sym.kind() == object::SymbolKind::Section {
17 return false;
18 }
19 if !sym.is_global() {
20 return false;
21 }
22 if sym.is_undefined() {
23 return false;
24 }
25 true
26}
27
28pub fn get_native_object_symbols(
29 buf: &[u8],
30 f: &mut dyn FnMut(&[u8]) -> io::Result<()>,
31) -> io::Result<bool> {
32 // FIXME match what LLVM does
33
34 match object::File::parse(data:buf) {
35 Ok(file: File<'_>) => {
36 for sym: Symbol<'_, '_> in file.symbols() {
37 if !is_archive_symbol(&sym) {
38 continue;
39 }
40 f(sym.name_bytes().expect(msg:"FIXME"))?;
41 }
42 Ok(true)
43 }
44 Err(_) => {
45 let mut offset: u64 = 0;
46 // Try to handle this as a COFF import library.
47 if ImportObjectHeader::parse(data:buf, &mut offset).is_ok() {
48 coff_import_file::get_short_import_symbol(buf, f).or(res:Ok(false))
49 } else {
50 Ok(false)
51 }
52 }
53 }
54}
55
56pub fn is_ec_object(obj: &[u8]) -> bool {
57 match object::FileKind::parse(data:obj) {
58 Ok(object::FileKind::Coff) => {
59 u16::from_le_bytes([obj[0], obj[1]]) != object::pe::IMAGE_FILE_MACHINE_ARM64
60 }
61 Ok(object::FileKind::CoffImport) => {
62 // COFF Import Header is:
63 // sig1: u16
64 // sig2: u16
65 // version: u16
66 // machine: u16
67 u16::from_le_bytes([obj[6], obj[7]]) != object::pe::IMAGE_FILE_MACHINE_ARM64
68 }
69 _ => false,
70 }
71}
72
73pub fn is_64_bit_symbolic_file(obj: &[u8]) -> bool {
74 object::FileKind::parse(data:obj).is_ok_and(|kind: FileKind| match kind {
75 object::FileKind::Elf64
76 | object::FileKind::MachO64
77 | object::FileKind::Pe64
78 | object::FileKind::Xcoff64
79 | object::FileKind::MachOFat64 => true,
80 object::FileKind::Elf32
81 | object::FileKind::MachO32
82 | object::FileKind::Pe32
83 | object::FileKind::Xcoff32
84 | object::FileKind::MachOFat32
85 | object::FileKind::Coff
86 | object::FileKind::CoffBig
87 | object::FileKind::CoffImport => false,
88 _ => panic!("Unexpected file kind"),
89 })
90}
91
92// Log2 of PAGESIZE(4096) on an AIX system.
93const LOG2_OF_AIXPAGE_SIZE: u32 = 12;
94
95// In the AIX big archive format, since the data content follows the member file
96// name, if the name ends on an odd byte, an extra byte will be added for
97// padding. This ensures that the data within the member file starts at an even
98// byte.
99const MIN_BIG_ARCHIVE_MEM_DATA_ALIGN: u32 = 2;
100
101fn get_aux_max_alignment<AuxiliaryHeader: object::read::xcoff::AuxHeader>(
102 aux_header_size: u16,
103 aux_header: Option<&AuxiliaryHeader>,
104 log_2_of_max_align: u32,
105 offset_of_modtype: u16,
106) -> u32 {
107 // If the member doesn't have an auxiliary header, it isn't a loadable object
108 // and so it just needs aligning at the minimum value.
109 let Some(aux_header) = aux_header else {
110 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
111 };
112
113 // If the auxiliary header does not have both MaxAlignOfData and
114 // MaxAlignOfText field, it is not a loadable shared object file, so align at
115 // the minimum value. The 'ModuleType' member is located right after
116 // 'MaxAlignOfData' in the AuxiliaryHeader.
117 if aux_header_size < offset_of_modtype {
118 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
119 }
120
121 // If the XCOFF object file does not have a loader section, it is not
122 // loadable, so align at the minimum value.
123 if aux_header.o_snloader() == 0 {
124 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
125 }
126
127 // The content of the loadable member file needs to be aligned at MAX(maximum
128 // alignment of .text, maximum alignment of .data) if there are both fields.
129 // If the desired alignment is > PAGESIZE, 32-bit members are aligned on a
130 // word boundary, while 64-bit members are aligned on a PAGESIZE(2^12=4096)
131 // boundary.
132 let log_2_of_align = u32::from(std::cmp::max(
133 aux_header.o_algntext(),
134 aux_header.o_algndata(),
135 ));
136 1 << (if log_2_of_align > LOG2_OF_AIXPAGE_SIZE {
137 log_2_of_max_align
138 } else {
139 log_2_of_align
140 })
141}
142
143// AIX big archives may contain shared object members. The AIX OS requires these
144// members to be aligned if they are 64-bit and recommends it for 32-bit
145// members. This ensures that when these members are loaded they are aligned in
146// memory.
147pub fn get_member_alignment(obj: &[u8]) -> u32 {
148 use object::read::xcoff::FileHeader;
149
150 // If the desired alignment is > PAGESIZE, 32-bit members are aligned on a
151 // word boundary, while 64-bit members are aligned on a PAGESIZE boundary.
152 match object::FileKind::parse(obj) {
153 Ok(object::FileKind::Xcoff64) => {
154 let mut offset = 0;
155 let Ok(header) = xcoff::FileHeader64::parse(obj, &mut offset) else {
156 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
157 };
158 let Ok(aux_header) = header.aux_header(obj, &mut offset) else {
159 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
160 };
161 get_aux_max_alignment(
162 header.f_opthdr(),
163 aux_header,
164 LOG2_OF_AIXPAGE_SIZE,
165 offset_of!(object::xcoff::AuxHeader64, o_modtype)
166 .try_into()
167 .unwrap(),
168 )
169 }
170 Ok(object::FileKind::Xcoff32) => {
171 let mut offset = 0;
172 let Ok(header) = object::xcoff::FileHeader32::parse(obj, &mut offset) else {
173 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
174 };
175 let Ok(aux_header) = header.aux_header(obj, &mut offset) else {
176 return MIN_BIG_ARCHIVE_MEM_DATA_ALIGN;
177 };
178 get_aux_max_alignment(
179 header.f_opthdr(),
180 aux_header,
181 2,
182 offset_of!(object::xcoff::AuxHeader32, o_modtype)
183 .try_into()
184 .unwrap(),
185 )
186 }
187 _ => MIN_BIG_ARCHIVE_MEM_DATA_ALIGN,
188 }
189}
190

Provided by KDAB

Privacy Policy
Learn Rust with the experts
Find out more