jaulib v1.3.0
Jau Support Library (C++, Java, ..)
ElfHeaderPart2.java
Go to the documentation of this file.
1/**
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021 Gothel Software e.K.
4 * Copyright (c) 2013 Gothel Software e.K.
5 * Copyright (c) 2013 JogAmp Community.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26package org.jau.sys.elf;
27
28import static org.jau.sys.elf.IOUtils.readBytes;
29import static org.jau.sys.elf.IOUtils.seek;
30import static org.jau.sys.elf.IOUtils.shortToInt;
31import static org.jau.sys.elf.IOUtils.toHexString;
32
33import java.io.IOException;
34import java.io.RandomAccessFile;
35import java.nio.ByteBuffer;
36
37import org.jau.sys.PlatformTypes.ABIType;
38import org.jau.sys.PlatformTypes.CPUFamily;
39import org.jau.sys.PlatformTypes.CPUType;
40
41/**
42 * ELF ABI Header Part-2
43 * <p>
44 * Part-2 can only be read w/ knowledge of CPUType!
45 * </p>
46 * <p>
47 * References:
48 * <ul>
49 * <li>http://www.sco.com/developers/gabi/latest/contents.html</li>
50 * <li>https://en.wikipedia.org/wiki/Executable_and_Linkable_Format</li>
51 * <li>http://linux.die.net/man/5/elf</li>
52 * <li>http://infocenter.arm.com/
53 * <ul>
54 * <li>ARM IHI 0044E, current through ABI release 2.09</li>
55 * <li>ARM IHI 0056B: Elf for ARM 64-bit Architecture</li>
56 * </ul></li>
57 * </ul>
58 * </p>
59 */
60public class ElfHeaderPart2 {
61 /**
62 * This masks an 8-bit version number, the version of the ABI to which this
63 * ELF file conforms. This ABI is version 5. A value of 0 denotes unknown conformance.
64 * {@value}
65 */
66 public static final int EF_ARM_ABIMASK = 0xFF000000;
67 public static final int EF_ARM_ABISHIFT = 24;
68
69 /**
70 * ARM ABI version 5.
71 * {@value}
72 */
73 public static final int EF_ARM_ABI5 = 0x05000000;
74
75 /**
76 * The ELF file contains BE-8 code, suitable for execution on an ARM
77 * Architecture v6 processor. This flag must only be set on an executable file.
78 * {@value}
79 */
80 public static final int EF_ARM_BE8 = 0x00800000;
81
82 /**
83 * Legacy code (ABI version 4 and earlier) generated by gcc-arm-xxx might
84 * use these bits.
85 * {@value}
86 */
87 public static final int EF_ARM_GCCMASK = 0x00400FFF;
88
89 /**
90 * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note that
91 * the executable file was built to conform to the hardware floating-point
92 * procedure-call standard.
93 * <p>
94 * Compatible with legacy (pre version 5) gcc use as EF_ARM_VFP_FLOAT.
95 * </p>
96 * <p>
97 * Note: This is not used (anymore)
98 * </p>
99 * {@value}
100 */
101 public static final int EF_ARM_ABI_FLOAT_HARD = 0x00000400;
102
103 /**
104 * Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note
105 * explicitly that the executable file was built to conform to the software
106 * floating-point procedure-call standard (the base standard). If both
107 * {@link #EF_ARM_ABI_FLOAT_HARD} and {@link #EF_ARM_ABI_FLOAT_SOFT} are clear,
108 * conformance to the base procedure-call standard is implied.
109 * <p>
110 * Compatible with legacy (pre version 5) gcc use as EF_ARM_SOFT_FLOAT.
111 * </p>
112 * <p>
113 * Note: This is not used (anymore)
114 * </p>
115 * {@value}
116 */
117 public static final int EF_ARM_ABI_FLOAT_SOFT = 0x00000200;
118
119 /** Public access to the elf header part-1 (CPU/ABI independent read) */
120 public final ElfHeaderPart1 eh1;
121
122 /** Public access to the raw elf header part-2 (CPU/ABI dependent read) */
123 public final Ehdr_p2 raw;
124
125 /** Lower case CPUType name */
126 public final String cpuName;
127 public final CPUType cpuType;
128 public final ABIType abiType;
129
130 /** Public access to the {@link SectionHeader} */
131 public final SectionHeader[] sht;
132
133 /**
134 * Note: The input stream shall stay untouch to be able to read sections!
135 *
136 * @param in input stream of a binary file at position zero
137 * @return
138 * @throws IOException if reading from the given input stream fails or less then ELF Header size bytes
139 * @throws IllegalArgumentException if the given input stream does not represent an ELF Header
140 */
141 public static ElfHeaderPart2 read(final ElfHeaderPart1 eh1, final RandomAccessFile in) throws IOException, IllegalArgumentException {
142 return new ElfHeaderPart2(eh1, in);
143 }
144
145 /**
146 * @param buf ELF Header bytes
147 * @throws IllegalArgumentException if the given buffer does not represent an ELF Header
148 * @throws IOException
149 */
150 ElfHeaderPart2(final ElfHeaderPart1 eh1, final RandomAccessFile in) throws IllegalArgumentException, IOException {
151 this.eh1 = eh1;
152 //
153 // Part-2
154 //
155 {
156 final byte[] buf = new byte[Ehdr_p2.size(eh1.machDesc.ordinal())];
157 readBytes (in, buf, 0, buf.length);
158 final ByteBuffer eh2Bytes = ByteBuffer.wrap(buf, 0, buf.length);
159 raw = Ehdr_p2.create(eh1.machDesc.ordinal(), eh2Bytes);
160 }
161 sht = readSectionHeaderTable(in);
162
163 if( CPUFamily.ARM32 == eh1.cpuType.family ) {
164 // AArch64, has no SHT_ARM_ATTRIBUTES or SHT_AARCH64_ATTRIBUTES SectionHeader defined in our builds!
165 String armCpuName = null;
166 String armCpuRawName = null;
167 boolean abiVFPArgsAcceptsVFPVariant = false;
168 final SectionHeader sh = getSectionHeader(SectionHeader.SHT_ARM_ATTRIBUTES);
169 if(ElfHeaderPart1.DEBUG) {
170 System.err.println("ELF-2: Got ARM Attribs Section Header: "+sh);
171 }
172 if( null != sh ) {
173 final SectionArmAttributes sArmAttrs = (SectionArmAttributes) sh.readSection(in);
174 if(ElfHeaderPart1.DEBUG) {
175 System.err.println("ELF-2: Got ARM Attribs Section Block : "+sArmAttrs);
176 }
177 final SectionArmAttributes.Attribute cpuNameArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.CPU_name);
178 if( null != cpuNameArgsAttr && cpuNameArgsAttr.isNTBS() ) {
179 armCpuName = cpuNameArgsAttr.getNTBS();
180 }
181 final SectionArmAttributes.Attribute cpuRawNameArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.CPU_raw_name);
182 if( null != cpuRawNameArgsAttr && cpuRawNameArgsAttr.isNTBS() ) {
183 armCpuRawName = cpuRawNameArgsAttr.getNTBS();
184 }
185 final SectionArmAttributes.Attribute abiVFPArgsAttr = sArmAttrs.get(SectionArmAttributes.Tag.ABI_VFP_args);
186 if( null != abiVFPArgsAttr ) {
187 abiVFPArgsAcceptsVFPVariant = SectionArmAttributes.abiVFPArgsAcceptsVFPVariant(abiVFPArgsAttr.getULEB128());
188 }
189 }
190 {
191 String _cpuName;
192 CPUType _cpuType;
193 if( null != armCpuName && armCpuName.length() > 0 ) {
194 _cpuName = armCpuName.toLowerCase().replace(' ', '-');
195 _cpuType = queryCPUTypeSafe(_cpuName, true /* isARM */); // 1st-try: native name
196 } else if( null != armCpuRawName && armCpuRawName.length() > 0 ) {
197 _cpuName = armCpuRawName.toLowerCase().replace(' ', '-');
198 _cpuType = queryCPUTypeSafe(_cpuName, true /* isARM */); // 1st-try: native name
199 } else {
200 _cpuName = eh1.cpuName;
201 _cpuType = eh1.cpuType;
202 }
203
204 if( null == _cpuType ) {
205 // 2nd-try: "arm-" + native name
206 _cpuName = "arm-"+_cpuName;
207 _cpuType = queryCPUTypeSafe(_cpuName, true /* isARM */);
208 if( null == _cpuType ) {
209 // finally: Use ELF-1, impossible path due to above 'arm-' prefix
210 _cpuName = eh1.cpuName;
211 _cpuType = queryCPUTypeSafe(_cpuName, true /* isARM */);
212 if( null == _cpuType ) {
213 throw new InternalError("XXX: "+_cpuName+", "+eh1); // shall not happen
214 }
215 }
216 }
217 cpuName = _cpuName;
218 cpuType = _cpuType;
219 if(ElfHeaderPart1.DEBUG) {
220 System.err.println("ELF-2: abiARM cpuName "+_cpuName+"[armCpuName "+armCpuName+", armCpuRawName "+armCpuRawName+"] -> "+cpuName+" -> "+cpuType+", abiVFPArgsAcceptsVFPVariant "+abiVFPArgsAcceptsVFPVariant);
221 }
222 }
223 abiType = abiVFPArgsAcceptsVFPVariant ? ABIType.EABI_GNU_ARMHF : ABIType.EABI_GNU_ARMEL;
224 } else {
225 // Non CPUFamily.ARM32
229 }
230 if(ElfHeaderPart1.DEBUG) {
231 System.err.println("ELF-2: cpuName "+cpuName+" -> "+cpuType+", "+abiType);
232 }
233 }
234 private static CPUType queryCPUTypeSafe(final String cpuName, final boolean isARM) {
235 try {
236 final CPUType res = CPUType.query(cpuName);
237 if( isARM && null != res ) {
238 if( res.family != CPUFamily.ARM32 && res.family != CPUFamily.ARM64 ) {
239 if(ElfHeaderPart1.DEBUG) {
240 System.err.println("ELF-2: queryCPUTypeSafe("+cpuName+", isARM="+isARM+") -> "+res+" ( "+res.family+" ) rejected");
241 }
242 return null; // reject non-arm
243 }
244 }
245 return res;
246 } catch (final Throwable t) {
247 if(ElfHeaderPart1.DEBUG) {
248 System.err.println("ELF-2: queryCPUTypeSafe("+cpuName+", isARM="+isARM+"): "+t.getMessage());
249 t.printStackTrace();
250 }
251 }
252 return null;
253 }
254
255 public final short getSize() { return raw.getE_ehsize(); }
256
257 /** Returns the processor-specific flags associated with the file. */
258 public final int getFlags() {
259 return raw.getE_flags();
260 }
261
262 /** Returns the ARM EABI version from {@link #getFlags() flags}, maybe 0 if not an ARM EABI. */
263 public byte getArmABI() {
264 return (byte) ( ( ( EF_ARM_ABIMASK & raw.getE_flags() ) >> EF_ARM_ABISHIFT ) & 0xff );
265 }
266
267 /** Returns the ARM EABI legacy GCC {@link #getFlags() flags}, maybe 0 if not an ARM EABI or not having legacy GCC flags. */
268 public int getArmLegacyGCCFlags() {
269 final int f = raw.getE_flags();
270 return 0 != ( EF_ARM_ABIMASK & f ) ? ( EF_ARM_GCCMASK & f ) : 0;
271 }
272
273 /**
274 * Returns the ARM EABI float mode from {@link #getFlags() flags},
275 * i.e. 1 for {@link #EF_ARM_ABI_FLOAT_SOFT}, 2 for {@link #EF_ARM_ABI_FLOAT_HARD}
276 * or 0 for none.
277 * <p>
278 * Note: This is not used (anymore)
279 * </p>
280 */
281 public byte getArmFloatMode() {
282 final int f = raw.getE_flags();
283 if( 0 != ( EF_ARM_ABIMASK & f ) ) {
284 if( ( EF_ARM_ABI_FLOAT_HARD & f ) != 0 ) {
285 return 2;
286 }
287 if( ( EF_ARM_ABI_FLOAT_SOFT & f ) != 0 ) {
288 return 1;
289 }
290 }
291 return 0;
292 }
293
294 /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getType() type}, or null if not exists. */
295 public final SectionHeader getSectionHeader(final int type) {
296 for(int i=0; i<sht.length; i++) {
297 final SectionHeader sh = sht[i];
298 if( sh.getType() == type ) {
299 return sh;
300 }
301 }
302 return null;
303 }
304
305 /** Returns the 1st occurence of matching SectionHeader {@link SectionHeader#getName() name}, or null if not exists. */
306 public final SectionHeader getSectionHeader(final String name) {
307 for(int i=0; i<sht.length; i++) {
308 final SectionHeader sh = sht[i];
309 if( sh.getName().equals(name) ) {
310 return sh;
311 }
312 }
313 return null;
314 }
315
316 @Override
317 public final String toString() {
318 final int armABI = getArmABI();
319 final String armFlagsS;
320 if( 0 != armABI ) {
321 armFlagsS=", arm[abi "+armABI+", lGCC "+getArmLegacyGCCFlags()+", float "+getArmFloatMode()+"]";
322 } else {
323 armFlagsS="";
324 }
325 return "ELF-2["+cpuType+", "+abiType+", flags["+toHexString(getFlags())+armFlagsS+"], sh-num "+sht.length+"]";
326 }
327
328 final SectionHeader[] readSectionHeaderTable(final RandomAccessFile in) throws IOException, IllegalArgumentException {
329 // positioning
330 {
331 final long off = raw.getE_shoff(); // absolute offset
332 if( 0 == off ) {
333 return new SectionHeader[0];
334 }
335 seek(in, off);
336 }
337 final SectionHeader[] sht;
338 final int strndx = raw.getE_shstrndx();
339 final int size = raw.getE_shentsize();
340 final int num;
341 int i;
342 if( 0 == raw.getE_shnum() ) {
343 // Read 1st table 1st and use it's sh_size
344 final byte[] buf0 = new byte[size];
345 readBytes(in, buf0, 0, size);
346 final SectionHeader sh0 = new SectionHeader(this, buf0, 0, size, 0);
347 num = (int) sh0.raw.getSh_size();
348 if( 0 >= num ) {
349 throw new IllegalArgumentException("EHdr sh_num == 0 and 1st SHdr size == 0");
350 }
351 sht = new SectionHeader[num];
352 sht[0] = sh0;
353 i=1;
354 } else {
355 num = raw.getE_shnum();
356 sht = new SectionHeader[num];
357 i=0;
358 }
359 for(; i<num; i++) {
360 final byte[] buf = new byte[size];
361 readBytes(in, buf, 0, size);
362 sht[i] = new SectionHeader(this, buf, 0, size, i);
363 }
364 if( SectionHeader.SHN_UNDEF != strndx ) {
365 // has section name string table
366 if( shortToInt(SectionHeader.SHN_LORESERVE) <= strndx ) {
367 throw new InternalError("TODO strndx: "+SectionHeader.SHN_LORESERVE+" < "+strndx);
368 }
369 final SectionHeader strShdr = sht[strndx];
370 if( SectionHeader.SHT_STRTAB != strShdr.getType() ) {
371 throw new IllegalArgumentException("Ref. string Shdr["+strndx+"] is of type "+strShdr.raw.getSh_type());
372 }
373 final Section strS = strShdr.readSection(in);
374 for(i=0; i<num; i++) {
375 sht[i].initName(strS, sht[i].raw.getSh_name());
376 }
377 }
378
379 return sht;
380 }
381}
static Ehdr_p2 create(final int mdIdx)
Definition: Ehdr_p2.java:180
short getE_shnum()
Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]].
Definition: Ehdr_p2.java:160
int getE_flags()
Getter for native field: CType['uint32_t', size [fixed true, lnx64 4], [int]].
Definition: Ehdr_p2.java:105
short getE_shstrndx()
Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]].
Definition: Ehdr_p2.java:171
static int size(final int mdIdx)
Definition: Ehdr_p2.java:176
short getE_shentsize()
Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]].
Definition: Ehdr_p2.java:149
short getE_ehsize()
Getter for native field: CType['uint16_t', size [fixed true, lnx64 2], [int]].
Definition: Ehdr_p2.java:116
long getE_shoff()
Getter for native field: CType['ElfN_Off' (typedef), size [fixed false, lnx64 8], [int]].
Definition: Ehdr_p2.java:94
final MachineDataInfo.StaticConfig machDesc
final String cpuName
Lower case CPUType name.
final SectionHeader[] sht
Public access to the SectionHeader.
int getArmLegacyGCCFlags()
Returns the ARM EABI legacy GCC flags, maybe 0 if not an ARM EABI or not having legacy GCC flags.
final ElfHeaderPart1 eh1
Public access to the elf header part-1 (CPU/ABI independent read)
static final int EF_ARM_ABI_FLOAT_HARD
Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note that the executable file was buil...
static final int EF_ARM_ABI_FLOAT_SOFT
Set in executable file headers (e_type = ET_EXEC or ET_DYN) to note explicitly that the executable fi...
static ElfHeaderPart2 read(final ElfHeaderPart1 eh1, final RandomAccessFile in)
Note: The input stream shall stay untouch to be able to read sections!
final int getFlags()
Returns the processor-specific flags associated with the file.
static final int EF_ARM_BE8
The ELF file contains BE-8 code, suitable for execution on an ARM Architecture v6 processor.
final SectionHeader getSectionHeader(final int type)
Returns the 1st occurence of matching SectionHeader type, or null if not exists.
final Ehdr_p2 raw
Public access to the raw elf header part-2 (CPU/ABI dependent read)
static final int EF_ARM_GCCMASK
Legacy code (ABI version 4 and earlier) generated by gcc-arm-xxx might use these bits.
static final int EF_ARM_ABIMASK
This masks an 8-bit version number, the version of the ABI to which this ELF file conforms.
static final int EF_ARM_ABI5
ARM ABI version 5.
final SectionHeader getSectionHeader(final String name)
Returns the 1st occurence of matching SectionHeader name, or null if not exists.
final String cpuName
Lower case CPUType name.
byte getArmABI()
Returns the ARM EABI version from flags, maybe 0 if not an ARM EABI.
byte getArmFloatMode()
Returns the ARM EABI float mode from flags, i.e.
ELF ABI Section Header.
int getType()
Returns the type of this section.
String getName()
Returns this section name, maybe null if not read.
static final ABIType query(final CPUType cpuType, final String cpuABILower)
EABI_GNU_ARMEL
ARM GNU-EABI ARMEL -mfloat-abi=softfp.