VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/ldr/ldrELFRelocatable.cpp.h

Last change on this file was 99775, checked in by vboxsync, 12 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 134.9 KB
Line 
1/* $Id: ldrELFRelocatable.cpp.h 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * IPRT - Binary Image Loader, Template for ELF Relocatable Images.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*******************************************************************************
39* Defined Constants And Macros *
40*******************************************************************************/
41#if ELF_MODE == 32
42# define RTLDRELF_NAME(name) rtldrELF32##name
43# define RTLDRELF_SUFF(name) name##32
44# define RTLDRELF_MID(pre,suff) pre##32##suff
45# define FMT_ELF_ADDR "%08RX32"
46# define FMT_ELF_ADDR7 "%07RX32"
47# define FMT_ELF_HALF "%04RX16"
48# define FMT_ELF_OFF "%08RX32"
49# define FMT_ELF_SIZE "%08RX32"
50# define FMT_ELF_SWORD "%RI32"
51# define FMT_ELF_WORD "%08RX32"
52# define FMT_ELF_XWORD "%08RX32"
53# define FMT_ELF_SXWORD "%RI32"
54# define Elf_Xword Elf32_Word
55# define Elf_Sxword Elf32_Sword
56
57#elif ELF_MODE == 64
58# define RTLDRELF_NAME(name) rtldrELF64##name
59# define RTLDRELF_SUFF(name) name##64
60# define RTLDRELF_MID(pre,suff) pre##64##suff
61# define FMT_ELF_ADDR "%016RX64"
62# define FMT_ELF_ADDR7 "%08RX64"
63# define FMT_ELF_HALF "%04RX16"
64# define FMT_ELF_SHALF "%RI16"
65# define FMT_ELF_OFF "%016RX64"
66# define FMT_ELF_SIZE "%016RX64"
67# define FMT_ELF_SWORD "%RI32"
68# define FMT_ELF_WORD "%08RX32"
69# define FMT_ELF_XWORD "%016RX64"
70# define FMT_ELF_SXWORD "%RI64"
71# define Elf_Xword Elf64_Xword
72# define Elf_Sxword Elf64_Sxword
73#endif
74
75#define Elf_Ehdr RTLDRELF_MID(Elf,_Ehdr)
76#define Elf_Phdr RTLDRELF_MID(Elf,_Phdr)
77#define Elf_Shdr RTLDRELF_MID(Elf,_Shdr)
78#define Elf_Sym RTLDRELF_MID(Elf,_Sym)
79#define Elf_Rel RTLDRELF_MID(Elf,_Rel)
80#define Elf_Rela RTLDRELF_MID(Elf,_Rela)
81#define Elf_Nhdr RTLDRELF_MID(Elf,_Nhdr)
82#define Elf_Dyn RTLDRELF_MID(Elf,_Dyn)
83#define Elf_Addr RTLDRELF_MID(Elf,_Addr)
84#define Elf_Half RTLDRELF_MID(Elf,_Half)
85#define Elf_Off RTLDRELF_MID(Elf,_Off)
86#define Elf_Size RTLDRELF_MID(Elf,_Size)
87#define Elf_Sword RTLDRELF_MID(Elf,_Sword)
88#define Elf_Word RTLDRELF_MID(Elf,_Word)
89
90#define RTLDRMODELF RTLDRELF_MID(RTLDRMODELF,RT_NOTHING)
91#define PRTLDRMODELF RTLDRELF_MID(PRTLDRMODELF,RT_NOTHING)
92
93#define RTLDRMODELFSHX RTLDRELF_MID(RTLDRMODELFSHX,RT_NOTHING)
94#define PRTLDRMODELFSHX RTLDRELF_MID(PRTLDRMODELFSHX,RT_NOTHING)
95
96#define ELF_R_SYM(info) RTLDRELF_MID(ELF,_R_SYM)(info)
97#define ELF_R_TYPE(info) RTLDRELF_MID(ELF,_R_TYPE)(info)
98#define ELF_R_INFO(sym, type) RTLDRELF_MID(ELF,_R_INFO)(sym, type)
99
100#define ELF_ST_BIND(info) RTLDRELF_MID(ELF,_ST_BIND)(info)
101
102
103
104/*******************************************************************************
105* Structures and Typedefs *
106*******************************************************************************/
107/**
108 * Extra section info.
109 */
110typedef struct RTLDRMODELFSHX
111{
112 /** The corresponding program header. */
113 uint16_t idxPhdr;
114 /** The corresponding dynamic section entry (address). */
115 uint16_t idxDt;
116 /** The DT tag. */
117 uint32_t uDtTag;
118} RTLDRMODELFSHX;
119typedef RTLDRMODELFSHX *PRTLDRMODELFSHX;
120
121/**
122 * The ELF loader structure.
123 */
124typedef struct RTLDRMODELF
125{
126 /** Core module structure. */
127 RTLDRMODINTERNAL Core;
128 /** Pointer to readonly mapping of the image bits.
129 * This mapping is provided by the pReader. */
130 const void *pvBits;
131
132 /** The ELF header. */
133 Elf_Ehdr Ehdr;
134 /** Pointer to our copy of the section headers with sh_addr as RVAs.
135 * The virtual addresses in this array is the 0 based assignments we've given the image.
136 * Not valid if the image is DONE. */
137 Elf_Shdr *paShdrs;
138 /** Unmodified section headers (allocated after paShdrs, so no need to free).
139 * Not valid if the image is DONE. */
140 Elf_Shdr const *paOrgShdrs;
141 /** Runs parallel to paShdrs and is part of the same allocation. */
142 PRTLDRMODELFSHX paShdrExtras;
143 /** Base section number, either 1 or zero depending on whether we've
144 * re-used the NULL entry for .elf.headers in ET_EXEC/ET_DYN. */
145 unsigned iFirstSect;
146 /** Set if the SHF_ALLOC section headers are in order of sh_addr. */
147 bool fShdrInOrder;
148 /** The size of the loaded image. */
149 size_t cbImage;
150
151 /** The image base address if it's an EXEC or DYN image. */
152 Elf_Addr LinkAddress;
153
154 struct
155 {
156 /** The symbol section index. */
157 unsigned iSymSh;
158 /** Number of symbols in the table. */
159 unsigned cSyms;
160 /** Pointer to symbol table within RTLDRMODELF::pvBits. */
161 const Elf_Sym *paSyms;
162
163 /** The string section index. */
164 unsigned iStrSh;
165 /** Size of the string table. */
166 unsigned cbStr;
167 /** Pointer to string table within RTLDRMODELF::pvBits. */
168 const char *pStr;
169 } Rel /**< Regular symbols and strings. */
170 , Dyn /**< Dynamic symbols and strings. */;
171
172 /** Pointer to section header string table within RTLDRMODELF::pvBits. */
173 const char *pShStr;
174 /** Size of the section header string table. */
175 unsigned cbShStr;
176
177 /** The '.eh_frame' section index. Zero if not searched for, ~0U if not found. */
178 unsigned iShEhFrame;
179 /** The '.eh_frame_hdr' section index. Zero if not searched for, ~0U if not found. */
180 unsigned iShEhFrameHdr;
181
182 /** The '.dynamic' / SHT_DYNAMIC section index. ~0U if not present. */
183 unsigned iShDynamic;
184 /** Number of entries in paDynamic. */
185 unsigned cDynamic;
186 /** The dynamic section (NULL for ET_REL). */
187 Elf_Dyn *paDynamic;
188 /** Program headers (NULL for ET_REL). */
189 Elf_Phdr *paPhdrs;
190
191 /** Info extracted from PT_DYNAMIC and the program headers. */
192 struct
193 {
194 /** DT_RELA/DT_REL. */
195 Elf_Addr uPtrRelocs;
196 /** DT_RELASZ/DT_RELSZ. */
197 Elf_Xword cbRelocs;
198 /** Non-zero if we've seen DT_RELAENT/DT_RELENT. */
199 unsigned cbRelocEntry;
200 /** DT_RELA or DT_REL. */
201 unsigned uRelocType;
202 /** The index of the section header matching DT_RELA/DT_REL. */
203 unsigned idxShRelocs;
204
205 /** DT_JMPREL. */
206 Elf_Addr uPtrJmpRelocs;
207 /** DT_PLTRELSZ. */
208 Elf_Xword cbJmpRelocs;
209 /** DT_RELA or DT_REL (if we've seen DT_PLTREL). */
210 unsigned uJmpRelocType;
211 /** The index of the section header matching DT_JMPREL. */
212 unsigned idxShJmpRelocs;
213 } DynInfo;
214} RTLDRMODELF;
215/** Pointer to an ELF module instance. */
216typedef RTLDRMODELF *PRTLDRMODELF;
217
218
219/**
220 * Maps the image bits into memory and resolve pointers into it.
221 *
222 * @returns iprt status code.
223 * @param pModElf The ELF loader module instance data.
224 * @param fNeedsBits Set if we actually need the pvBits member.
225 * If we don't, we can simply read the string and symbol sections, thus saving memory.
226 */
227static int RTLDRELF_NAME(MapBits)(PRTLDRMODELF pModElf, bool fNeedsBits)
228{
229 NOREF(fNeedsBits);
230 if (pModElf->pvBits)
231 return VINF_SUCCESS;
232 int rc = pModElf->Core.pReader->pfnMap(pModElf->Core.pReader, &pModElf->pvBits);
233 if (RT_SUCCESS(rc))
234 {
235 const uint8_t *pu8 = (const uint8_t *)pModElf->pvBits;
236 if (pModElf->Rel.iSymSh != ~0U)
237 pModElf->Rel.paSyms = (const Elf_Sym *)(pu8 + pModElf->paShdrs[pModElf->Rel.iSymSh].sh_offset);
238 if (pModElf->Rel.iStrSh != ~0U)
239 pModElf->Rel.pStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->Rel.iStrSh].sh_offset);
240 if (pModElf->Dyn.iSymSh != ~0U)
241 pModElf->Dyn.paSyms = (const Elf_Sym *)(pu8 + pModElf->paShdrs[pModElf->Dyn.iSymSh].sh_offset);
242 if (pModElf->Dyn.iStrSh != ~0U)
243 pModElf->Dyn.pStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->Dyn.iStrSh].sh_offset);
244 pModElf->pShStr = (const char *)(pu8 + pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_offset);
245
246 /*
247 * Verify that the ends of the string tables have a zero terminator
248 * (this avoids duplicating the appropriate checks later in the code accessing the string tables).
249 *
250 * sh_offset and sh_size were verfied in RTLDRELF_NAME(ValidateSectionHeader)() already so they
251 * are safe to use.
252 */
253 AssertMsgStmt( pModElf->Rel.iStrSh == ~0U
254 || pModElf->Rel.pStr[pModElf->paShdrs[pModElf->Rel.iStrSh].sh_size - 1] == '\0',
255 ("The string table is not zero terminated!\n"),
256 rc = VERR_LDRELF_UNTERMINATED_STRING_TAB);
257 AssertMsgStmt( pModElf->Dyn.iStrSh == ~0U
258 || pModElf->Dyn.pStr[pModElf->paShdrs[pModElf->Dyn.iStrSh].sh_size - 1] == '\0',
259 ("The string table is not zero terminated!\n"),
260 rc = VERR_LDRELF_UNTERMINATED_STRING_TAB);
261 AssertMsgStmt(pModElf->pShStr[pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_size - 1] == '\0',
262 ("The section header string table is not zero terminated!\n"),
263 rc = VERR_LDRELF_UNTERMINATED_STRING_TAB);
264
265 if (RT_FAILURE(rc))
266 {
267 /* Unmap. */
268 int rc2 = pModElf->Core.pReader->pfnUnmap(pModElf->Core.pReader, pModElf->pvBits);
269 AssertRC(rc2);
270 pModElf->pvBits = NULL;
271 pModElf->Rel.paSyms = NULL;
272 pModElf->Rel.pStr = NULL;
273 pModElf->Dyn.paSyms = NULL;
274 pModElf->Dyn.pStr = NULL;
275 pModElf->pShStr = NULL;
276 }
277 }
278 return rc;
279}
280
281
282/*
283 *
284 * EXEC & DYN.
285 * EXEC & DYN.
286 * EXEC & DYN.
287 * EXEC & DYN.
288 * EXEC & DYN.
289 *
290 */
291
292/**
293 * Get the symbol and symbol value.
294 *
295 * @returns iprt status code.
296 * @param pModElf The ELF loader module instance data.
297 * @param BaseAddr The base address which the module is being fixedup to.
298 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
299 * @param pvUser User argument to pass to the callback.
300 * @param iSym The symbol to get.
301 * @param ppSym Where to store the symbol pointer on success. (read only)
302 * @param pSymValue Where to store the symbol value on success.
303 */
304static int RTLDRELF_NAME(SymbolExecDyn)(PRTLDRMODELF pModElf, Elf_Addr BaseAddr, PFNRTLDRIMPORT pfnGetImport, void *pvUser,
305 Elf_Size iSym, const Elf_Sym **ppSym, Elf_Addr *pSymValue)
306{
307 /*
308 * Validate and find the symbol.
309 */
310 AssertMsgReturn(iSym < pModElf->Dyn.cSyms, ("iSym=%d is an invalid symbol index!\n", iSym), VERR_LDRELF_INVALID_SYMBOL_INDEX);
311 const Elf_Sym *pSym = &pModElf->Dyn.paSyms[iSym];
312 *ppSym = pSym;
313
314 AssertMsgReturn(pSym->st_name < pModElf->Dyn.cbStr,
315 ("iSym=%d st_name=%d str sh_size=%d\n", iSym, pSym->st_name, pModElf->Dyn.cbStr),
316 VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET);
317 const char * const pszName = pModElf->Dyn.pStr + pSym->st_name;
318
319 /*
320 * Determine the symbol value.
321 *
322 * Symbols needs different treatment depending on which section their are in.
323 * Undefined and absolute symbols goes into special non-existing sections.
324 */
325 switch (pSym->st_shndx)
326 {
327 /*
328 * Undefined symbol, needs resolving.
329 *
330 * Since ELF has no generic concept of importing from specific module (the OS/2 ELF format
331 * has but that's an OS extension and only applies to programs and dlls), we'll have to ask
332 * the resolver callback to do a global search.
333 */
334 case SHN_UNDEF:
335 {
336 /* Try to resolve the symbol. */
337 RTUINTPTR Value;
338 int rc = pfnGetImport(&pModElf->Core, "", pszName, ~0U, &Value, pvUser);
339 AssertMsgRCReturn(rc, ("Failed to resolve '%s' (iSym=" FMT_ELF_SIZE " rc=%Rrc\n", pszName, iSym, rc), rc);
340
341 *pSymValue = (Elf_Addr)Value;
342 AssertMsgReturn((RTUINTPTR)*pSymValue == Value,
343 ("Symbol value overflowed! '%s' (iSym=" FMT_ELF_SIZE "\n", pszName, iSym), VERR_SYMBOL_VALUE_TOO_BIG);
344
345 Log2(("rtldrELF: #%-3d - UNDEF " FMT_ELF_ADDR " '%s'\n", iSym, *pSymValue, pszName));
346 break;
347 }
348
349 /*
350 * Absolute symbols needs no fixing since they are, well, absolute.
351 */
352 case SHN_ABS:
353 *pSymValue = pSym->st_value;
354 Log2(("rtldrELF: #%-3d - ABS " FMT_ELF_ADDR " '%s'\n", iSym, *pSymValue, pszName));
355 break;
356
357 /*
358 * All other symbols are addressed relative the image base in DYN and EXEC binaries.
359 */
360 default:
361 AssertMsgReturn(pSym->st_shndx < pModElf->Ehdr.e_shnum,
362 ("iSym=%d st_shndx=%d e_shnum=%d pszName=%s\n", iSym, pSym->st_shndx, pModElf->Ehdr.e_shnum, pszName),
363 VERR_BAD_EXE_FORMAT);
364 *pSymValue = pSym->st_value + BaseAddr;
365 Log2(("rtldrELF: #%-3d - %5d " FMT_ELF_ADDR " '%s'\n", iSym, pSym->st_shndx, *pSymValue, pszName));
366 break;
367 }
368
369 return VINF_SUCCESS;
370}
371
372
373#if ELF_MODE == 32
374/** Helper for RelocateSectionExecDyn. */
375DECLINLINE(const Elf_Shdr *) RTLDRELF_NAME(RvaToSectionHeader)(PRTLDRMODELF pModElf, Elf_Addr uRva)
376{
377 const Elf_Shdr * const pShdrFirst = pModElf->paShdrs;
378 const Elf_Shdr *pShdr = pShdrFirst + pModElf->Ehdr.e_shnum;
379 while (--pShdr != pShdrFirst)
380 if (uRva - pShdr->sh_addr /*rva*/ < pShdr->sh_size)
381 return pShdr;
382 AssertFailed();
383 return pShdr;
384}
385#endif
386
387
388/**
389 * Applies the fixups for a section in an executable image.
390 *
391 * @returns iprt status code.
392 * @param pModElf The ELF loader module instance data.
393 * @param BaseAddr The base address which the module is being fixedup to.
394 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
395 * @param pvUser User argument to pass to the callback.
396 * @param SecAddr The section address. This is the address the relocations are relative to.
397 * @param cbSec The section size. The relocations must be inside this.
398 * @param pu8SecBaseR Where we read section bits from.
399 * @param pu8SecBaseW Where we write section bits to.
400 * @param pvRelocs Pointer to where we read the relocations from.
401 * @param cbRelocs Size of the relocations.
402 */
403static int RTLDRELF_NAME(RelocateSectionExecDyn)(PRTLDRMODELF pModElf, Elf_Addr BaseAddr,
404 PFNRTLDRIMPORT pfnGetImport, void *pvUser,
405 const Elf_Addr SecAddr, Elf_Size cbSec,
406 const uint8_t *pu8SecBaseR, uint8_t *pu8SecBaseW,
407 const void *pvRelocs, Elf_Size cbRelocs)
408{
409#if ELF_MODE != 32
410 NOREF(pu8SecBaseR);
411#endif
412
413 /*
414 * Iterate the relocations.
415 * The relocations are stored in an array of Elf32_Rel records and covers the entire relocation section.
416 */
417#if ELF_MODE == 32
418 const Elf_Shdr *pShdr = pModElf->paShdrs;
419 const Elf_Addr offDelta = BaseAddr - pModElf->LinkAddress;
420#endif
421 const Elf_Reloc *paRels = (const Elf_Reloc *)pvRelocs;
422 const unsigned iRelMax = (unsigned)(cbRelocs / sizeof(paRels[0]));
423 AssertMsgReturn(iRelMax == cbRelocs / sizeof(paRels[0]), (FMT_ELF_SIZE "\n", cbRelocs / sizeof(paRels[0])),
424 VERR_IMAGE_TOO_BIG);
425 for (unsigned iRel = 0; iRel < iRelMax; iRel++)
426 {
427 /*
428 * Apply fixups not taking a symbol (will 'continue' rather than 'break').
429 */
430 AssertMsgReturn(paRels[iRel].r_offset < cbSec, (FMT_ELF_ADDR " " FMT_ELF_SIZE "\n", paRels[iRel].r_offset, cbSec),
431 VERR_LDRELF_INVALID_RELOCATION_OFFSET);
432#if ELF_MODE == 32
433 if (paRels[iRel].r_offset - pShdr->sh_addr /*rva*/ >= pShdr->sh_size)
434 pShdr = RTLDRELF_NAME(RvaToSectionHeader)(pModElf, paRels[iRel].r_offset);
435 static const Elf_Addr s_uZero = 0;
436 const Elf_Addr *pAddrR = RT_LIKELY(pShdr->sh_type != SHT_NOBITS) /* Where to read the addend. */
437 ? (const Elf_Addr *)(pu8SecBaseR + paRels[iRel].r_offset - pShdr->sh_addr /*rva*/
438 + pShdr->sh_offset)
439 : &s_uZero;
440#endif
441 Elf_Addr *pAddrW = (Elf_Addr *)(pu8SecBaseW + paRels[iRel].r_offset); /* Where to write the fixup. */
442 switch (ELF_R_TYPE(paRels[iRel].r_info))
443 {
444 /*
445 * Image relative (addend + base).
446 */
447#if ELF_MODE == 32
448 case R_386_RELATIVE:
449 {
450 const Elf_Addr Value = *pAddrR + BaseAddr;
451 *(uint32_t *)pAddrW = Value;
452 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_386_RELATIVE Value=" FMT_ELF_ADDR "\n",
453 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value));
454 AssertCompile(sizeof(Value) == sizeof(uint32_t));
455 continue;
456 }
457#elif ELF_MODE == 64
458 case R_X86_64_RELATIVE:
459 {
460 const Elf_Addr Value = paRels[iRel].r_addend + BaseAddr;
461 *(uint64_t *)pAddrW = (uint64_t)Value;
462 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_RELATIVE Value=" FMT_ELF_ADDR "\n",
463 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value));
464 AssertCompile(sizeof(Value) == sizeof(uint64_t));
465 continue;
466 }
467#endif
468
469 /*
470 * R_XXX_NONE.
471 */
472#if ELF_MODE == 32
473 case R_386_NONE:
474#elif ELF_MODE == 64
475 case R_X86_64_NONE:
476#endif
477 continue;
478 }
479
480 /*
481 * Validate and find the symbol, resolve undefined ones.
482 */
483 const Elf_Sym *pSym = NULL; /* shut up gcc */
484 Elf_Addr SymValue = 0; /* shut up gcc-4 */
485 int rc = RTLDRELF_NAME(SymbolExecDyn)(pModElf, BaseAddr, pfnGetImport, pvUser, ELF_R_SYM(paRels[iRel].r_info), &pSym, &SymValue);
486 if (RT_FAILURE(rc))
487 return rc;
488
489 /*
490 * Apply the fixup.
491 */
492 switch (ELF_R_TYPE(paRels[iRel].r_info))
493 {
494#if ELF_MODE == 32
495 /*
496 * GOT/PLT.
497 */
498 case R_386_GLOB_DAT:
499 {
500 *(uint32_t *)pAddrW = (uint32_t)SymValue;
501 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_386_GLOB_DAT Value=" FMT_ELF_ADDR "\n",
502 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, SymValue));
503 AssertCompile(sizeof(SymValue) == sizeof(uint32_t));
504 break;
505 }
506
507 case R_386_JMP_SLOT:
508 {
509 *(uint32_t *)pAddrW = (uint32_t)SymValue;
510 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_386_JMP_SLOT Value=" FMT_ELF_ADDR "\n",
511 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, SymValue));
512 AssertCompile(sizeof(SymValue) == sizeof(uint32_t));
513 break;
514 }
515
516 /*
517 * Absolute addressing.
518 */
519 case R_386_32:
520 {
521 Elf_Addr Value;
522 if (pSym->st_shndx < pModElf->Ehdr.e_shnum)
523 Value = *pAddrR + offDelta; /* Simplified. */
524 else if (pSym->st_shndx == SHN_ABS)
525 continue; /* Internal fixup, no need to apply it. */
526 else if (pSym->st_shndx == SHN_UNDEF)
527 Value = SymValue + *pAddrR;
528 else
529 AssertFailedReturn(VERR_LDR_GENERAL_FAILURE); /** @todo SHN_COMMON */
530 *(uint32_t *)pAddrW = Value;
531 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_386_32 Value=" FMT_ELF_ADDR "\n",
532 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value));
533 break;
534 }
535
536 /*
537 * PC relative addressing.
538 */
539 case R_386_PC32:
540 {
541 Elf_Addr Value;
542 if (pSym->st_shndx < pModElf->Ehdr.e_shnum)
543 continue; /* Internal fixup, no need to apply it. */
544 else if (pSym->st_shndx == SHN_ABS)
545 Value = *pAddrR + offDelta; /* Simplified. */
546 else if (pSym->st_shndx == SHN_UNDEF)
547 {
548 const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
549 Value = SymValue + *(uint32_t *)pAddrR - SourceAddr;
550 *(uint32_t *)pAddrW = Value;
551 }
552 else
553 AssertFailedReturn(VERR_LDR_GENERAL_FAILURE); /** @todo SHN_COMMON */
554 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_386_PC32 Value=" FMT_ELF_ADDR "\n",
555 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value));
556 break;
557 }
558
559#elif ELF_MODE == 64
560 /*
561 * GOT/PLT.
562 */
563 case R_X86_64_GLOB_DAT:
564 {
565 *(uint64_t *)pAddrW = (uint64_t)SymValue;
566 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_GLOB_DAT Value=" FMT_ELF_ADDR "\n",
567 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, SymValue));
568 AssertCompile(sizeof(SymValue) == sizeof(uint64_t));
569 break;
570 }
571
572 case R_X86_64_JMP_SLOT:
573 {
574 *(uint64_t *)pAddrW = (uint64_t)SymValue;
575 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_JMP_SLOT Value=" FMT_ELF_ADDR "\n",
576 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, SymValue));
577 AssertCompile(sizeof(SymValue) == sizeof(uint64_t));
578 break;
579 }
580
581 /*
582 * Absolute addressing.
583 */
584 case R_X86_64_64:
585 {
586 const Elf_Addr Value = SymValue + paRels[iRel].r_addend;
587 *(uint64_t *)pAddrW = Value;
588 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_64 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
589 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value, SymValue));
590 break;
591 }
592
593 /*
594 * Truncated 32-bit value (zero-extendedable to the 64-bit value).
595 */
596 case R_X86_64_32:
597 {
598 const Elf_Addr Value = SymValue + paRels[iRel].r_addend;
599 *(uint32_t *)pAddrW = (uint32_t)Value;
600 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
601 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value, SymValue));
602 AssertMsgReturn((Elf_Addr)*(uint32_t *)pAddrW == SymValue, ("Value=" FMT_ELF_ADDR "\n", SymValue),
603 VERR_SYMBOL_VALUE_TOO_BIG);
604 break;
605 }
606
607 /*
608 * Truncated 32-bit value (sign-extendedable to the 64-bit value).
609 */
610 case R_X86_64_32S:
611 {
612 const Elf_Addr Value = SymValue + paRels[iRel].r_addend;
613 *(int32_t *)pAddrW = (int32_t)Value;
614 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_32S Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
615 SecAddr + paRels[iRel].r_offset + BaseAddr, paRels[iRel].r_offset, Value, SymValue));
616 AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
617 break;
618 }
619
620 /*
621 * PC relative addressing.
622 */
623 case R_X86_64_PC32:
624 {
625 const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
626 const Elf_Addr Value = SymValue + paRels[iRel].r_addend - SourceAddr;
627 *(int32_t *)pAddrW = (int32_t)Value;
628 Log4((FMT_ELF_ADDR "/" FMT_ELF_ADDR7 ": R_X86_64_PC32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
629 SourceAddr, paRels[iRel].r_offset, Value, SymValue));
630 AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
631 break;
632 }
633
634#endif
635 default:
636 AssertMsgFailed(("Unknown relocation type: %d (iRel=%d iRelMax=%d)\n",
637 ELF_R_TYPE(paRels[iRel].r_info), iRel, iRelMax));
638 return VERR_LDRELF_RELOCATION_NOT_SUPPORTED;
639 }
640 }
641
642 return VINF_SUCCESS;
643}
644
645
646
647/*
648 *
649 * REL
650 * REL
651 * REL
652 * REL
653 * REL
654 *
655 */
656
657/**
658 * Get the symbol and symbol value.
659 *
660 * @returns iprt status code.
661 * @param pModElf The ELF loader module instance data.
662 * @param BaseAddr The base address which the module is being fixedup to.
663 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
664 * @param pvUser User argument to pass to the callback.
665 * @param iSym The symbol to get.
666 * @param ppSym Where to store the symbol pointer on success. (read only)
667 * @param pSymValue Where to store the symbol value on success.
668 */
669static int RTLDRELF_NAME(Symbol)(PRTLDRMODELF pModElf, Elf_Addr BaseAddr, PFNRTLDRIMPORT pfnGetImport, void *pvUser,
670 Elf_Size iSym, const Elf_Sym **ppSym, Elf_Addr *pSymValue)
671{
672 /*
673 * Validate and find the symbol.
674 */
675 AssertMsgReturn(iSym < pModElf->Rel.cSyms, ("iSym=%d is an invalid symbol index!\n", iSym), VERR_LDRELF_INVALID_SYMBOL_INDEX);
676 const Elf_Sym *pSym = &pModElf->Rel.paSyms[iSym];
677 *ppSym = pSym;
678
679 AssertMsgReturn(pSym->st_name < pModElf->Rel.cbStr,
680 ("iSym=%d st_name=%d str sh_size=%d\n", iSym, pSym->st_name, pModElf->Rel.cbStr),
681 VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET);
682 const char *pszName = ELF_STR(pModElf, pSym->st_name);
683
684 /*
685 * Determine the symbol value.
686 *
687 * Symbols needs different treatment depending on which section their are in.
688 * Undefined and absolute symbols goes into special non-existing sections.
689 */
690 switch (pSym->st_shndx)
691 {
692 /*
693 * Undefined symbol, needs resolving.
694 *
695 * Since ELF has no generic concept of importing from specific module (the OS/2 ELF format
696 * has but that's an OS extension and only applies to programs and dlls), we'll have to ask
697 * the resolver callback to do a global search.
698 */
699 case SHN_UNDEF:
700 {
701 /* Try to resolve the symbol. */
702 RTUINTPTR Value;
703 int rc = pfnGetImport(&pModElf->Core, "", pszName, ~0U, &Value, pvUser);
704 AssertMsgRCReturn(rc, ("Failed to resolve '%s' (iSym=" FMT_ELF_SIZE " rc=%Rrc\n", pszName, iSym, rc), rc);
705 *pSymValue = (Elf_Addr)Value;
706
707 AssertMsgReturn((RTUINTPTR)*pSymValue == Value,
708 ("Symbol value overflowed! '%s' (iSym=" FMT_ELF_SIZE ")\n", pszName, iSym),
709 VERR_SYMBOL_VALUE_TOO_BIG);
710
711 Log2(("rtldrELF: #%-3d - UNDEF " FMT_ELF_ADDR " '%s'\n", iSym, *pSymValue, pszName));
712 break;
713 }
714
715 /*
716 * Absolute symbols needs no fixing since they are, well, absolute.
717 */
718 case SHN_ABS:
719 *pSymValue = pSym->st_value;
720 Log2(("rtldrELF: #%-3d - ABS " FMT_ELF_ADDR " '%s'\n", iSym, *pSymValue, pszName));
721 break;
722
723 /*
724 * All other symbols are addressed relative to their section and need to be fixed up.
725 */
726 default:
727 if (pSym->st_shndx >= pModElf->Ehdr.e_shnum)
728 {
729 /* what about common symbols? */
730 AssertMsg(pSym->st_shndx < pModElf->Ehdr.e_shnum,
731 ("iSym=%d st_shndx=%d e_shnum=%d pszName=%s\n", iSym, pSym->st_shndx, pModElf->Ehdr.e_shnum, pszName));
732 return VERR_BAD_EXE_FORMAT;
733 }
734 *pSymValue = pSym->st_value + pModElf->paShdrs[pSym->st_shndx].sh_addr + BaseAddr;
735 Log2(("rtldrELF: #%-3d - %5d " FMT_ELF_ADDR " '%s'\n", iSym, pSym->st_shndx, *pSymValue, pszName));
736 break;
737 }
738
739 return VINF_SUCCESS;
740}
741
742
743/**
744 * Applies the fixups for a sections.
745 *
746 * @returns iprt status code.
747 * @param pModElf The ELF loader module instance data.
748 * @param BaseAddr The base address which the module is being fixedup to.
749 * @param pfnGetImport The callback function to use to resolve imports (aka unresolved externals).
750 * @param pvUser User argument to pass to the callback.
751 * @param SecAddr The section address. This is the address the relocations are relative to.
752 * @param cbSec The section size. The relocations must be inside this.
753 * @param pu8SecBaseR Where we read section bits from.
754 * @param pu8SecBaseW Where we write section bits to.
755 * @param pvRelocs Pointer to where we read the relocations from.
756 * @param cbRelocs Size of the relocations.
757 */
758static int RTLDRELF_NAME(RelocateSectionRel)(PRTLDRMODELF pModElf, Elf_Addr BaseAddr, PFNRTLDRIMPORT pfnGetImport, void *pvUser,
759 const Elf_Addr SecAddr, Elf_Size cbSec, const uint8_t *pu8SecBaseR,
760 uint8_t *pu8SecBaseW, const void *pvRelocs, Elf_Size cbRelocs)
761{
762#if ELF_MODE != 32
763 NOREF(pu8SecBaseR);
764#endif
765
766 /*
767 * Iterate the relocations.
768 * The relocations are stored in an array of Elf32_Rel records and covers the entire relocation section.
769 */
770 const Elf_Reloc *paRels = (const Elf_Reloc *)pvRelocs;
771 const unsigned iRelMax = (unsigned)(cbRelocs / sizeof(paRels[0]));
772 AssertMsgReturn(iRelMax == cbRelocs / sizeof(paRels[0]), (FMT_ELF_SIZE "\n", cbRelocs / sizeof(paRels[0])), VERR_IMAGE_TOO_BIG);
773 for (unsigned iRel = 0; iRel < iRelMax; iRel++)
774 {
775 /*
776 * Skip R_XXX_NONE entries early to avoid confusion in the symbol
777 * getter code.
778 */
779#if ELF_MODE == 32
780 if (ELF_R_TYPE(paRels[iRel].r_info) == R_386_NONE)
781 continue;
782#elif ELF_MODE == 64
783 if (ELF_R_TYPE(paRels[iRel].r_info) == R_X86_64_NONE)
784 continue;
785#endif
786
787
788 /*
789 * Get the symbol.
790 */
791 const Elf_Sym *pSym = NULL; /* shut up gcc */
792 Elf_Addr SymValue = 0; /* shut up gcc-4 */
793 int rc = RTLDRELF_NAME(Symbol)(pModElf, BaseAddr, pfnGetImport, pvUser, ELF_R_SYM(paRels[iRel].r_info), &pSym, &SymValue);
794 if (RT_FAILURE(rc))
795 return rc;
796
797 Log3(("rtldrELF: " FMT_ELF_ADDR " %02x %06x - " FMT_ELF_ADDR " %3d %02x %s\n",
798 paRels[iRel].r_offset, ELF_R_TYPE(paRels[iRel].r_info), (unsigned)ELF_R_SYM(paRels[iRel].r_info),
799 SymValue, (unsigned)pSym->st_shndx, pSym->st_info, ELF_STR(pModElf, pSym->st_name)));
800
801 /*
802 * Apply the fixup.
803 */
804 AssertMsgReturn(paRels[iRel].r_offset < cbSec, (FMT_ELF_ADDR " " FMT_ELF_SIZE "\n", paRels[iRel].r_offset, cbSec), VERR_LDRELF_INVALID_RELOCATION_OFFSET);
805#if ELF_MODE == 32
806 const Elf_Addr *pAddrR = (const Elf_Addr *)(pu8SecBaseR + paRels[iRel].r_offset); /* Where to read the addend. */
807#endif
808 Elf_Addr *pAddrW = (Elf_Addr *)(pu8SecBaseW + paRels[iRel].r_offset); /* Where to write the fixup. */
809 switch (ELF_R_TYPE(paRels[iRel].r_info))
810 {
811#if ELF_MODE == 32
812 /*
813 * Absolute addressing.
814 */
815 case R_386_32:
816 {
817 const Elf_Addr Value = SymValue + *pAddrR;
818 *(uint32_t *)pAddrW = Value;
819 Log4((FMT_ELF_ADDR": R_386_32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
820 SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
821 break;
822 }
823
824 /*
825 * PC relative addressing.
826 */
827 case R_386_PC32:
828 {
829 const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
830 const Elf_Addr Value = SymValue + *(uint32_t *)pAddrR - SourceAddr;
831 *(uint32_t *)pAddrW = Value;
832 Log4((FMT_ELF_ADDR": R_386_PC32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
833 SourceAddr, Value, SymValue));
834 break;
835 }
836
837 /* ignore */
838 case R_386_NONE:
839 break;
840
841#elif ELF_MODE == 64
842
843 /*
844 * Absolute addressing
845 */
846 case R_X86_64_64:
847 {
848 const Elf_Addr Value = SymValue + paRels[iRel].r_addend;
849 *(uint64_t *)pAddrW = Value;
850 Log4((FMT_ELF_ADDR": R_X86_64_64 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
851 SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
852 break;
853 }
854
855 /*
856 * Truncated 32-bit value (zero-extendedable to the 64-bit value).
857 */
858 case R_X86_64_32:
859 {
860 const Elf_Addr Value = SymValue + paRels[iRel].r_addend;
861 *(uint32_t *)pAddrW = (uint32_t)Value;
862 Log4((FMT_ELF_ADDR": R_X86_64_32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
863 SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
864 AssertMsgReturn((Elf_Addr)*(uint32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG);
865 break;
866 }
867
868 /*
869 * Truncated 32-bit value (sign-extendedable to the 64-bit value).
870 */
871 case R_X86_64_32S:
872 {
873 const Elf_Addr Value = SymValue + paRels[iRel].r_addend;
874 *(int32_t *)pAddrW = (int32_t)Value;
875 Log4((FMT_ELF_ADDR": R_X86_64_32S Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
876 SecAddr + paRels[iRel].r_offset + BaseAddr, Value, SymValue));
877 AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
878 break;
879 }
880
881 /*
882 * PC relative addressing.
883 */
884 case R_X86_64_PC32:
885 case R_X86_64_PLT32: /* binutils commit 451875b4f976a527395e9303224c7881b65e12ed feature/regression. */
886 {
887 const Elf_Addr SourceAddr = SecAddr + paRels[iRel].r_offset + BaseAddr; /* Where the source really is. */
888 const Elf_Addr Value = SymValue + paRels[iRel].r_addend - SourceAddr;
889 *(int32_t *)pAddrW = (int32_t)Value;
890 Log4((FMT_ELF_ADDR": R_X86_64_PC32 Value=" FMT_ELF_ADDR " SymValue=" FMT_ELF_ADDR "\n",
891 SourceAddr, Value, SymValue));
892 AssertMsgReturn((Elf_Addr)*(int32_t *)pAddrW == Value, ("Value=" FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG); /** @todo check the sign-extending here. */
893 break;
894 }
895
896 /* ignore */
897 case R_X86_64_NONE:
898 break;
899#endif
900
901 default:
902 AssertMsgFailed(("Unknown relocation type: %d (iRel=%d iRelMax=%d)\n",
903 ELF_R_TYPE(paRels[iRel].r_info), iRel, iRelMax));
904 return VERR_LDRELF_RELOCATION_NOT_SUPPORTED;
905 }
906 }
907
908 return VINF_SUCCESS;
909}
910
911
912
913/** @copydoc RTLDROPS::pfnClose */
914static DECLCALLBACK(int) RTLDRELF_NAME(Close)(PRTLDRMODINTERNAL pMod)
915{
916 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
917
918 if (pModElf->paShdrs)
919 {
920 RTMemFree(pModElf->paShdrs);
921 pModElf->paShdrs = NULL;
922 }
923
924 if (pModElf->paPhdrs)
925 {
926 RTMemFree(pModElf->paPhdrs);
927 pModElf->paPhdrs = NULL;
928 }
929
930 if (pModElf->paDynamic)
931 {
932 RTMemFree(pModElf->paDynamic);
933 pModElf->paDynamic = NULL;
934 }
935
936 if (pModElf->pvBits)
937 {
938 pModElf->Core.pReader->pfnUnmap(pModElf->Core.pReader, pModElf->pvBits);
939 pModElf->pvBits = NULL;
940 }
941
942 return VINF_SUCCESS;
943}
944
945
946/** @copydoc RTLDROPS::Done */
947static DECLCALLBACK(int) RTLDRELF_NAME(Done)(PRTLDRMODINTERNAL pMod)
948{
949 NOREF(pMod); /*PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;*/
950 /** @todo Have to think more about this .... */
951 return -1;
952}
953
954
955/** @copydoc RTLDROPS::pfnEnumSymbols */
956static DECLCALLBACK(int) RTLDRELF_NAME(EnumSymbols)(PRTLDRMODINTERNAL pMod, unsigned fFlags, const void *pvBits,
957 RTUINTPTR BaseAddress, PFNRTLDRENUMSYMS pfnCallback, void *pvUser)
958{
959 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
960 NOREF(pvBits);
961
962 /*
963 * Validate the input.
964 */
965 Elf_Addr BaseAddr = (Elf_Addr)BaseAddress;
966 AssertMsgReturn((RTUINTPTR)BaseAddr == BaseAddress, ("%RTptr", BaseAddress), VERR_IMAGE_BASE_TOO_HIGH);
967
968 /*
969 * Make sure we've got the string and symbol tables. (We don't need the pvBits.)
970 */
971 int rc = RTLDRELF_NAME(MapBits)(pModElf, false);
972 if (RT_FAILURE(rc))
973 return rc;
974
975 /*
976 * Enumerate the symbol table.
977 */
978 const Elf_Sym *paSyms = pModElf->Rel.paSyms;
979 unsigned cSyms = pModElf->Rel.cSyms;
980 const char *pszzStr = pModElf->Rel.pStr;
981 unsigned cbStr = pModElf->Rel.cbStr;
982 if ( ( !(fFlags & RTLDR_ENUM_SYMBOL_FLAGS_ALL)
983 && pModElf->Dyn.cSyms > 0)
984 || cSyms == 0)
985 {
986 paSyms = pModElf->Dyn.paSyms;
987 cSyms = pModElf->Dyn.cSyms;
988 pszzStr = pModElf->Dyn.pStr;
989 cbStr = pModElf->Dyn.cbStr;
990 }
991
992 for (unsigned iSym = 1; iSym < cSyms; iSym++)
993 {
994 /*
995 * Skip imports (undefined).
996 */
997 if (paSyms[iSym].st_shndx != SHN_UNDEF)
998 {
999 /*
1000 * Calc value and get name.
1001 */
1002 Elf_Addr Value;
1003 if (paSyms[iSym].st_shndx == SHN_ABS)
1004 /* absolute symbols are not subject to any relocation. */
1005 Value = paSyms[iSym].st_value;
1006 else if (paSyms[iSym].st_shndx < pModElf->Ehdr.e_shnum)
1007 {
1008 if (pModElf->Ehdr.e_type == ET_REL)
1009 /* relative to the section. */
1010 Value = BaseAddr + paSyms[iSym].st_value + pModElf->paShdrs[paSyms[iSym].st_shndx].sh_addr;
1011 else /* Fixed up for link address. */
1012 Value = BaseAddr + paSyms[iSym].st_value - pModElf->LinkAddress;
1013 }
1014 else
1015 {
1016 AssertMsgFailed(("Arg! paSyms[%u].st_shndx=" FMT_ELF_HALF "\n", iSym, paSyms[iSym].st_shndx));
1017 return VERR_BAD_EXE_FORMAT;
1018 }
1019
1020 AssertMsgReturn(paSyms[iSym].st_name < cbStr,
1021 ("String outside string table! iSym=%d paSyms[iSym].st_name=%#x\n", iSym, paSyms[iSym].st_name),
1022 VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET);
1023 const char * const pszName = pszzStr + paSyms[iSym].st_name;
1024
1025 /* String termination was already checked when the string table was mapped. */
1026 if ( *pszName != '\0'
1027 && ( (fFlags & RTLDR_ENUM_SYMBOL_FLAGS_ALL)
1028 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL) )
1029 {
1030 /*
1031 * Call back.
1032 */
1033 AssertMsgReturn(Value == (RTUINTPTR)Value, (FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG);
1034 rc = pfnCallback(pMod, pszName, iSym, (RTUINTPTR)Value, pvUser);
1035 if (rc)
1036 return rc;
1037 }
1038 }
1039 }
1040
1041 return VINF_SUCCESS;
1042}
1043
1044
1045/** @copydoc RTLDROPS::GetImageSize */
1046static DECLCALLBACK(size_t) RTLDRELF_NAME(GetImageSize)(PRTLDRMODINTERNAL pMod)
1047{
1048 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1049
1050 return pModElf->cbImage;
1051}
1052
1053
1054/** @copydoc RTLDROPS::GetBits */
1055static DECLCALLBACK(int) RTLDRELF_NAME(GetBits)(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR BaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
1056{
1057 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1058
1059 /*
1060 * This operation is currently only available on relocatable images.
1061 */
1062 switch (pModElf->Ehdr.e_type)
1063 {
1064 case ET_REL:
1065 case ET_DYN:
1066 break;
1067 case ET_EXEC:
1068 Log(("RTLdrELF: %s: Executable images are not supported yet!\n", pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader)));
1069 return VERR_LDRELF_EXEC;
1070 default: AssertFailedReturn(VERR_BAD_EXE_FORMAT);
1071 }
1072
1073 /*
1074 * Load the bits into pvBits.
1075 */
1076 const Elf_Shdr *paShdrs = pModElf->paShdrs;
1077 for (unsigned iShdr = 0; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
1078 {
1079 if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
1080 {
1081 AssertMsgReturn((size_t)paShdrs[iShdr].sh_size == (size_t)paShdrs[iShdr].sh_size, (FMT_ELF_SIZE "\n", paShdrs[iShdr].sh_size), VERR_IMAGE_TOO_BIG);
1082 switch (paShdrs[iShdr].sh_type)
1083 {
1084 case SHT_NOBITS:
1085 memset((uint8_t *)pvBits + paShdrs[iShdr].sh_addr, 0, (size_t)paShdrs[iShdr].sh_size);
1086 break;
1087
1088 case SHT_PROGBITS:
1089 default:
1090 {
1091 int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, (uint8_t *)pvBits + paShdrs[iShdr].sh_addr,
1092 (size_t)paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset);
1093 if (RT_FAILURE(rc))
1094 {
1095 Log(("RTLdrELF: %s: Read error when reading " FMT_ELF_SIZE " bytes at " FMT_ELF_OFF ", iShdr=%d\n",
1096 pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader),
1097 paShdrs[iShdr].sh_size, paShdrs[iShdr].sh_offset, iShdr));
1098 return rc;
1099 }
1100 }
1101 }
1102 }
1103 }
1104
1105 /*
1106 * Relocate the image.
1107 */
1108 return pModElf->Core.pOps->pfnRelocate(pMod, pvBits, BaseAddress, ~(RTUINTPTR)0, pfnGetImport, pvUser);
1109}
1110
1111
1112/** @copydoc RTLDROPS::Relocate */
1113static DECLCALLBACK(int) RTLDRELF_NAME(Relocate)(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress,
1114 RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
1115{
1116 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1117#ifdef LOG_ENABLED
1118 const char *pszLogName = pModElf->Core.pReader->pfnLogName(pModElf->Core.pReader);
1119#endif
1120 NOREF(OldBaseAddress);
1121
1122 /*
1123 * This operation is currently only available on relocatable images.
1124 */
1125 switch (pModElf->Ehdr.e_type)
1126 {
1127 case ET_REL:
1128 case ET_DYN:
1129 break;
1130 case ET_EXEC:
1131 Log(("RTLdrELF: %s: Executable images are not supported yet!\n", pszLogName));
1132 return VERR_LDRELF_EXEC;
1133 default: AssertFailedReturn(VERR_BAD_EXE_FORMAT);
1134 }
1135
1136 /*
1137 * Validate the input.
1138 */
1139 Elf_Addr BaseAddr = (Elf_Addr)NewBaseAddress;
1140 AssertMsgReturn((RTUINTPTR)BaseAddr == NewBaseAddress, ("%RTptr", NewBaseAddress), VERR_IMAGE_BASE_TOO_HIGH);
1141
1142 /*
1143 * Map the image bits if not already done and setup pointer into it.
1144 */
1145 int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
1146 if (RT_FAILURE(rc))
1147 return rc;
1148
1149 /*
1150 * Iterate the sections looking for interesting SHT_REL[A] sections.
1151 *
1152 * In ET_REL files the SHT_REL[A] sections have the section index of
1153 * the section they contain fixups for in the sh_info member.
1154 */
1155 const Elf_Shdr *paShdrs = pModElf->paShdrs;
1156 Log2(("rtLdrElf: %s: Fixing up image\n", pszLogName));
1157 for (unsigned iShdr = 0; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
1158 {
1159 const Elf_Shdr *pShdrRel = &paShdrs[iShdr];
1160
1161 /*
1162 * Skip sections without interest to us.
1163 */
1164#if ELF_MODE == 32
1165 if (pShdrRel->sh_type != SHT_REL)
1166#else
1167 if (pShdrRel->sh_type != SHT_RELA)
1168#endif
1169 continue;
1170 if (pModElf->Ehdr.e_type == ET_REL)
1171 {
1172 if (pShdrRel->sh_info >= pModElf->Ehdr.e_shnum)
1173 continue;
1174 const Elf_Shdr *pShdr = &paShdrs[pShdrRel->sh_info]; /* the section to fixup. */
1175 if (!(pShdr->sh_flags & SHF_ALLOC))
1176 continue;
1177
1178 /*
1179 * Relocate the section.
1180 */
1181 Log2(("rtldrELF: %s: Relocation records for #%d [%s] (sh_info=%d sh_link=%d) found in #%d [%s] (sh_info=%d sh_link=%d)\n",
1182 pszLogName, (int)pShdrRel->sh_info, ELF_SH_STR(pModElf, pShdr->sh_name), (int)pShdr->sh_info, (int)pShdr->sh_link,
1183 iShdr, ELF_SH_STR(pModElf, pShdrRel->sh_name), (int)pShdrRel->sh_info, (int)pShdrRel->sh_link));
1184
1185 rc = RTLDRELF_NAME(RelocateSectionRel)(pModElf, BaseAddr, pfnGetImport, pvUser,
1186 pShdr->sh_addr,
1187 pShdr->sh_size,
1188 (const uint8_t *)pModElf->pvBits + pShdr->sh_offset,
1189 (uint8_t *)pvBits + pShdr->sh_addr,
1190 (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
1191 pShdrRel->sh_size);
1192 }
1193 else
1194 rc = RTLDRELF_NAME(RelocateSectionExecDyn)(pModElf, BaseAddr, pfnGetImport, pvUser,
1195 0, (Elf_Size)pModElf->cbImage,
1196 (const uint8_t *)pModElf->pvBits /** @todo file offset ?? */,
1197 (uint8_t *)pvBits,
1198 (const uint8_t *)pModElf->pvBits + pShdrRel->sh_offset,
1199 pShdrRel->sh_size);
1200
1201 if (RT_FAILURE(rc))
1202 return rc;
1203 }
1204 return VINF_SUCCESS;
1205}
1206
1207
1208/**
1209 * Worker for pfnGetSymbolEx.
1210 */
1211static int RTLDRELF_NAME(ReturnSymbol)(PRTLDRMODELF pThis, const Elf_Sym *pSym, Elf_Addr uBaseAddr, PRTUINTPTR pValue)
1212{
1213 Elf_Addr Value;
1214 if (pSym->st_shndx == SHN_ABS)
1215 /* absolute symbols are not subject to any relocation. */
1216 Value = pSym->st_value;
1217 else if (pSym->st_shndx < pThis->Ehdr.e_shnum)
1218 {
1219 if (pThis->Ehdr.e_type == ET_REL)
1220 /* relative to the section. */
1221 Value = uBaseAddr + pSym->st_value + pThis->paShdrs[pSym->st_shndx].sh_addr;
1222 else /* Fixed up for link address. */
1223 Value = uBaseAddr + pSym->st_value - pThis->LinkAddress;
1224 }
1225 else
1226 {
1227 AssertMsgFailed(("Arg! pSym->st_shndx=%d\n", pSym->st_shndx));
1228 return VERR_BAD_EXE_FORMAT;
1229 }
1230 AssertMsgReturn(Value == (RTUINTPTR)Value, (FMT_ELF_ADDR "\n", Value), VERR_SYMBOL_VALUE_TOO_BIG);
1231 *pValue = (RTUINTPTR)Value;
1232 return VINF_SUCCESS;
1233}
1234
1235
1236/** @copydoc RTLDROPS::pfnGetSymbolEx */
1237static DECLCALLBACK(int) RTLDRELF_NAME(GetSymbolEx)(PRTLDRMODINTERNAL pMod, const void *pvBits, RTUINTPTR BaseAddress,
1238 uint32_t iOrdinal, const char *pszSymbol, RTUINTPTR *pValue)
1239{
1240 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1241 NOREF(pvBits);
1242
1243 /*
1244 * Validate the input.
1245 */
1246 Elf_Addr uBaseAddr = (Elf_Addr)BaseAddress;
1247 AssertMsgReturn((RTUINTPTR)uBaseAddr == BaseAddress, ("%RTptr", BaseAddress), VERR_IMAGE_BASE_TOO_HIGH);
1248
1249 /*
1250 * Map the image bits if not already done and setup pointer into it.
1251 */
1252 int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
1253 if (RT_FAILURE(rc))
1254 return rc;
1255
1256 /*
1257 * Calc all kinds of pointers before we start iterating the symbol table.
1258 */
1259 const Elf_Sym *paSyms = pModElf->Rel.paSyms;
1260 unsigned cSyms = pModElf->Rel.cSyms;
1261 const char *pszzStr = pModElf->Rel.pStr;
1262 unsigned cbStr = pModElf->Rel.cbStr;
1263 if (pModElf->Dyn.cSyms > 0)
1264 {
1265 paSyms = pModElf->Dyn.paSyms;
1266 cSyms = pModElf->Dyn.cSyms;
1267 pszzStr = pModElf->Dyn.pStr;
1268 cbStr = pModElf->Dyn.cbStr;
1269 }
1270
1271 if (iOrdinal == UINT32_MAX)
1272 {
1273 for (unsigned iSym = 1; iSym < cSyms; iSym++)
1274 {
1275 /* Undefined symbols are not exports, they are imports. */
1276 if ( paSyms[iSym].st_shndx != SHN_UNDEF
1277 && ( ELF_ST_BIND(paSyms[iSym].st_info) == STB_GLOBAL
1278 || ELF_ST_BIND(paSyms[iSym].st_info) == STB_WEAK))
1279 {
1280 /* Validate the name string and try match with it. */
1281 AssertMsgReturn(paSyms[iSym].st_name < cbStr,
1282 ("String outside string table! iSym=%d paSyms[iSym].st_name=%#x\n", iSym, paSyms[iSym].st_name),
1283 VERR_LDRELF_INVALID_SYMBOL_NAME_OFFSET);
1284 if (!strcmp(pszSymbol, pszzStr + paSyms[iSym].st_name))
1285 {
1286 /* matched! */
1287 return RTLDRELF_NAME(ReturnSymbol)(pModElf, &paSyms[iSym], uBaseAddr, pValue);
1288 }
1289 }
1290 }
1291 }
1292 else if (iOrdinal < cSyms)
1293 {
1294 if ( paSyms[iOrdinal].st_shndx != SHN_UNDEF
1295 && ( ELF_ST_BIND(paSyms[iOrdinal].st_info) == STB_GLOBAL
1296 || ELF_ST_BIND(paSyms[iOrdinal].st_info) == STB_WEAK))
1297 return RTLDRELF_NAME(ReturnSymbol)(pModElf, &paSyms[iOrdinal], uBaseAddr, pValue);
1298 }
1299
1300 return VERR_SYMBOL_NOT_FOUND;
1301}
1302
1303
1304/** @copydoc RTLDROPS::pfnEnumDbgInfo */
1305static DECLCALLBACK(int) RTLDRELF_NAME(EnumDbgInfo)(PRTLDRMODINTERNAL pMod, const void *pvBits,
1306 PFNRTLDRENUMDBG pfnCallback, void *pvUser)
1307{
1308 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1309 RT_NOREF_PV(pvBits);
1310
1311 /*
1312 * Map the image bits if not already done and setup pointer into it.
1313 */
1314 int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
1315 if (RT_FAILURE(rc))
1316 return rc;
1317
1318 /*
1319 * Do the enumeration.
1320 */
1321 const Elf_Shdr *paShdrs = pModElf->paOrgShdrs;
1322 for (unsigned iShdr = 0; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
1323 {
1324 /* Debug sections are expected to be PROGBITS and not allocated. */
1325 if (paShdrs[iShdr].sh_type != SHT_PROGBITS)
1326 continue;
1327 if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
1328 continue;
1329
1330 RTLDRDBGINFO DbgInfo;
1331 const char *pszSectName = ELF_SH_STR(pModElf, paShdrs[iShdr].sh_name);
1332 if ( !strncmp(pszSectName, RT_STR_TUPLE(".debug_"))
1333 || !strcmp(pszSectName, ".WATCOM_references") )
1334 {
1335 RT_ZERO(DbgInfo.u);
1336 DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF;
1337 DbgInfo.pszExtFile = NULL;
1338 DbgInfo.offFile = paShdrs[iShdr].sh_offset;
1339 DbgInfo.cb = paShdrs[iShdr].sh_size;
1340 DbgInfo.u.Dwarf.pszSection = pszSectName;
1341 }
1342 else if (!strcmp(pszSectName, ".gnu_debuglink"))
1343 {
1344 if ((paShdrs[iShdr].sh_size & 3) || paShdrs[iShdr].sh_size < 8)
1345 return VERR_BAD_EXE_FORMAT;
1346
1347 RT_ZERO(DbgInfo.u);
1348 DbgInfo.enmType = RTLDRDBGINFOTYPE_DWARF_DWO;
1349 DbgInfo.pszExtFile = (const char *)((uintptr_t)pModElf->pvBits + (uintptr_t)paShdrs[iShdr].sh_offset);
1350 if (!RTStrEnd(DbgInfo.pszExtFile, paShdrs[iShdr].sh_size))
1351 return VERR_BAD_EXE_FORMAT;
1352 DbgInfo.u.Dwo.uCrc32 = *(uint32_t *)((uintptr_t)DbgInfo.pszExtFile + (uintptr_t)paShdrs[iShdr].sh_size
1353 - sizeof(uint32_t));
1354 DbgInfo.offFile = -1;
1355 DbgInfo.cb = 0;
1356 }
1357 else
1358 continue;
1359
1360 DbgInfo.LinkAddress = NIL_RTLDRADDR;
1361 DbgInfo.iDbgInfo = iShdr - 1;
1362
1363 rc = pfnCallback(pMod, &DbgInfo, pvUser);
1364 if (rc != VINF_SUCCESS)
1365 return rc;
1366
1367 }
1368
1369 return VINF_SUCCESS;
1370}
1371
1372
1373/**
1374 * Locate the next allocated section by RVA (sh_addr).
1375 *
1376 * This is a helper for EnumSegments and SegOffsetToRva.
1377 *
1378 * @returns Pointer to the section header if found, NULL if none.
1379 * @param pModElf The module instance.
1380 * @param iShdrCur The current section header.
1381 */
1382static const Elf_Shdr *RTLDRELF_NAME(GetNextAllocatedSection)(PRTLDRMODELF pModElf, unsigned iShdrCur)
1383{
1384 unsigned const cShdrs = pModElf->Ehdr.e_shnum;
1385 const Elf_Shdr * const paShdrs = pModElf->paShdrs;
1386 if (pModElf->fShdrInOrder)
1387 {
1388 for (unsigned iShdr = iShdrCur + 1; iShdr < cShdrs; iShdr++)
1389 if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
1390 return &paShdrs[iShdr];
1391 }
1392 else
1393 {
1394 Elf_Addr const uEndCur = paShdrs[iShdrCur].sh_addr + paShdrs[iShdrCur].sh_size;
1395 Elf_Addr offBest = ~(Elf_Addr)0;
1396 unsigned iBest = cShdrs;
1397 for (unsigned iShdr = pModElf->iFirstSect; iShdr < cShdrs; iShdr++)
1398 if ((paShdrs[iShdr].sh_flags & SHF_ALLOC) && iShdr != iShdrCur)
1399 {
1400 Elf_Addr const offDelta = paShdrs[iShdr].sh_addr - uEndCur;
1401 if ( offDelta < offBest
1402 && paShdrs[iShdr].sh_addr >= uEndCur)
1403 {
1404 offBest = offDelta;
1405 iBest = iShdr;
1406 }
1407 }
1408 if (iBest < cShdrs)
1409 return &paShdrs[iBest];
1410 }
1411 return NULL;
1412}
1413
1414
1415/** @copydoc RTLDROPS::pfnEnumSegments. */
1416static DECLCALLBACK(int) RTLDRELF_NAME(EnumSegments)(PRTLDRMODINTERNAL pMod, PFNRTLDRENUMSEGS pfnCallback, void *pvUser)
1417{
1418 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1419
1420 /*
1421 * Map the image bits if not already done and setup pointer into it.
1422 */
1423 int rc = RTLDRELF_NAME(MapBits)(pModElf, true);
1424 if (RT_FAILURE(rc))
1425 return rc;
1426
1427 /*
1428 * Do the enumeration.
1429 */
1430 char szName[32];
1431 Elf_Addr uPrevMappedRva = 0;
1432 const Elf_Shdr *paShdrs = pModElf->paShdrs;
1433 const Elf_Shdr *paOrgShdrs = pModElf->paOrgShdrs;
1434 for (unsigned iShdr = pModElf->iFirstSect; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
1435 {
1436 RTLDRSEG Seg;
1437 if (iShdr != 0)
1438 {
1439 Seg.pszName = ELF_SH_STR(pModElf, paShdrs[iShdr].sh_name);
1440 Seg.cchName = (uint32_t)strlen(Seg.pszName);
1441 if (Seg.cchName == 0)
1442 {
1443 Seg.pszName = szName;
1444 Seg.cchName = (uint32_t)RTStrPrintf(szName, sizeof(szName), "UnamedSect%02u", iShdr);
1445 }
1446 }
1447 else
1448 {
1449 Seg.pszName = ".elf.headers";
1450 Seg.cchName = 12;
1451 }
1452 Seg.SelFlat = 0;
1453 Seg.Sel16bit = 0;
1454 Seg.fFlags = 0;
1455 Seg.fProt = RTMEM_PROT_READ;
1456 if (paShdrs[iShdr].sh_flags & SHF_WRITE)
1457 Seg.fProt |= RTMEM_PROT_WRITE;
1458 if (paShdrs[iShdr].sh_flags & SHF_EXECINSTR)
1459 Seg.fProt |= RTMEM_PROT_EXEC;
1460 Seg.cb = paShdrs[iShdr].sh_size;
1461 Seg.Alignment = paShdrs[iShdr].sh_addralign;
1462 if (paShdrs[iShdr].sh_flags & SHF_ALLOC)
1463 {
1464 Seg.LinkAddress = paOrgShdrs[iShdr].sh_addr;
1465 Seg.RVA = paShdrs[iShdr].sh_addr;
1466 const Elf_Shdr *pShdr2 = RTLDRELF_NAME(GetNextAllocatedSection)(pModElf, iShdr);
1467 if (pShdr2)
1468 Seg.cbMapped = pShdr2->sh_addr - paShdrs[iShdr].sh_addr;
1469 else
1470 Seg.cbMapped = pModElf->cbImage - paShdrs[iShdr].sh_addr;
1471 uPrevMappedRva = Seg.RVA;
1472 }
1473 else
1474 {
1475 Seg.LinkAddress = NIL_RTLDRADDR;
1476 Seg.RVA = NIL_RTLDRADDR;
1477 Seg.cbMapped = NIL_RTLDRADDR;
1478 }
1479 if (paShdrs[iShdr].sh_type != SHT_NOBITS)
1480 {
1481 Seg.offFile = paShdrs[iShdr].sh_offset;
1482 Seg.cbFile = paShdrs[iShdr].sh_size;
1483 }
1484 else
1485 {
1486 Seg.offFile = -1;
1487 Seg.cbFile = 0;
1488 }
1489
1490 rc = pfnCallback(pMod, &Seg, pvUser);
1491 if (rc != VINF_SUCCESS)
1492 return rc;
1493 }
1494
1495 return VINF_SUCCESS;
1496}
1497
1498
1499/** @copydoc RTLDROPS::pfnLinkAddressToSegOffset. */
1500static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToSegOffset)(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress,
1501 uint32_t *piSeg, PRTLDRADDR poffSeg)
1502{
1503 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1504
1505 const Elf_Shdr *pShdrEnd = NULL;
1506 unsigned cLeft = pModElf->Ehdr.e_shnum - pModElf->iFirstSect;
1507 const Elf_Shdr *pShdr = &pModElf->paOrgShdrs[pModElf->Ehdr.e_shnum];
1508 while (cLeft-- > 0)
1509 {
1510 pShdr--;
1511 if (pShdr->sh_flags & SHF_ALLOC)
1512 {
1513 RTLDRADDR offSeg = LinkAddress - pShdr->sh_addr;
1514 if (offSeg < pShdr->sh_size)
1515 {
1516 *poffSeg = offSeg;
1517 *piSeg = cLeft;
1518 return VINF_SUCCESS;
1519 }
1520 if (offSeg == pShdr->sh_size)
1521 pShdrEnd = pShdr;
1522 }
1523 }
1524
1525 if (pShdrEnd)
1526 {
1527 *poffSeg = pShdrEnd->sh_size;
1528 *piSeg = pShdrEnd - pModElf->paOrgShdrs - pModElf->iFirstSect;
1529 return VINF_SUCCESS;
1530 }
1531
1532 return VERR_LDR_INVALID_LINK_ADDRESS;
1533}
1534
1535
1536/** @copydoc RTLDROPS::pfnLinkAddressToRva. */
1537static DECLCALLBACK(int) RTLDRELF_NAME(LinkAddressToRva)(PRTLDRMODINTERNAL pMod, RTLDRADDR LinkAddress, PRTLDRADDR pRva)
1538{
1539 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1540 uint32_t iSeg;
1541 RTLDRADDR offSeg;
1542 int rc = RTLDRELF_NAME(LinkAddressToSegOffset)(pMod, LinkAddress, &iSeg, &offSeg);
1543 if (RT_SUCCESS(rc))
1544 *pRva = pModElf->paShdrs[iSeg + pModElf->iFirstSect].sh_addr + offSeg;
1545 return rc;
1546}
1547
1548
1549/** @copydoc RTLDROPS::pfnSegOffsetToRva. */
1550static DECLCALLBACK(int) RTLDRELF_NAME(SegOffsetToRva)(PRTLDRMODINTERNAL pMod, uint32_t iSeg, RTLDRADDR offSeg,
1551 PRTLDRADDR pRva)
1552{
1553 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1554 if (iSeg >= pModElf->Ehdr.e_shnum - pModElf->iFirstSect)
1555 return VERR_LDR_INVALID_SEG_OFFSET;
1556
1557 iSeg += pModElf->iFirstSect; /* skip section 0 if not used */
1558 if (offSeg > pModElf->paShdrs[iSeg].sh_size)
1559 {
1560 const Elf_Shdr *pShdr2 = RTLDRELF_NAME(GetNextAllocatedSection)(pModElf, iSeg);
1561 if ( !pShdr2
1562 || offSeg > (pShdr2->sh_addr - pModElf->paShdrs[iSeg].sh_addr))
1563 return VERR_LDR_INVALID_SEG_OFFSET;
1564 }
1565
1566 if (!(pModElf->paShdrs[iSeg].sh_flags & SHF_ALLOC))
1567 return VERR_LDR_INVALID_SEG_OFFSET;
1568
1569 *pRva = pModElf->paShdrs[iSeg].sh_addr;
1570 return VINF_SUCCESS;
1571}
1572
1573
1574/** @copydoc RTLDROPS::pfnRvaToSegOffset. */
1575static DECLCALLBACK(int) RTLDRELF_NAME(RvaToSegOffset)(PRTLDRMODINTERNAL pMod, RTLDRADDR Rva,
1576 uint32_t *piSeg, PRTLDRADDR poffSeg)
1577{
1578 PRTLDRMODELF pModElf = (PRTLDRMODELF)pMod;
1579 Elf_Addr PrevAddr = 0;
1580 unsigned cLeft = pModElf->Ehdr.e_shnum - pModElf->iFirstSect;
1581 const Elf_Shdr *pShdr = &pModElf->paShdrs[pModElf->Ehdr.e_shnum];
1582 while (cLeft-- > 0)
1583 {
1584 pShdr--;
1585 if (pShdr->sh_flags & SHF_ALLOC)
1586 {
1587 Elf_Addr cbSeg = PrevAddr ? PrevAddr - pShdr->sh_addr : pShdr->sh_size;
1588 RTLDRADDR offSeg = Rva - pShdr->sh_addr;
1589 if (offSeg <= cbSeg)
1590 {
1591 *poffSeg = offSeg;
1592 *piSeg = cLeft;
1593 return VINF_SUCCESS;
1594 }
1595 PrevAddr = pShdr->sh_addr;
1596 }
1597 }
1598
1599 return VERR_LDR_INVALID_RVA;
1600}
1601
1602
1603/** @callback_method_impl{FNRTLDRIMPORT, Stub used by ReadDbgInfo.} */
1604static DECLCALLBACK(int) RTLDRELF_NAME(GetImportStubCallback)(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
1605 unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
1606{
1607 RT_NOREF_PV(hLdrMod); RT_NOREF_PV(pszModule); RT_NOREF_PV(pszSymbol);
1608 RT_NOREF_PV(uSymbol); RT_NOREF_PV(pValue); RT_NOREF_PV(pvUser);
1609 return VERR_SYMBOL_NOT_FOUND;
1610}
1611
1612
1613/** @copydoc RTLDROPS::pfnReadDbgInfo. */
1614static DECLCALLBACK(int) RTLDRELF_NAME(ReadDbgInfo)(PRTLDRMODINTERNAL pMod, uint32_t iDbgInfo, RTFOFF off,
1615 size_t cb, void *pvBuf)
1616{
1617 PRTLDRMODELF pThis = (PRTLDRMODELF)pMod;
1618 LogFlow(("%s: iDbgInfo=%#x off=%RTfoff cb=%#zu\n", __FUNCTION__, iDbgInfo, off, cb));
1619
1620 /*
1621 * Input validation.
1622 */
1623 AssertReturn(iDbgInfo < pThis->Ehdr.e_shnum && iDbgInfo + 1 < pThis->Ehdr.e_shnum, VERR_INVALID_PARAMETER);
1624 iDbgInfo++;
1625 AssertReturn(!(pThis->paShdrs[iDbgInfo].sh_flags & SHF_ALLOC), VERR_INVALID_PARAMETER);
1626 AssertReturn(pThis->paShdrs[iDbgInfo].sh_type == SHT_PROGBITS, VERR_INVALID_PARAMETER);
1627 AssertReturn(pThis->paShdrs[iDbgInfo].sh_offset == (uint64_t)off, VERR_INVALID_PARAMETER);
1628 AssertReturn(pThis->paShdrs[iDbgInfo].sh_size == cb, VERR_INVALID_PARAMETER);
1629 uint64_t cbRawImage = pThis->Core.pReader->pfnSize(pThis->Core.pReader);
1630 AssertReturn(off >= 0 && cb <= cbRawImage && (uint64_t)off + cb <= cbRawImage, VERR_INVALID_PARAMETER);
1631
1632 /*
1633 * Read it from the file and look for fixup sections.
1634 */
1635 int rc;
1636 if (pThis->pvBits)
1637 memcpy(pvBuf, (const uint8_t *)pThis->pvBits + (size_t)off, cb);
1638 else
1639 {
1640 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pvBuf, cb, off);
1641 if (RT_FAILURE(rc))
1642 return rc;
1643 }
1644
1645 uint32_t iRelocs = iDbgInfo + 1;
1646 if ( iRelocs >= pThis->Ehdr.e_shnum
1647 || pThis->paShdrs[iRelocs].sh_info != iDbgInfo
1648 || ( pThis->paShdrs[iRelocs].sh_type != SHT_REL
1649 && pThis->paShdrs[iRelocs].sh_type != SHT_RELA) )
1650 {
1651 iRelocs = 0;
1652 while ( iRelocs < pThis->Ehdr.e_shnum
1653 && ( pThis->paShdrs[iRelocs].sh_info != iDbgInfo
1654 || ( pThis->paShdrs[iRelocs].sh_type != SHT_REL
1655 && pThis->paShdrs[iRelocs].sh_type != SHT_RELA)) )
1656 iRelocs++;
1657 }
1658 if ( iRelocs < pThis->Ehdr.e_shnum
1659 && pThis->paShdrs[iRelocs].sh_size > 0)
1660 {
1661 /*
1662 * Load the relocations.
1663 */
1664 uint8_t *pbRelocsBuf = NULL;
1665 const uint8_t *pbRelocs;
1666 if (pThis->pvBits)
1667 pbRelocs = (const uint8_t *)pThis->pvBits + pThis->paShdrs[iRelocs].sh_offset;
1668 else
1669 {
1670 pbRelocs = pbRelocsBuf = (uint8_t *)RTMemTmpAlloc(pThis->paShdrs[iRelocs].sh_size);
1671 if (!pbRelocsBuf)
1672 return VERR_NO_TMP_MEMORY;
1673 rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbRelocsBuf,
1674 pThis->paShdrs[iRelocs].sh_size,
1675 pThis->paShdrs[iRelocs].sh_offset);
1676 if (RT_FAILURE(rc))
1677 {
1678 RTMemTmpFree(pbRelocsBuf);
1679 return rc;
1680 }
1681 }
1682
1683 /*
1684 * Apply the relocations.
1685 */
1686 if (pThis->Ehdr.e_type == ET_REL)
1687 rc = RTLDRELF_NAME(RelocateSectionRel)(pThis, pThis->LinkAddress,
1688 RTLDRELF_NAME(GetImportStubCallback), NULL /*pvUser*/,
1689 pThis->paShdrs[iDbgInfo].sh_addr,
1690 pThis->paShdrs[iDbgInfo].sh_size,
1691 (const uint8_t *)pvBuf,
1692 (uint8_t *)pvBuf,
1693 pbRelocs,
1694 pThis->paShdrs[iRelocs].sh_size);
1695 else
1696 rc = RTLDRELF_NAME(RelocateSectionExecDyn)(pThis, pThis->LinkAddress,
1697 RTLDRELF_NAME(GetImportStubCallback), NULL /*pvUser*/,
1698 pThis->paShdrs[iDbgInfo].sh_addr,
1699 pThis->paShdrs[iDbgInfo].sh_size,
1700 (const uint8_t *)pvBuf,
1701 (uint8_t *)pvBuf,
1702 pbRelocs,
1703 pThis->paShdrs[iRelocs].sh_size);
1704
1705 RTMemTmpFree(pbRelocsBuf);
1706 }
1707 else
1708 rc = VINF_SUCCESS;
1709 return rc;
1710}
1711
1712
1713/**
1714 * Handles RTLDRPROP_BUILDID queries.
1715 */
1716static int RTLDRELF_NAME(QueryPropBuildId)(PRTLDRMODELF pThis, void *pvBuf, size_t cbBuf, size_t *pcbRet)
1717{
1718 /*
1719 * Map the image bits if not already done and setup pointer into it.
1720 */
1721 int rc = RTLDRELF_NAME(MapBits)(pThis, true);
1722 if (RT_FAILURE(rc))
1723 return rc;
1724
1725 /*
1726 * Search for the build ID.
1727 */
1728 const Elf_Shdr *paShdrs = pThis->paOrgShdrs;
1729 for (unsigned iShdr = 0; iShdr < pThis->Ehdr.e_shnum; iShdr++)
1730 {
1731 const char *pszSectName = ELF_SH_STR(pThis, paShdrs[iShdr].sh_name);
1732
1733 if (!strcmp(pszSectName, ".note.gnu.build-id"))
1734 {
1735 if ((paShdrs[iShdr].sh_size & 3) || paShdrs[iShdr].sh_size < sizeof(Elf_Nhdr))
1736 return VERR_BAD_EXE_FORMAT;
1737
1738 Elf_Nhdr *pNHdr = (Elf_Nhdr *)((uintptr_t)pThis->pvBits + (uintptr_t)paShdrs[iShdr].sh_offset);
1739 if ( pNHdr->n_namesz > paShdrs[iShdr].sh_size
1740 || pNHdr->n_descsz > paShdrs[iShdr].sh_size
1741 || (paShdrs[iShdr].sh_size - pNHdr->n_descsz) < pNHdr->n_namesz
1742 || pNHdr->n_type != NT_GNU_BUILD_ID)
1743 return VERR_BAD_EXE_FORMAT;
1744
1745 const char *pszOwner = (const char *)(pNHdr + 1);
1746 if ( !RTStrEnd(pszOwner, pNHdr->n_namesz)
1747 || strcmp(pszOwner, "GNU"))
1748 return VERR_BAD_EXE_FORMAT;
1749
1750 if (cbBuf < pNHdr->n_descsz)
1751 return VERR_BUFFER_OVERFLOW;
1752
1753 memcpy(pvBuf, pszOwner + pNHdr->n_namesz, pNHdr->n_descsz);
1754 *pcbRet = pNHdr->n_descsz;
1755 return VINF_SUCCESS;
1756 }
1757 }
1758
1759 return VERR_NOT_FOUND;
1760}
1761
1762
1763/** @interface_method_impl{RTLDROPS,pfnQueryProp} */
1764static DECLCALLBACK(int) RTLDRELF_NAME(QueryProp)(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void const *pvBits,
1765 void *pvBuf, size_t cbBuf, size_t *pcbRet)
1766{
1767 PRTLDRMODELF pThis = (PRTLDRMODELF)pMod;
1768 RT_NOREF(pvBits);
1769 switch (enmProp)
1770 {
1771 case RTLDRPROP_BUILDID:
1772 return RTLDRELF_NAME(QueryPropBuildId)(pThis, pvBuf, cbBuf, pcbRet);
1773
1774 case RTLDRPROP_IS_SIGNED:
1775 *pcbRet = sizeof(bool);
1776 return rtLdrELFLnxKModQueryPropIsSigned(pThis->Core.pReader, (bool *)pvBuf);
1777
1778 case RTLDRPROP_PKCS7_SIGNED_DATA:
1779 *pcbRet = sizeof(bool);
1780 return rtLdrELFLnxKModQueryPropPkcs7SignedData(pThis->Core.pReader, pvBuf, cbBuf, pcbRet);
1781
1782 default:
1783 return VERR_NOT_FOUND;
1784 }
1785}
1786
1787
1788/**
1789 * @interface_method_impl{RTLDROPS,pfnUnwindFrame}
1790 */
1791static DECLCALLBACK(int)
1792RTLDRELF_NAME(UnwindFrame)(PRTLDRMODINTERNAL pMod, void const *pvBits, uint32_t iSeg, RTUINTPTR off, PRTDBGUNWINDSTATE pState)
1793{
1794 PRTLDRMODELF pThis = (PRTLDRMODELF)pMod;
1795 LogFlow(("%s: iSeg=%#x off=%RTptr\n", __FUNCTION__, iSeg, off));
1796
1797 /*
1798 * Process the input address, making us both RVA and proper seg:offset out of it.
1799 */
1800 int rc;
1801 RTLDRADDR uRva = off;
1802 if (iSeg == UINT32_MAX)
1803 rc = RTLDRELF_NAME(RvaToSegOffset)(pMod, uRva, &iSeg, &off);
1804 else
1805 rc = RTLDRELF_NAME(SegOffsetToRva)(pMod, iSeg, off, &uRva);
1806 AssertRCReturn(rc, rc);
1807
1808 /*
1809 * Map the image bits if not already done and setup pointer into it.
1810 */
1811 RT_NOREF(pvBits); /** @todo Try use passed in pvBits? */
1812 rc = RTLDRELF_NAME(MapBits)(pThis, true);
1813 if (RT_FAILURE(rc))
1814 return rc;
1815
1816 /*
1817 * Do we need to search for .eh_frame and .eh_frame_hdr?
1818 */
1819 if (pThis->iShEhFrame == 0)
1820 {
1821 pThis->iShEhFrame = ~0U;
1822 pThis->iShEhFrameHdr = ~0U;
1823 unsigned cLeft = 2;
1824 for (unsigned iShdr = 1; iShdr < pThis->Ehdr.e_shnum; iShdr++)
1825 {
1826 const char *pszName = ELF_SH_STR(pThis, pThis->paShdrs[iShdr].sh_name);
1827 if ( pszName[0] == '.'
1828 && pszName[1] == 'e'
1829 && pszName[2] == 'h'
1830 && pszName[3] == '_'
1831 && pszName[4] == 'f'
1832 && pszName[5] == 'r'
1833 && pszName[6] == 'a'
1834 && pszName[7] == 'm'
1835 && pszName[8] == 'e')
1836 {
1837 if (pszName[9] == '\0')
1838 pThis->iShEhFrame = iShdr;
1839 else if ( pszName[9] == '_'
1840 && pszName[10] == 'h'
1841 && pszName[11] == 'd'
1842 && pszName[12] == 'r'
1843 && pszName[13] == '\0')
1844 pThis->iShEhFrameHdr = iShdr;
1845 else
1846 continue;
1847 if (--cLeft == 0)
1848 break;
1849 }
1850 }
1851 }
1852
1853 /*
1854 * Any info present?
1855 */
1856 unsigned iShdr = pThis->iShEhFrame;
1857 if ( iShdr != ~0U
1858 && pThis->paShdrs[iShdr].sh_size > 0)
1859 {
1860 if (pThis->paShdrs[iShdr].sh_flags & SHF_ALLOC)
1861 return rtDwarfUnwind_EhData((uint8_t const *)pThis->pvBits + pThis->paShdrs[iShdr].sh_addr,
1862 pThis->paShdrs[iShdr].sh_size, pThis->paShdrs[iShdr].sh_addr,
1863 iSeg, off, uRva, pState, pThis->Core.enmArch);
1864 }
1865 return VERR_DBG_NO_UNWIND_INFO;
1866}
1867
1868
1869/**
1870 * The ELF module operations.
1871 */
1872static RTLDROPS RTLDRELF_MID(s_rtldrElf,Ops) =
1873{
1874#if ELF_MODE == 32
1875 "elf32",
1876#elif ELF_MODE == 64
1877 "elf64",
1878#endif
1879 RTLDRELF_NAME(Close),
1880 NULL, /* Get Symbol */
1881 RTLDRELF_NAME(Done),
1882 RTLDRELF_NAME(EnumSymbols),
1883 /* ext: */
1884 RTLDRELF_NAME(GetImageSize),
1885 RTLDRELF_NAME(GetBits),
1886 RTLDRELF_NAME(Relocate),
1887 RTLDRELF_NAME(GetSymbolEx),
1888 NULL /*pfnQueryForwarderInfo*/,
1889 RTLDRELF_NAME(EnumDbgInfo),
1890 RTLDRELF_NAME(EnumSegments),
1891 RTLDRELF_NAME(LinkAddressToSegOffset),
1892 RTLDRELF_NAME(LinkAddressToRva),
1893 RTLDRELF_NAME(SegOffsetToRva),
1894 RTLDRELF_NAME(RvaToSegOffset),
1895 RTLDRELF_NAME(ReadDbgInfo),
1896 RTLDRELF_NAME(QueryProp),
1897 NULL /*pfnVerifySignature*/,
1898 rtldrELFLnxKModHashImage,
1899 RTLDRELF_NAME(UnwindFrame),
1900 42
1901};
1902
1903
1904
1905/**
1906 * Validates the ELF header.
1907 *
1908 * @returns iprt status code.
1909 * @param pEhdr Pointer to the ELF header.
1910 * @param cbRawImage The size of the raw image.
1911 * @param pszLogName The log name.
1912 * @param penmArch Where to return the architecture.
1913 * @param pErrInfo Where to return extended error info. Optional.
1914 */
1915static int RTLDRELF_NAME(ValidateElfHeader)(const Elf_Ehdr *pEhdr, uint64_t cbRawImage, const char *pszLogName,
1916 PRTLDRARCH penmArch, PRTERRINFO pErrInfo)
1917{
1918 Log3(("RTLdrELF: e_ident: %.*Rhxs\n"
1919 "RTLdrELF: e_type: " FMT_ELF_HALF "\n"
1920 "RTLdrELF: e_version: " FMT_ELF_HALF "\n"
1921 "RTLdrELF: e_entry: " FMT_ELF_ADDR "\n"
1922 "RTLdrELF: e_phoff: " FMT_ELF_OFF "\n"
1923 "RTLdrELF: e_shoff: " FMT_ELF_OFF "\n"
1924 "RTLdrELF: e_flags: " FMT_ELF_WORD "\n"
1925 "RTLdrELF: e_ehsize: " FMT_ELF_HALF "\n"
1926 "RTLdrELF: e_phentsize: " FMT_ELF_HALF "\n"
1927 "RTLdrELF: e_phnum: " FMT_ELF_HALF "\n"
1928 "RTLdrELF: e_shentsize: " FMT_ELF_HALF "\n"
1929 "RTLdrELF: e_shnum: " FMT_ELF_HALF "\n"
1930 "RTLdrELF: e_shstrndx: " FMT_ELF_HALF "\n",
1931 RT_ELEMENTS(pEhdr->e_ident), &pEhdr->e_ident[0], pEhdr->e_type, pEhdr->e_version,
1932 pEhdr->e_entry, pEhdr->e_phoff, pEhdr->e_shoff,pEhdr->e_flags, pEhdr->e_ehsize, pEhdr->e_phentsize,
1933 pEhdr->e_phnum, pEhdr->e_shentsize, pEhdr->e_shnum, pEhdr->e_shstrndx));
1934
1935 if ( pEhdr->e_ident[EI_MAG0] != ELFMAG0
1936 || pEhdr->e_ident[EI_MAG1] != ELFMAG1
1937 || pEhdr->e_ident[EI_MAG2] != ELFMAG2
1938 || pEhdr->e_ident[EI_MAG3] != ELFMAG3)
1939 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
1940 "%s: Invalid ELF magic (%.*Rhxs)", pszLogName, sizeof(pEhdr->e_ident), pEhdr->e_ident);
1941 if (pEhdr->e_ident[EI_CLASS] != RTLDRELF_SUFF(ELFCLASS))
1942 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
1943 "%s: Invalid ELF class (%.*Rhxs)", pszLogName, sizeof(pEhdr->e_ident), pEhdr->e_ident);
1944 if (pEhdr->e_ident[EI_DATA] != ELFDATA2LSB)
1945 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRELF_ODD_ENDIAN,
1946 "%s: ELF endian %x is unsupported", pszLogName, pEhdr->e_ident[EI_DATA]);
1947 if (pEhdr->e_version != EV_CURRENT)
1948 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRELF_VERSION,
1949 "%s: ELF version %x is unsupported", pszLogName, pEhdr->e_version);
1950
1951 if (sizeof(Elf_Ehdr) != pEhdr->e_ehsize)
1952 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
1953 "%s: Elf header e_ehsize is %d expected %d!", pszLogName, pEhdr->e_ehsize, sizeof(Elf_Ehdr));
1954 if ( sizeof(Elf_Phdr) != pEhdr->e_phentsize
1955 && ( pEhdr->e_phnum != 0
1956 || pEhdr->e_type == ET_DYN
1957 || pEhdr->e_type == ET_EXEC))
1958 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Elf header e_phentsize is %d expected %d!",
1959 pszLogName, pEhdr->e_phentsize, sizeof(Elf_Phdr));
1960 if (sizeof(Elf_Shdr) != pEhdr->e_shentsize)
1961 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Elf header e_shentsize is %d expected %d!",
1962 pszLogName, pEhdr->e_shentsize, sizeof(Elf_Shdr));
1963
1964 switch (pEhdr->e_type)
1965 {
1966 case ET_REL:
1967 case ET_EXEC:
1968 case ET_DYN:
1969 break;
1970 default:
1971 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: image type %#x is not supported!",
1972 pszLogName, pEhdr->e_type);
1973 }
1974
1975 switch (pEhdr->e_machine)
1976 {
1977#if ELF_MODE == 32
1978 case EM_386:
1979 case EM_486:
1980 *penmArch = RTLDRARCH_X86_32;
1981 break;
1982#elif ELF_MODE == 64
1983 case EM_X86_64:
1984 *penmArch = RTLDRARCH_AMD64;
1985 break;
1986#endif
1987 default:
1988 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRELF_MACHINE,
1989 "%s: machine type %u is not supported!", pszLogName, pEhdr->e_machine);
1990 }
1991
1992 if ( pEhdr->e_phoff < pEhdr->e_ehsize
1993 && !(pEhdr->e_phoff && pEhdr->e_phnum)
1994 && pEhdr->e_phnum)
1995 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
1996 "%s: The program headers overlap with the ELF header! e_phoff=" FMT_ELF_OFF,
1997 pszLogName, pEhdr->e_phoff);
1998 if ( pEhdr->e_phoff + pEhdr->e_phnum * pEhdr->e_phentsize > cbRawImage
1999 || pEhdr->e_phoff + pEhdr->e_phnum * pEhdr->e_phentsize < pEhdr->e_phoff)
2000 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2001 "%s: The program headers extends beyond the file! e_phoff=" FMT_ELF_OFF " e_phnum=" FMT_ELF_HALF,
2002 pszLogName, pEhdr->e_phoff, pEhdr->e_phnum);
2003
2004
2005 if ( pEhdr->e_shoff < pEhdr->e_ehsize
2006 && !(pEhdr->e_shoff && pEhdr->e_shnum))
2007 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2008 "%s: The section headers overlap with the ELF header! e_shoff=" FMT_ELF_OFF,
2009 pszLogName, pEhdr->e_shoff);
2010 if ( pEhdr->e_shoff + pEhdr->e_shnum * pEhdr->e_shentsize > cbRawImage
2011 || pEhdr->e_shoff + pEhdr->e_shnum * pEhdr->e_shentsize < pEhdr->e_shoff)
2012 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2013 "%s: The section headers extends beyond the file! e_shoff=" FMT_ELF_OFF " e_shnum=" FMT_ELF_HALF,
2014 pszLogName, pEhdr->e_shoff, pEhdr->e_shnum);
2015
2016 if (pEhdr->e_shstrndx == 0 || pEhdr->e_shstrndx > pEhdr->e_shnum)
2017 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2018 "%s: The section headers string table is out of bounds! e_shstrndx=" FMT_ELF_HALF " e_shnum=" FMT_ELF_HALF,
2019 pszLogName, pEhdr->e_shstrndx, pEhdr->e_shnum);
2020
2021 return VINF_SUCCESS;
2022}
2023
2024
2025/**
2026 * Gets the section header name.
2027 *
2028 * @returns pszName.
2029 * @param pEhdr The elf header.
2030 * @param offName The offset of the section header name.
2031 * @param pszName Where to store the name.
2032 * @param cbName The size of the buffer pointed to by pszName.
2033 */
2034static const char *RTLDRELF_NAME(GetSHdrName)(PRTLDRMODELF pModElf, Elf_Word offName, char *pszName, size_t cbName)
2035{
2036 RTFOFF off = pModElf->paShdrs[pModElf->Ehdr.e_shstrndx].sh_offset + offName;
2037 int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, pszName, cbName - 1, off);
2038 if (RT_FAILURE(rc))
2039 {
2040 /* read by for byte. */
2041 for (unsigned i = 0; i < cbName; i++, off++)
2042 {
2043 rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, pszName + i, 1, off);
2044 if (RT_FAILURE(rc))
2045 {
2046 pszName[i] = '\0';
2047 break;
2048 }
2049 }
2050 }
2051
2052 pszName[cbName - 1] = '\0';
2053 return pszName;
2054}
2055
2056
2057/**
2058 * Validates a section header.
2059 *
2060 * @returns iprt status code.
2061 * @param pModElf Pointer to the module structure.
2062 * @param iShdr The index of section header which should be validated.
2063 * The section headers are found in the pModElf->paShdrs array.
2064 * @param cbRawImage The size of the raw image.
2065 * @param pszLogName The log name.
2066 * @param pErrInfo Where to return extended error info. Optional.
2067 */
2068static int RTLDRELF_NAME(ValidateSectionHeader)(PRTLDRMODELF pModElf, unsigned iShdr, uint64_t cbRawImage,
2069 const char *pszLogName, PRTERRINFO pErrInfo)
2070{
2071 const Elf_Shdr *pShdr = &pModElf->paShdrs[iShdr];
2072 char szSectionName[80]; NOREF(szSectionName);
2073 Log3(("RTLdrELF: Section Header #%d:\n"
2074 "RTLdrELF: sh_name: " FMT_ELF_WORD " - %s\n"
2075 "RTLdrELF: sh_type: " FMT_ELF_WORD " (%s)\n"
2076 "RTLdrELF: sh_flags: " FMT_ELF_XWORD "\n"
2077 "RTLdrELF: sh_addr: " FMT_ELF_ADDR "\n"
2078 "RTLdrELF: sh_offset: " FMT_ELF_OFF "\n"
2079 "RTLdrELF: sh_size: " FMT_ELF_XWORD "\n"
2080 "RTLdrELF: sh_link: " FMT_ELF_WORD "\n"
2081 "RTLdrELF: sh_info: " FMT_ELF_WORD "\n"
2082 "RTLdrELF: sh_addralign: " FMT_ELF_XWORD "\n"
2083 "RTLdrELF: sh_entsize: " FMT_ELF_XWORD "\n",
2084 iShdr,
2085 pShdr->sh_name, RTLDRELF_NAME(GetSHdrName)(pModElf, pShdr->sh_name, szSectionName, sizeof(szSectionName)),
2086 pShdr->sh_type, rtldrElfGetShdrType(pShdr->sh_type), pShdr->sh_flags, pShdr->sh_addr,
2087 pShdr->sh_offset, pShdr->sh_size, pShdr->sh_link, pShdr->sh_info, pShdr->sh_addralign,
2088 pShdr->sh_entsize));
2089
2090 if (iShdr == 0)
2091 {
2092 if ( pShdr->sh_name != 0
2093 || pShdr->sh_type != SHT_NULL
2094 || pShdr->sh_flags != 0
2095 || pShdr->sh_addr != 0
2096 || pShdr->sh_size != 0
2097 || pShdr->sh_offset != 0
2098 || pShdr->sh_link != SHN_UNDEF
2099 || pShdr->sh_addralign != 0
2100 || pShdr->sh_entsize != 0 )
2101 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2102 "%s: Bad #0 section: %.*Rhxs", pszLogName, sizeof(*pShdr), pShdr);
2103 return VINF_SUCCESS;
2104 }
2105
2106 if (pShdr->sh_name >= pModElf->cbShStr)
2107 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2108 "%s: Shdr #%d: sh_name (%d) is beyond the end of the section header string table (%d)!",
2109 pszLogName, iShdr, pShdr->sh_name, pModElf->cbShStr);
2110
2111 if (pShdr->sh_link >= pModElf->Ehdr.e_shnum)
2112 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2113 "%s: Shdr #%d: sh_link (%d) is beyond the end of the section table (%d)!",
2114 pszLogName, iShdr, pShdr->sh_link, pModElf->Ehdr.e_shnum);
2115
2116 switch (pShdr->sh_type)
2117 {
2118 /** @todo find specs and check up which sh_info fields indicates section table entries */
2119 case 12301230:
2120 if (pShdr->sh_info >= pModElf->Ehdr.e_shnum)
2121 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2122 "%s: Shdr #%d: sh_info (%d) is beyond the end of the section table (%d)!",
2123 pszLogName, iShdr, pShdr->sh_link, pModElf->Ehdr.e_shnum);
2124 break;
2125
2126 case SHT_NULL:
2127 break;
2128 case SHT_PROGBITS:
2129 case SHT_SYMTAB:
2130 case SHT_STRTAB:
2131 case SHT_RELA:
2132 case SHT_HASH:
2133 case SHT_DYNAMIC:
2134 case SHT_NOTE:
2135 case SHT_NOBITS:
2136 case SHT_REL:
2137 case SHT_SHLIB:
2138 case SHT_DYNSYM:
2139 /*
2140 * For these types sh_info doesn't have any special meaning, or anything which
2141 * we need/can validate now.
2142 */
2143 break;
2144
2145
2146 default:
2147 Log(("RTLdrELF: %s: Warning, unknown type %d!\n", pszLogName, pShdr->sh_type));
2148 break;
2149 }
2150
2151 if ( pShdr->sh_type != SHT_NOBITS
2152 && pShdr->sh_size)
2153 {
2154 uint64_t offEnd = pShdr->sh_offset + pShdr->sh_size;
2155 if ( offEnd > cbRawImage
2156 || offEnd < (uint64_t)pShdr->sh_offset)
2157 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2158 "%s: Shdr #%d: sh_offset (" FMT_ELF_OFF ") + sh_size (" FMT_ELF_XWORD " = %RX64) is beyond the end of the file (%RX64)!",
2159 pszLogName, iShdr, pShdr->sh_offset, pShdr->sh_size, offEnd, cbRawImage);
2160 if (pShdr->sh_offset < sizeof(Elf_Ehdr))
2161 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2162 "%s: Shdr #%d: sh_offset (" FMT_ELF_OFF ") + sh_size (" FMT_ELF_XWORD ") is starting in the ELF header!",
2163 pszLogName, iShdr, pShdr->sh_offset, pShdr->sh_size);
2164 }
2165
2166 return VINF_SUCCESS;
2167}
2168
2169
2170/**
2171 * Process the section headers.
2172 *
2173 * @returns iprt status code.
2174 * @param pModElf Pointer to the module structure.
2175 * @param paShdrs The section headers.
2176 * @param cbRawImage The size of the raw image.
2177 * @param pszLogName The log name.
2178 * @param pErrInfo Where to return extended error info. Optional.
2179 */
2180static int RTLDRELF_NAME(ValidateAndProcessSectionHeaders)(PRTLDRMODELF pModElf, Elf_Shdr *paShdrs, uint64_t cbRawImage,
2181 const char *pszLogName, PRTERRINFO pErrInfo)
2182{
2183 Elf_Addr uNextAddr = 0;
2184 for (unsigned i = 0; i < pModElf->Ehdr.e_shnum; i++)
2185 {
2186 int rc = RTLDRELF_NAME(ValidateSectionHeader)(pModElf, i, cbRawImage, pszLogName, pErrInfo);
2187 if (RT_FAILURE(rc))
2188 return rc;
2189
2190 /*
2191 * We're looking for symbol tables.
2192 */
2193 if (paShdrs[i].sh_type == SHT_SYMTAB)
2194 {
2195 if (pModElf->Rel.iSymSh != ~0U)
2196 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRELF_MULTIPLE_SYMTABS,
2197 "%s: Multiple symbol tabs! iSymSh=%d i=%d", pszLogName, pModElf->Rel.iSymSh, i);
2198 pModElf->Rel.iSymSh = i;
2199 pModElf->Rel.cSyms = (unsigned)(paShdrs[i].sh_size / sizeof(Elf_Sym));
2200 AssertBreakStmt(pModElf->Rel.cSyms == paShdrs[i].sh_size / sizeof(Elf_Sym), rc = VERR_IMAGE_TOO_BIG);
2201 pModElf->Rel.iStrSh = paShdrs[i].sh_link;
2202 pModElf->Rel.cbStr = (unsigned)paShdrs[pModElf->Rel.iStrSh].sh_size;
2203 AssertBreakStmt(pModElf->Rel.cbStr == paShdrs[pModElf->Rel.iStrSh].sh_size, rc = VERR_IMAGE_TOO_BIG);
2204 }
2205 else if (paShdrs[i].sh_type == SHT_DYNSYM)
2206 {
2207 if (pModElf->Dyn.iSymSh != ~0U)
2208 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_LDRELF_MULTIPLE_SYMTABS,
2209 "%s: Multiple dynamic symbol tabs! iSymSh=%d i=%d", pszLogName, pModElf->Dyn.iSymSh, i);
2210 if (pModElf->Ehdr.e_type != ET_DYN && pModElf->Ehdr.e_type != ET_EXEC)
2211 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2212 "%s: Unexpected SHT_DYNSYM (i=%d) for e_type=%d", pszLogName, i, pModElf->Ehdr.e_type);
2213 pModElf->Dyn.iSymSh = i;
2214 pModElf->Dyn.cSyms = (unsigned)(paShdrs[i].sh_size / sizeof(Elf_Sym));
2215 AssertBreakStmt(pModElf->Dyn.cSyms == paShdrs[i].sh_size / sizeof(Elf_Sym), rc = VERR_IMAGE_TOO_BIG);
2216 pModElf->Dyn.iStrSh = paShdrs[i].sh_link;
2217 pModElf->Dyn.cbStr = (unsigned)paShdrs[pModElf->Dyn.iStrSh].sh_size;
2218 AssertBreakStmt(pModElf->Dyn.cbStr == paShdrs[pModElf->Dyn.iStrSh].sh_size, rc = VERR_IMAGE_TOO_BIG);
2219 }
2220 /*
2221 * We're also look for the dynamic section.
2222 */
2223 else if (paShdrs[i].sh_type == SHT_DYNAMIC)
2224 {
2225 if (pModElf->iShDynamic != ~0U)
2226 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2227 "%s: Multiple dynamic sections! iShDynamic=%d i=%d",
2228 pszLogName, pModElf->iShDynamic, i);
2229 if (pModElf->Ehdr.e_type != ET_DYN && pModElf->Ehdr.e_type != ET_EXEC)
2230 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2231 "%s: Unexpected SHT_DYNAMIC (i=%d) for e_type=%d", pszLogName, i, pModElf->Ehdr.e_type);
2232 if (paShdrs[i].sh_entsize != sizeof(Elf_Dyn))
2233 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2234 "%s: SHT_DYNAMIC (i=%d) sh_entsize=" FMT_ELF_XWORD ", expected %#zx",
2235 pszLogName, i, paShdrs[i].sh_entsize, sizeof(Elf_Dyn));
2236 pModElf->iShDynamic = i;
2237 Elf_Xword const cDynamic = paShdrs[i].sh_size / sizeof(Elf_Dyn);
2238 if (cDynamic > _64K || cDynamic < 2)
2239 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2240 "%s: SHT_DYNAMIC (i=%d) sh_size=" FMT_ELF_XWORD " is out of range (2..64K)",
2241 pszLogName, i, paShdrs[i].sh_size);
2242 pModElf->cDynamic = (unsigned)cDynamic;
2243 }
2244
2245 /*
2246 * Special checks for the section string table.
2247 */
2248 if (i == pModElf->Ehdr.e_shstrndx)
2249 {
2250 if (paShdrs[i].sh_type != SHT_STRTAB)
2251 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2252 "%s: Section header string table is not a SHT_STRTAB: %#x",
2253 pszLogName, paShdrs[i].sh_type);
2254 if (paShdrs[i].sh_size == 0)
2255 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Section header string table is empty", pszLogName);
2256 }
2257
2258 /*
2259 * Kluge for the .data..percpu segment in 64-bit linux kernels.
2260 */
2261 if (paShdrs[i].sh_flags & SHF_ALLOC)
2262 {
2263 if ( paShdrs[i].sh_addr == 0
2264 && paShdrs[i].sh_addr < uNextAddr)
2265 {
2266 Elf_Addr uAddr = RT_ALIGN_T(uNextAddr, paShdrs[i].sh_addralign, Elf_Addr);
2267 Log(("RTLdrElf: Out of order section #%d; adjusting sh_addr from " FMT_ELF_ADDR " to " FMT_ELF_ADDR "\n",
2268 i, paShdrs[i].sh_addr, uAddr));
2269 paShdrs[i].sh_addr = uAddr;
2270 }
2271 uNextAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
2272 }
2273 } /* for each section header */
2274
2275 return VINF_SUCCESS;
2276}
2277
2278
2279/**
2280 * Process the section headers.
2281 *
2282 * @returns iprt status code.
2283 * @param pModElf Pointer to the module structure.
2284 * @param paShdrs The section headers.
2285 * @param cbRawImage The size of the raw image.
2286 * @param pszLogName The log name.
2287 * @param pErrInfo Where to return extended error info. Optional.
2288 */
2289static int RTLDRELF_NAME(ValidateAndProcessDynamicInfo)(PRTLDRMODELF pModElf, uint64_t cbRawImage, uint32_t fFlags,
2290 const char *pszLogName, PRTERRINFO pErrInfo)
2291{
2292 /*
2293 * Check preconditions.
2294 */
2295 AssertReturn(pModElf->Ehdr.e_type == ET_DYN || pModElf->Ehdr.e_type == ET_EXEC, VERR_INTERNAL_ERROR_2);
2296 if (pModElf->Ehdr.e_phnum <= 1 || pModElf->Ehdr.e_phnum >= _32K)
2297 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2298 "%s: e_phnum=%u is out of bounds (2..32K)", pszLogName, pModElf->Ehdr.e_phnum);
2299 if (pModElf->iShDynamic == ~0U)
2300 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: no .dynamic section", pszLogName);
2301 AssertReturn(pModElf->cDynamic > 1 && pModElf->cDynamic <= _64K, VERR_INTERNAL_ERROR_3);
2302
2303 /* ASSUME that the sections are ordered by address. That simplifies
2304 validation code further down. */
2305 AssertReturn(pModElf->Ehdr.e_shnum >= 2, VERR_INTERNAL_ERROR_4);
2306 Elf_Shdr const *paShdrs = pModElf->paShdrs;
2307 Elf_Addr uPrevEnd = paShdrs[1].sh_addr + paShdrs[1].sh_size;
2308 for (unsigned i = 2; i < pModElf->Ehdr.e_shnum; i++)
2309 if (paShdrs[i].sh_flags & SHF_ALLOC)
2310 {
2311 if (uPrevEnd > paShdrs[i].sh_addr)
2312 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2313 "%s: section %u is out of order: uPrevEnd=" FMT_ELF_ADDR " sh_addr=" FMT_ELF_ADDR,
2314 pszLogName, i, uPrevEnd, paShdrs[i].sh_addr);
2315 uPrevEnd = paShdrs[i].sh_addr + paShdrs[i].sh_size;
2316 }
2317
2318 /* Must have string and symbol tables. */
2319 if (pModElf->Dyn.iStrSh == ~0U)
2320 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: No dynamic string table section", pszLogName);
2321 if (pModElf->Dyn.iSymSh == ~0U)
2322 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: No dynamic symbol table section", pszLogName);
2323
2324 /*
2325 * Load the program headers.
2326 */
2327 size_t const cbPhdrs = sizeof(pModElf->paPhdrs[0]) * pModElf->Ehdr.e_phnum;
2328 Elf_Phdr *paPhdrs = (Elf_Phdr *)RTMemAllocZ(cbPhdrs);
2329 pModElf->paPhdrs = paPhdrs;
2330 AssertReturn(paPhdrs, VERR_NO_MEMORY);
2331
2332 int rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, paPhdrs, cbPhdrs, pModElf->Ehdr.e_phoff);
2333 if (RT_FAILURE(rc))
2334 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "%s: pfnRead(,,%#zx, " FMT_ELF_OFF ") -> %Rrc",
2335 pszLogName, cbPhdrs, pModElf->Ehdr.e_phoff, rc);
2336
2337 /*
2338 * Validate them.
2339 */
2340 unsigned cbPage = _4K; /** @todo generalize architecture specific stuff using its own code template header. */
2341 switch (pModElf->Core.enmArch)
2342 {
2343 case RTLDRARCH_AMD64:
2344 case RTLDRARCH_X86_32:
2345 break;
2346 default:
2347 AssertFailedBreak(/** @todo page size for got.plt hacks */);
2348 }
2349 unsigned iLoad = 0;
2350 unsigned iLoadShdr = 1; /* ASSUMES ordered (checked above). */
2351 unsigned cDynamic = 0;
2352 Elf_Addr cbImage = 0;
2353 Elf_Addr uLinkAddress = ~(Elf_Addr)0;
2354 for (unsigned i = 0; i < pModElf->Ehdr.e_phnum; i++)
2355 {
2356 const Elf_Phdr * const pPhdr = &paPhdrs[i];
2357 Log3(("RTLdrELF: Program Header #%d:\n"
2358 "RTLdrELF: p_type: " FMT_ELF_WORD " (%s)\n"
2359 "RTLdrELF: p_flags: " FMT_ELF_WORD "\n"
2360 "RTLdrELF: p_offset: " FMT_ELF_OFF "\n"
2361 "RTLdrELF: p_vaddr: " FMT_ELF_ADDR "\n"
2362 "RTLdrELF: p_paddr: " FMT_ELF_ADDR "\n"
2363 "RTLdrELF: p_filesz: " FMT_ELF_XWORD "\n"
2364 "RTLdrELF: p_memsz: " FMT_ELF_XWORD "\n"
2365 "RTLdrELF: p_align: " FMT_ELF_XWORD "\n",
2366 i,
2367 pPhdr->p_type, rtldrElfGetPhdrType(pPhdr->p_type), pPhdr->p_flags, pPhdr->p_offset,
2368 pPhdr->p_vaddr, pPhdr->p_paddr, pPhdr->p_filesz, pPhdr->p_memsz, pPhdr->p_align));
2369
2370 if (pPhdr->p_type == DT_NULL)
2371 continue;
2372
2373 if ( pPhdr->p_filesz != 0
2374 && ( pPhdr->p_offset >= cbRawImage
2375 || pPhdr->p_filesz > cbRawImage
2376 || pPhdr->p_offset + pPhdr->p_filesz > cbRawImage))
2377 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2378 "%s: Prog Hdr #%u: bogus p_offset=" FMT_ELF_OFF " & p_filesz=" FMT_ELF_XWORD " (file size %#RX64)",
2379 pszLogName, i, pPhdr->p_offset, pPhdr->p_filesz, cbRawImage);
2380
2381 if (pPhdr->p_flags & ~(Elf64_Word)(PF_X | PF_R | PF_W))
2382 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Prog Hdr #%u: bogus p_flags=" FMT_ELF_WORD,
2383 pszLogName, i, pPhdr->p_flags);
2384
2385 if (!RT_IS_POWER_OF_TWO(pPhdr->p_align))
2386 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Prog Hdr #%u: bogus p_align=" FMT_ELF_XWORD,
2387 pszLogName, i, pPhdr->p_align);
2388
2389 if ( pPhdr->p_align > 1
2390 && pPhdr->p_memsz > 0
2391 && pPhdr->p_filesz > 0
2392 && (pPhdr->p_offset & (pPhdr->p_align - 1)) != (pPhdr->p_vaddr & (pPhdr->p_align - 1)))
2393 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2394 "%s: Prog Hdr #%u: misaligned p_offset=" FMT_ELF_OFF " p_vaddr=" FMT_ELF_ADDR " p_align=" FMT_ELF_XWORD,
2395 pszLogName, i, pPhdr->p_offset, pPhdr->p_vaddr, pPhdr->p_align);
2396
2397 /* Do some type specfic checks: */
2398 switch (pPhdr->p_type)
2399 {
2400 case PT_LOAD:
2401 {
2402 if (pPhdr->p_memsz < pPhdr->p_filesz)
2403 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2404 "%s: Prog Hdr #%u/LOAD#%u: bogus p_memsz=" FMT_ELF_XWORD " or p_filesz=" FMT_ELF_XWORD,
2405 pszLogName, i, iLoad, pPhdr->p_memsz, pPhdr->p_filesz);
2406 cbImage = pPhdr->p_vaddr + pPhdr->p_memsz;
2407 if (iLoad == 0)
2408 uLinkAddress = pPhdr->p_vaddr;
2409
2410 /* Find the corresponding sections, checking their addresses and
2411 file offsets since the rest of the code is still section based
2412 rather than using program headers as it should... */
2413 Elf_Off off = pPhdr->p_offset;
2414 Elf_Addr uAddr = pPhdr->p_vaddr;
2415 Elf_Xword cbMem = pPhdr->p_memsz;
2416 Elf_Xword cbFile = pPhdr->p_filesz;
2417
2418 /* HACK to allow loading isolinux-debug.elf where program headers aren't
2419 sorted by virtual address. */
2420 if ( (fFlags & RTLDR_O_FOR_DEBUG)
2421 && uAddr != paShdrs[iLoadShdr].sh_addr)
2422 {
2423 for (unsigned iShdr = 1; iShdr < pModElf->Ehdr.e_shnum; iShdr++)
2424 if (uAddr == paShdrs[iShdr].sh_addr)
2425 {
2426 iLoadShdr = iShdr;
2427 break;
2428 }
2429 }
2430
2431 while (cbMem > 0)
2432 {
2433 if (iLoadShdr < pModElf->Ehdr.e_shnum)
2434 { /* likely */ }
2435 else if (iLoadShdr == pModElf->Ehdr.e_shnum)
2436 {
2437 /** @todo anything else to check here? */
2438 iLoadShdr++;
2439 break;
2440 }
2441 else
2442 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2443 "%s: Prog Hdr #%u/LOAD#%u: Out of sections at " FMT_ELF_ADDR " LB " FMT_ELF_XWORD,
2444 pszLogName, i, iLoad, uAddr, cbMem);
2445 if (!(paShdrs[iLoadShdr].sh_flags & SHF_ALLOC))
2446 {
2447 if ( paShdrs[iLoadShdr].sh_type != SHT_NOBITS
2448 && paShdrs[iLoadShdr].sh_size > 0
2449 && off < paShdrs[iLoadShdr].sh_offset + paShdrs[iLoadShdr].sh_size
2450 && paShdrs[iLoadShdr].sh_offset < off + cbMem)
2451 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2452 "%s: Prog Hdr #%u/LOAD#%u: Overlaps with !SHF_ALLOC section at " FMT_ELF_OFF " LB " FMT_ELF_XWORD,
2453 pszLogName, i, iLoad, paShdrs[iLoadShdr].sh_offset, paShdrs[iLoadShdr].sh_size);
2454 pModElf->paShdrExtras[iLoadShdr].idxPhdr = UINT16_MAX;
2455 iLoadShdr++;
2456 continue;
2457 }
2458
2459 if (uAddr != paShdrs[iLoadShdr].sh_addr)
2460 {
2461 /* Before the first section we expect headers to be loaded, so
2462 that the file is simply mapped from file offset zero. */
2463 if ( iLoadShdr == 1
2464 && iLoad == 0
2465 && paShdrs[1].sh_addr == paShdrs[1].sh_offset
2466 && cbFile >= paShdrs[1].sh_offset
2467 && cbMem >= paShdrs[1].sh_offset)
2468 {
2469 /* Modify paShdrs[0] to describe the gap. ".elf.headers" */
2470 pModElf->iFirstSect = 0;
2471 pModElf->paShdrs[0].sh_name = 0;
2472 pModElf->paShdrs[0].sh_type = SHT_PROGBITS;
2473 pModElf->paShdrs[0].sh_flags = SHF_ALLOC
2474 | (pPhdr->p_flags & PF_W ? SHF_WRITE : 0)
2475 | (pPhdr->p_flags & PF_X ? SHF_EXECINSTR : 0);
2476 pModElf->paShdrs[0].sh_addr = uAddr;
2477 pModElf->paShdrs[0].sh_offset = off;
2478 pModElf->paShdrs[0].sh_size = paShdrs[1].sh_offset;
2479 pModElf->paShdrs[0].sh_link = 0;
2480 pModElf->paShdrs[0].sh_info = 0;
2481 pModElf->paShdrs[0].sh_addralign = pPhdr->p_align;
2482 pModElf->paShdrs[0].sh_entsize = 0;
2483 *(Elf_Shdr *)pModElf->paOrgShdrs = pModElf->paShdrs[0]; /* (necessary for segment enumeration) */
2484
2485 uAddr += paShdrs[1].sh_offset;
2486 cbMem -= paShdrs[1].sh_offset;
2487 cbFile -= paShdrs[1].sh_offset;
2488 off = paShdrs[1].sh_offset;
2489 }
2490 /* Alignment padding? Allow up to a page size. */
2491 else if ( paShdrs[iLoadShdr].sh_addr > uAddr
2492 && paShdrs[iLoadShdr].sh_addr - uAddr
2493 < RT_MAX(paShdrs[iLoadShdr].sh_addralign, cbPage /*got.plt hack*/))
2494 {
2495 Elf_Xword cbAlignPadding = paShdrs[iLoadShdr].sh_addr - uAddr;
2496 if (cbAlignPadding >= cbMem)
2497 break;
2498 cbMem -= cbAlignPadding;
2499 uAddr += cbAlignPadding;
2500 if (cbFile > cbAlignPadding)
2501 {
2502 off += cbAlignPadding;
2503 cbFile -= cbAlignPadding;
2504 }
2505 else
2506 {
2507 off += cbFile;
2508 cbFile = 0;
2509 }
2510 }
2511 }
2512
2513 if ( uAddr == paShdrs[iLoadShdr].sh_addr
2514 && cbMem >= paShdrs[iLoadShdr].sh_size
2515 && ( paShdrs[iLoadShdr].sh_type != SHT_NOBITS
2516 ? off == paShdrs[iLoadShdr].sh_offset
2517 && cbFile >= paShdrs[iLoadShdr].sh_size /* this might be too strict... */
2518 : cbFile == 0
2519 || cbMem > paShdrs[iLoadShdr].sh_size /* isolinux.elf: linker merge no-bits and progbits sections */) )
2520 {
2521 if ( paShdrs[iLoadShdr].sh_type != SHT_NOBITS
2522 || cbFile != 0)
2523 {
2524 off += paShdrs[iLoadShdr].sh_size;
2525 cbFile -= paShdrs[iLoadShdr].sh_size;
2526 }
2527 uAddr += paShdrs[iLoadShdr].sh_size;
2528 cbMem -= paShdrs[iLoadShdr].sh_size;
2529 }
2530 else
2531 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2532 "%s: Prog Hdr #%u/LOAD#%u: Mismatch at " FMT_ELF_ADDR " LB " FMT_ELF_XWORD " (file " FMT_ELF_OFF " LB " FMT_ELF_XWORD ") with section #%u " FMT_ELF_ADDR " LB " FMT_ELF_XWORD " (file " FMT_ELF_OFF " sh_type=" FMT_ELF_WORD ")",
2533 pszLogName, i, iLoad, uAddr, cbMem, off, cbFile,
2534 iLoadShdr, paShdrs[iLoadShdr].sh_addr, paShdrs[iLoadShdr].sh_size,
2535 paShdrs[iLoadShdr].sh_offset, paShdrs[iLoadShdr].sh_type);
2536
2537 pModElf->paShdrExtras[iLoadShdr].idxPhdr = iLoad;
2538 iLoadShdr++;
2539 } /* section loop */
2540
2541 iLoad++;
2542 break;
2543 }
2544
2545 case PT_DYNAMIC:
2546 {
2547 const Elf_Shdr *pShdr = &pModElf->paShdrs[pModElf->iShDynamic];
2548 if (pPhdr->p_offset != pShdr->sh_offset)
2549 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2550 "%s: Prog Hdr #%u/DYNAMIC: p_offset=" FMT_ELF_OFF " expected " FMT_ELF_OFF,
2551 pszLogName, i, pPhdr->p_offset, pShdr->sh_offset);
2552 if (RT_MAX(pPhdr->p_memsz, pPhdr->p_filesz) != pShdr->sh_size)
2553 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2554 "%s: Prog Hdr #%u/DYNAMIC: expected " FMT_ELF_XWORD " for RT_MAX(p_memsz=" FMT_ELF_XWORD ", p_filesz=" FMT_ELF_XWORD ")",
2555 pszLogName, i, pShdr->sh_size, pPhdr->p_memsz, pPhdr->p_filesz);
2556 cDynamic++;
2557 break;
2558 }
2559 }
2560 }
2561
2562 if (iLoad == 0)
2563 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "%s: No PT_LOAD program headers", pszLogName);
2564 if (cDynamic != 1)
2565 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "%s: No program header for the DYNAMIC section", pszLogName);
2566
2567 cbImage -= uLinkAddress;
2568 pModElf->cbImage = (uint64_t)cbImage;
2569 pModElf->LinkAddress = uLinkAddress;
2570 AssertReturn(pModElf->cbImage == cbImage, VERR_INTERNAL_ERROR_5);
2571 Log3(("RTLdrELF: LinkAddress=" FMT_ELF_ADDR " cbImage=" FMT_ELF_ADDR " (from PT_LOAD)\n", uLinkAddress, cbImage));
2572
2573 for (; iLoadShdr < pModElf->Ehdr.e_shnum; iLoadShdr++)
2574 if ( !(paShdrs[iLoadShdr].sh_flags & SHF_ALLOC)
2575 || paShdrs[iLoadShdr].sh_size == 0)
2576 pModElf->paShdrExtras[iLoadShdr].idxPhdr = UINT16_MAX;
2577 else
2578 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2579 "%s: No PT_LOAD for section #%u " FMT_ELF_ADDR " LB " FMT_ELF_XWORD " (file " FMT_ELF_OFF " sh_type=" FMT_ELF_WORD ")",
2580 pszLogName, iLoadShdr, paShdrs[iLoadShdr].sh_addr, paShdrs[iLoadShdr].sh_size,
2581 paShdrs[iLoadShdr].sh_offset, paShdrs[iLoadShdr].sh_type);
2582
2583 /*
2584 * Load and validate the dynamic table. We have got / will get most of the
2585 * info we need from the section table, so we must make sure this matches up.
2586 */
2587 Log3(("RTLdrELF: Dynamic section - %u entries\n", pModElf->cDynamic));
2588 size_t const cbDynamic = pModElf->cDynamic * sizeof(pModElf->paDynamic[0]);
2589 Elf_Dyn * const paDynamic = (Elf_Dyn *)RTMemAlloc(cbDynamic);
2590 AssertReturn(paDynamic, VERR_NO_MEMORY);
2591 pModElf->paDynamic = paDynamic;
2592
2593 rc = pModElf->Core.pReader->pfnRead(pModElf->Core.pReader, paDynamic, cbDynamic, paShdrs[pModElf->iShDynamic].sh_offset);
2594 if (RT_FAILURE(rc))
2595 return RTERRINFO_LOG_SET_F(pErrInfo, rc, "%s: pfnRead(,,%#zx, " FMT_ELF_OFF ") -> %Rrc",
2596 pszLogName, cbDynamic, paShdrs[pModElf->iShDynamic].sh_offset, rc);
2597
2598 for (uint32_t i = 0; i < pModElf->cDynamic; i++)
2599 {
2600#define LOG_VALIDATE_PTR_RET(szName) do { \
2601 Log3(("RTLdrELF: DT[%u]: %16s " FMT_ELF_ADDR "\n", i, szName, paDynamic[i].d_un.d_ptr)); \
2602 if ((uint64_t)paDynamic[i].d_un.d_ptr - uLinkAddress < cbImage) { /* likely */ } \
2603 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" szName ": Invalid address " FMT_ELF_ADDR " (valid range: " FMT_ELF_ADDR " LB " FMT_ELF_ADDR ")", \
2604 pszLogName, i, paDynamic[i].d_un.d_ptr, uLinkAddress, cbImage); \
2605 } while (0)
2606#define LOG_VALIDATE_PTR_VAL_RET(szName, uExpected) do { \
2607 Log3(("RTLdrELF: DT[%u]: %16s " FMT_ELF_ADDR "\n", i, szName, (uint64_t)paDynamic[i].d_un.d_ptr)); \
2608 if (paDynamic[i].d_un.d_ptr == (Elf_Addr)(uExpected)) { /* likely */ } \
2609 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" szName ": " FMT_ELF_ADDR ", expected " FMT_ELF_ADDR, \
2610 pszLogName, i, paDynamic[i].d_un.d_ptr, (Elf_Addr)(uExpected)); \
2611 } while (0)
2612#define LOG_VALIDATE_STR_RET(szName) do { \
2613 Log3(("RTLdrELF: DT[%u]: %16s %#RX64\n", i, szName, (uint64_t)paDynamic[i].d_un.d_val)); \
2614 if ((uint64_t)paDynamic[i].d_un.d_val < pModElf->Dyn.cbStr) { /* likely */ } \
2615 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" szName ": Invalid string table offset %#RX64 (max %#x)", \
2616 pszLogName, i, (uint64_t)paDynamic[i].d_un.d_val, pModElf->Dyn.cbStr); \
2617 } while (0)
2618#define LOG_VALIDATE_VAL_RET(szName, uExpected) do { \
2619 Log3(("RTLdrELF: DT[%u]: %16s %#RX64\n", i, szName, (uint64_t)paDynamic[i].d_un.d_val)); \
2620 if ((uint64_t)paDynamic[i].d_un.d_val == (uint64_t)(uExpected)) { /* likely */ } \
2621 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" szName ": %#RX64, expected %#RX64", \
2622 pszLogName, i, (uint64_t)paDynamic[i].d_un.d_val, (uint64_t)(uExpected)); \
2623 } while (0)
2624#define SET_RELOC_TYPE_RET(a_szName, a_uType) do { \
2625 if (pModElf->DynInfo.uRelocType == 0 || pModElf->DynInfo.uRelocType == (a_uType)) \
2626 pModElf->DynInfo.uRelocType = (a_uType); \
2627 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" a_szName ": Mixing DT_RELA and DT_REL", pszLogName, i); \
2628 } while (0)
2629#define SET_INFO_FIELD_RET(a_szName, a_Field, a_Value, a_UnsetValue, a_szFmt) do { \
2630 if ((a_Field) == (a_UnsetValue) && (a_Value) != (a_UnsetValue)) \
2631 (a_Field) = (a_Value); /* likely */ \
2632 else if ((a_Field) != (a_UnsetValue)) \
2633 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" a_szName ": Multiple entries (first value " a_szFmt ", second " a_szFmt ")", pszLogName, i, (a_Field), (a_Value)); \
2634 else if ((a_Value) != (a_UnsetValue)) \
2635 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" a_szName ": Unexpected value " a_szFmt, pszLogName, i, (a_Value)); \
2636 } while (0)
2637#define FIND_MATCHING_SECTION_RET(a_szName, a_ExtraMatchExpr, a_idxShFieldToSet) do { \
2638 unsigned iSh; \
2639 for (iSh = 1; iSh < pModElf->Ehdr.e_shnum; iSh++) \
2640 if ( paShdrs[iSh].sh_addr == paDynamic[i].d_un.d_ptr \
2641 && (a_ExtraMatchExpr)) \
2642 { \
2643 (a_idxShFieldToSet) = iSh; \
2644 if (pModElf->paShdrExtras[iSh].idxDt != UINT16_MAX) \
2645 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, \
2646 "%s: DT[%u]/" a_szName ": section #%u (" FMT_ELF_ADDR ") already referenced by DT[%u]", \
2647 pszLogName, i, iSh, paShdrs[iSh].sh_addr, pModElf->paShdrExtras[iSh].idxDt); \
2648 pModElf->paShdrExtras[iSh].idxDt = i; \
2649 pModElf->paShdrExtras[iSh].uDtTag = (uint32_t)paDynamic[i].d_tag; \
2650 break; \
2651 } \
2652 if (iSh < pModElf->Ehdr.e_shnum) { /* likely */ } \
2653 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" a_szName ": No matching section for " FMT_ELF_ADDR, pszLogName, i, paDynamic[i].d_un.d_ptr); \
2654 } while (0)
2655#define ONLY_FOR_DEBUG_OR_VALIDATION_RET(a_szName) do { \
2656 if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)) { /* likely */ } \
2657 else return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/" a_szName ": Not supported (" FMT_ELF_ADDR ")", pszLogName, i, paDynamic[i].d_un.d_ptr); \
2658 } while (0)
2659#define LOG_NON_VALUE_ENTRY(a_szName) Log3(("RTLdrELF: DT[%u]: %16s (%#RX64)\n", i, a_szName, (uint64_t)paDynamic[i].d_un.d_val))
2660
2661 switch (paDynamic[i].d_tag)
2662 {
2663 case DT_NULL:
2664 LOG_NON_VALUE_ENTRY("DT_NULL");
2665 for (unsigned iNull = i + 1; iNull < pModElf->cDynamic; iNull++)
2666 if (paDynamic[i].d_tag == DT_NULL) /* Not technically a bug, but let's try being extremely strict for now */
2667 LOG_NON_VALUE_ENTRY("DT_NULL");
2668 else if (!(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
2669 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2670 "%s: DT[%u]/DT_NULL: Dynamic section isn't zero padded (extra #%u of #%u)",
2671 pszLogName, i, iNull - i, pModElf->cDynamic - i);
2672 i = pModElf->cDynamic;
2673 break;
2674 case DT_NEEDED:
2675 LOG_VALIDATE_STR_RET("DT_NEEDED");
2676 break;
2677 case DT_PLTRELSZ:
2678 Log3(("RTLdrELF: DT[%u]: %16s %#RX64 bytes\n", i, "DT_PLTRELSZ", (uint64_t)paDynamic[i].d_un.d_val));
2679 SET_INFO_FIELD_RET("DT_PLTRELSZ", pModElf->DynInfo.cbJmpRelocs, (Elf_Xword)paDynamic[i].d_un.d_val, 0, FMT_ELF_XWORD);
2680 break;
2681 case DT_PLTGOT:
2682 LOG_VALIDATE_PTR_RET("DT_PLTGOT");
2683 break;
2684 case DT_HASH:
2685 LOG_VALIDATE_PTR_RET("DT_HASH");
2686 break;
2687 case DT_STRTAB:
2688 LOG_VALIDATE_PTR_VAL_RET("DT_STRTAB", paShdrs[pModElf->Dyn.iStrSh].sh_addr);
2689 pModElf->paShdrExtras[pModElf->Dyn.iStrSh].idxDt = i;
2690 pModElf->paShdrExtras[pModElf->Dyn.iSymSh].uDtTag = DT_STRTAB;
2691 break;
2692 case DT_SYMTAB:
2693 LOG_VALIDATE_PTR_VAL_RET("DT_SYMTAB", paShdrs[pModElf->Dyn.iSymSh].sh_addr);
2694 pModElf->paShdrExtras[pModElf->Dyn.iSymSh].idxDt = i;
2695 pModElf->paShdrExtras[pModElf->Dyn.iSymSh].uDtTag = DT_SYMTAB;
2696 break;
2697 case DT_RELA:
2698 LOG_VALIDATE_PTR_RET("DT_RELA");
2699 SET_RELOC_TYPE_RET("DT_RELA", DT_RELA);
2700 SET_INFO_FIELD_RET("DT_RELA", pModElf->DynInfo.uPtrRelocs, paDynamic[i].d_un.d_ptr, ~(Elf_Addr)0, FMT_ELF_ADDR);
2701 FIND_MATCHING_SECTION_RET("DT_RELA", paShdrs[iSh].sh_type == SHT_RELA, pModElf->DynInfo.idxShRelocs);
2702 break;
2703 case DT_RELASZ:
2704 Log3(("RTLdrELF: DT[%u]: %16s %#RX64 bytes\n", i, "DT_RELASZ", (uint64_t)paDynamic[i].d_un.d_val));
2705 SET_RELOC_TYPE_RET("DT_RELASZ", DT_RELA);
2706 SET_INFO_FIELD_RET("DT_RELASZ", pModElf->DynInfo.cbRelocs, (Elf_Xword)paDynamic[i].d_un.d_val, 0, FMT_ELF_XWORD);
2707 break;
2708 case DT_RELAENT:
2709 LOG_VALIDATE_VAL_RET("DT_RELAENT", sizeof(Elf_Rela));
2710 SET_RELOC_TYPE_RET("DT_RELAENT", DT_RELA);
2711 SET_INFO_FIELD_RET("DT_RELAENT", pModElf->DynInfo.cbRelocEntry, (unsigned)sizeof(Elf_Rela), 0, "%u");
2712 break;
2713 case DT_STRSZ:
2714 LOG_VALIDATE_VAL_RET("DT_STRSZ", pModElf->Dyn.cbStr);
2715 break;
2716 case DT_SYMENT:
2717 LOG_VALIDATE_VAL_RET("DT_SYMENT", sizeof(Elf_Sym));
2718 break;
2719 case DT_INIT:
2720 LOG_VALIDATE_PTR_RET("DT_INIT");
2721 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_INIT");
2722 break;
2723 case DT_FINI:
2724 LOG_VALIDATE_PTR_RET("DT_FINI");
2725 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_FINI");
2726 break;
2727 case DT_SONAME:
2728 LOG_VALIDATE_STR_RET("DT_SONAME");
2729 break;
2730 case DT_RPATH:
2731 LOG_VALIDATE_STR_RET("DT_RPATH");
2732 break;
2733 case DT_SYMBOLIC:
2734 LOG_NON_VALUE_ENTRY("DT_SYMBOLIC");
2735 break;
2736 case DT_REL:
2737 LOG_VALIDATE_PTR_RET("DT_REL");
2738 SET_RELOC_TYPE_RET("DT_REL", DT_REL);
2739 SET_INFO_FIELD_RET("DT_REL", pModElf->DynInfo.uPtrRelocs, paDynamic[i].d_un.d_ptr, ~(Elf_Addr)0, FMT_ELF_ADDR);
2740 FIND_MATCHING_SECTION_RET("DT_REL", paShdrs[iSh].sh_type == SHT_REL, pModElf->DynInfo.idxShRelocs);
2741 break;
2742 case DT_RELSZ:
2743 Log3(("RTLdrELF: DT[%u]: %16s %#RX64 bytes\n", i, "DT_RELSZ", (uint64_t)paDynamic[i].d_un.d_val));
2744 SET_RELOC_TYPE_RET("DT_RELSZ", DT_REL);
2745 SET_INFO_FIELD_RET("DT_RELSZ", pModElf->DynInfo.cbRelocs, (Elf_Xword)paDynamic[i].d_un.d_val, 0, FMT_ELF_XWORD);
2746 break;
2747 case DT_RELENT:
2748 LOG_VALIDATE_VAL_RET("DT_RELENT", sizeof(Elf_Rel));
2749 SET_RELOC_TYPE_RET("DT_RELENT", DT_REL);
2750 SET_INFO_FIELD_RET("DT_RELENT", pModElf->DynInfo.cbRelocEntry, (unsigned)sizeof(Elf_Rel), 0, "%u");
2751 break;
2752 case DT_PLTREL:
2753 if (paDynamic[i].d_un.d_val != DT_RELA && paDynamic[i].d_un.d_val != DT_REL)
2754 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT[%u]/DT_PLTREL: Invalid value %#RX64",
2755 pszLogName, i, (uint64_t)paDynamic[i].d_un.d_val);
2756 Log3(("RTLdrELF: DT[%u]: %16s DT_REL%s\n", i, "DT_PLTREL", paDynamic[i].d_un.d_val == DT_RELA ? "A" : ""));
2757 SET_INFO_FIELD_RET("DT_PLTREL", pModElf->DynInfo.uJmpRelocType, (unsigned)paDynamic[i].d_un.d_val, 0, "%u");
2758 break;
2759 case DT_DEBUG:
2760 /*
2761 * DT_DEBUG is filled in by the dynamic linker to point a debugger to the head of the link map,
2762 * it can point anywhere in userspace. For binaries not being executed it will be 0,
2763 * so there is nothing we can validate here (and it is not required as we don't use
2764 * this dynamic section). See https://ypl.coffee/dl-resolve-full-relro/ for more information.
2765 */
2766 break;
2767 case DT_TEXTREL:
2768 LOG_NON_VALUE_ENTRY("DT_TEXTREL");
2769 break;
2770 case DT_JMPREL:
2771 LOG_VALIDATE_PTR_RET("DT_JMPREL");
2772 SET_INFO_FIELD_RET("DT_JMPREL", pModElf->DynInfo.uPtrJmpRelocs, paDynamic[i].d_un.d_ptr, ~(Elf_Addr)0, FMT_ELF_ADDR);
2773 FIND_MATCHING_SECTION_RET("DT_JMPREL", 1, pModElf->DynInfo.idxShJmpRelocs);
2774 break;
2775 case DT_BIND_NOW:
2776 LOG_NON_VALUE_ENTRY("DT_BIND_NOW");
2777 break;
2778 case DT_INIT_ARRAY:
2779 LOG_VALIDATE_PTR_RET("DT_INIT_ARRAY");
2780 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_INIT_ARRAY");
2781 break;
2782 case DT_FINI_ARRAY:
2783 LOG_VALIDATE_PTR_RET("DT_FINI_ARRAY");
2784 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_FINI_ARRAY");
2785 break;
2786 case DT_INIT_ARRAYSZ:
2787 Log3(("RTLdrELF: DT[%u]: %16s %#RX64 bytes\n", i, "DT_INIT_ARRAYSZ", (uint64_t)paDynamic[i].d_un.d_val));
2788 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_INIT_ARRAYSZ");
2789 break;
2790 case DT_FINI_ARRAYSZ:
2791 Log3(("RTLdrELF: DT[%u]: %16s %#RX64 bytes\n", i, "DT_FINI_ARRAYSZ", (uint64_t)paDynamic[i].d_un.d_val));
2792 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_FINI_ARRAYSZ");
2793 break;
2794 case DT_RUNPATH:
2795 LOG_VALIDATE_STR_RET("DT_RUNPATH");
2796 break;
2797 case DT_FLAGS:
2798 Log3(("RTLdrELF: DT[%u]: %16s %#RX64\n", i, "DT_FLAGS", (uint64_t)paDynamic[i].d_un.d_val));
2799 break;
2800 case DT_PREINIT_ARRAY:
2801 LOG_VALIDATE_PTR_RET("DT_PREINIT_ARRAY");
2802 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_PREINIT_ARRAY");
2803 break;
2804 case DT_PREINIT_ARRAYSZ:
2805 Log3(("RTLdrELF: DT[%u]: %16s %#RX64 bytes\n", i, "DT_PREINIT_ARRAYSZ", (uint64_t)paDynamic[i].d_un.d_val));
2806 ONLY_FOR_DEBUG_OR_VALIDATION_RET("DT_PREINIT_ARRAYSZ");
2807 break;
2808 default:
2809 if ( paDynamic[i].d_tag < DT_ENCODING
2810 || paDynamic[i].d_tag >= DT_LOOS
2811 || (paDynamic[i].d_tag & 1))
2812 Log3(("RTLdrELF: DT[%u]: %#010RX64 %#RX64%s\n", i, (uint64_t)paDynamic[i].d_tag,
2813 (uint64_t)paDynamic[i].d_un.d_val, paDynamic[i].d_un.d_val >= DT_ENCODING ? " (val)" : ""));
2814 else
2815 {
2816 Log3(("RTLdrELF: DT[%u]: %#010RX64 " FMT_ELF_ADDR " (addr)\n",
2817 i, (uint64_t)paDynamic[i].d_tag, paDynamic[i].d_un.d_ptr));
2818 if ((uint64_t)paDynamic[i].d_un.d_ptr - uLinkAddress >= cbImage)
2819 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2820 "%s: DT[%u]/%#RX64: Invalid address " FMT_ELF_ADDR " (valid range: " FMT_ELF_ADDR " LB " FMT_ELF_ADDR ")",
2821 pszLogName, i, (uint64_t)paDynamic[i].d_tag,
2822 paDynamic[i].d_un.d_ptr, uLinkAddress, cbImage);
2823 }
2824 break;
2825 }
2826#undef LOG_VALIDATE_VAL_RET
2827#undef LOG_VALIDATE_STR_RET
2828#undef LOG_VALIDATE_PTR_VAL_RET
2829#undef LOG_VALIDATE_PTR_RET
2830#undef SET_RELOC_TYPE_RET
2831#undef SET_INFO_FIELD_RET
2832#undef FIND_MATCHING_SECTION_RET
2833#undef ONLY_FOR_DEBUG_OR_VALIDATION_RET
2834 }
2835
2836 /*
2837 * Validate the relocation information we've gathered.
2838 */
2839 Elf_Word uShTypeArch = SHT_RELA; /** @todo generalize architecture specific stuff using its own code template header. */
2840 switch (pModElf->Core.enmArch)
2841 {
2842 case RTLDRARCH_AMD64:
2843 break;
2844 case RTLDRARCH_X86_32:
2845 uShTypeArch = SHT_REL;
2846 break;
2847 default:
2848 AssertFailedBreak(/** @todo page size for got.plt hacks */);
2849
2850 }
2851
2852 if (pModElf->DynInfo.uRelocType != 0)
2853 {
2854 const char * const pszModifier = pModElf->DynInfo.uRelocType == DT_RELA ? "A" : "";
2855 if (pModElf->DynInfo.uPtrRelocs == ~(Elf_Addr)0)
2856 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Missing DT_REL%s", pszLogName, pszModifier);
2857 if (pModElf->DynInfo.cbRelocs == 0)
2858 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Missing DT_REL%sSZ", pszLogName, pszModifier);
2859 if (pModElf->DynInfo.cbRelocEntry == 0)
2860 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Missing DT_REL%sENT", pszLogName, pszModifier);
2861 Elf_Shdr const *pShdrRelocs = &paShdrs[pModElf->DynInfo.idxShRelocs];
2862 Elf_Word const uShType = pModElf->DynInfo.uJmpRelocType == DT_RELA ? SHT_RELA : SHT_REL;
2863 if (pShdrRelocs->sh_type != uShType)
2864 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT_REL%s* does not match section type: %u vs %u",
2865 pszLogName, pszModifier, pShdrRelocs->sh_type, uShType);
2866 if (pShdrRelocs->sh_size != pModElf->DynInfo.cbRelocs)
2867 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT_REL%sSZ does not match section size: %u vs %u",
2868 pszLogName, pszModifier, pShdrRelocs->sh_size, pModElf->DynInfo.cbRelocs);
2869 if (uShType != uShTypeArch)
2870 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT_REL%s* does not match architecture: %u, arch wants %u",
2871 pszLogName, pszModifier, uShType, uShTypeArch);
2872 }
2873
2874 if ( pModElf->DynInfo.uPtrJmpRelocs != ~(Elf_Addr)0
2875 || pModElf->DynInfo.cbJmpRelocs != 0
2876 || pModElf->DynInfo.uJmpRelocType != 0)
2877 {
2878 if (pModElf->DynInfo.uPtrJmpRelocs == ~(Elf_Addr)0)
2879 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Missing DT_JMPREL", pszLogName);
2880 if (pModElf->DynInfo.cbJmpRelocs == 0)
2881 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Missing DT_PLTRELSZ", pszLogName);
2882 if (pModElf->DynInfo.uJmpRelocType == 0)
2883 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: Missing DT_PLTREL", pszLogName);
2884 Elf_Shdr const *pShdrRelocs = &paShdrs[pModElf->DynInfo.idxShJmpRelocs];
2885 Elf_Word const uShType = pModElf->DynInfo.uJmpRelocType == DT_RELA ? SHT_RELA : SHT_REL;
2886 if (pShdrRelocs->sh_type != uShType)
2887 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT_PLTREL does not match section type: %u vs %u",
2888 pszLogName, pShdrRelocs->sh_type, uShType);
2889 if (pShdrRelocs->sh_size != pModElf->DynInfo.cbJmpRelocs)
2890 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT_PLTRELSZ does not match section size: %u vs %u",
2891 pszLogName, pShdrRelocs->sh_size, pModElf->DynInfo.cbJmpRelocs);
2892 if (uShType != uShTypeArch)
2893 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT, "%s: DT_PLTREL does not match architecture: %u, arch wants %u",
2894 pszLogName, uShType, uShTypeArch);
2895 }
2896
2897 /*
2898 * Check that there aren't any other relocations hiding in the section table.
2899 */
2900 for (uint32_t i = 1; i < pModElf->Ehdr.e_shnum; i++)
2901 if ( (paShdrs[i].sh_type == SHT_REL || paShdrs[i].sh_type == SHT_RELA)
2902 && pModElf->paShdrExtras[i].uDtTag != DT_REL
2903 && pModElf->paShdrExtras[i].uDtTag != DT_RELA
2904 && pModElf->paShdrExtras[i].uDtTag != DT_JMPREL)
2905 {
2906 char szSecHdrNm[80];
2907 return RTERRINFO_LOG_SET_F(pErrInfo, VERR_BAD_EXE_FORMAT,
2908 "%s: section header #%u (%s type=" FMT_ELF_WORD " size=" FMT_ELF_XWORD ") contains relocations not referenced by the dynamic section",
2909 pszLogName, i,
2910 RTLDRELF_NAME(GetSHdrName)(pModElf, paShdrs[i].sh_name, szSecHdrNm, sizeof(szSecHdrNm)),
2911 paShdrs[i].sh_type, paShdrs[i].sh_size);
2912 }
2913
2914 return VINF_SUCCESS;
2915}
2916
2917
2918
2919/**
2920 * Opens an ELF image, fixed bitness.
2921 *
2922 * @returns iprt status code.
2923 * @param pReader The loader reader instance which will provide the raw image bits.
2924 * @param fFlags Reserved, MBZ.
2925 * @param enmArch Architecture specifier.
2926 * @param phLdrMod Where to store the handle.
2927 * @param pErrInfo Where to return extended error info. Optional.
2928 */
2929static int RTLDRELF_NAME(Open)(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
2930{
2931 const char *pszLogName = pReader->pfnLogName(pReader);
2932 uint64_t cbRawImage = pReader->pfnSize(pReader);
2933 RT_NOREF_PV(fFlags);
2934
2935 /*
2936 * Create the loader module instance.
2937 */
2938 PRTLDRMODELF pModElf = (PRTLDRMODELF)RTMemAllocZ(sizeof(*pModElf));
2939 if (!pModElf)
2940 return VERR_NO_MEMORY;
2941
2942 pModElf->Core.u32Magic = RTLDRMOD_MAGIC;
2943 pModElf->Core.eState = LDR_STATE_INVALID;
2944 pModElf->Core.pReader = pReader;
2945 pModElf->Core.enmFormat = RTLDRFMT_ELF;
2946 pModElf->Core.enmType = RTLDRTYPE_OBJECT;
2947 pModElf->Core.enmEndian = RTLDRENDIAN_LITTLE;
2948#if ELF_MODE == 32
2949 pModElf->Core.enmArch = RTLDRARCH_X86_32;
2950#else
2951 pModElf->Core.enmArch = RTLDRARCH_AMD64;
2952#endif
2953 //pModElf->pvBits = NULL;
2954 //pModElf->Ehdr = {0};
2955 //pModElf->paShdrs = NULL;
2956 //pModElf->Rel.paSyms = NULL;
2957 pModElf->Rel.iSymSh = ~0U;
2958 //pModElf->Rel.cSyms = 0;
2959 pModElf->Rel.iStrSh = ~0U;
2960 //pModElf->Rel.cbStr = 0;
2961 //pModElf->Rel.pStr = NULL;
2962 //pModElf->Dyn.paSyms = NULL;
2963 pModElf->Dyn.iSymSh = ~0U;
2964 //pModElf->Dyn.cSyms = 0;
2965 pModElf->Dyn.iStrSh = ~0U;
2966 //pModElf->Dyn.cbStr = 0;
2967 //pModElf->Dyn.pStr = NULL;
2968 pModElf->iFirstSect = 1;
2969 //pModElf->fShdrInOrder = false;
2970 //pModElf->cbImage = 0;
2971 pModElf->LinkAddress = ~(Elf_Addr)0;
2972 //pModElf->cbShStr = 0;
2973 //pModElf->pShStr = NULL;
2974 //pModElf->iShEhFrame = 0;
2975 //pModElf->iShEhFrameHdr= 0;
2976 pModElf->iShDynamic = ~0U;
2977 //pModElf->cDynamic = 0;
2978 //pModElf->paDynamic = NULL;
2979 //pModElf->paPhdrs = NULL;
2980 pModElf->DynInfo.uPtrRelocs = ~(Elf_Addr)0;
2981 //pModElf->DynInfo.cbRelocs = 0;
2982 //pModElf->DynInfo.cbRelocEntry = 0;
2983 //pModElf->DynInfo.uRelocType = 0;
2984 //pModElf->DynInfo.idxShRelocs = 0;
2985 pModElf->DynInfo.uPtrJmpRelocs = ~(Elf_Addr)0;
2986 //pModElf->DynInfo.cbJmpRelocs = 0;
2987 //pModElf->DynInfo.uJmpRelocType = 0;
2988 //pModElf->DynInfo.idxShJmpRelocs = 0;
2989
2990 /*
2991 * Read and validate the ELF header and match up the CPU architecture.
2992 */
2993 int rc = pReader->pfnRead(pReader, &pModElf->Ehdr, sizeof(pModElf->Ehdr), 0);
2994 if (RT_SUCCESS(rc))
2995 {
2996 RTLDRARCH enmArchImage = RTLDRARCH_INVALID; /* shut up gcc */
2997 rc = RTLDRELF_NAME(ValidateElfHeader)(&pModElf->Ehdr, cbRawImage, pszLogName, &enmArchImage, pErrInfo);
2998 if (RT_SUCCESS(rc))
2999 {
3000 if ( enmArch != RTLDRARCH_WHATEVER
3001 && enmArch != enmArchImage)
3002 rc = VERR_LDR_ARCH_MISMATCH;
3003 }
3004 }
3005 if (RT_SUCCESS(rc))
3006 {
3007 /*
3008 * Read the section headers, keeping a prestine copy for the module
3009 * introspection methods.
3010 */
3011 size_t const cbShdrs = pModElf->Ehdr.e_shnum * sizeof(Elf_Shdr);
3012 Elf_Shdr *paShdrs = (Elf_Shdr *)RTMemAlloc(cbShdrs * 2 + sizeof(RTLDRMODELFSHX) * pModElf->Ehdr.e_shnum);
3013 if (paShdrs)
3014 {
3015 pModElf->paShdrs = paShdrs;
3016 rc = pReader->pfnRead(pReader, paShdrs, cbShdrs, pModElf->Ehdr.e_shoff);
3017 if (RT_SUCCESS(rc))
3018 {
3019 memcpy(&paShdrs[pModElf->Ehdr.e_shnum], paShdrs, cbShdrs);
3020 pModElf->paOrgShdrs = &paShdrs[pModElf->Ehdr.e_shnum];
3021
3022 pModElf->paShdrExtras = (PRTLDRMODELFSHX)&pModElf->paOrgShdrs[pModElf->Ehdr.e_shnum];
3023 memset(pModElf->paShdrExtras, 0xff, sizeof(RTLDRMODELFSHX) * pModElf->Ehdr.e_shnum);
3024
3025 pModElf->cbShStr = paShdrs[pModElf->Ehdr.e_shstrndx].sh_size;
3026
3027 /*
3028 * Validate the section headers and find relevant sections.
3029 */
3030 rc = RTLDRELF_NAME(ValidateAndProcessSectionHeaders)(pModElf, paShdrs, cbRawImage, pszLogName, pErrInfo);
3031
3032 /*
3033 * Read validate and process program headers if ET_DYN or ET_EXEC.
3034 */
3035 if (RT_SUCCESS(rc) && (pModElf->Ehdr.e_type == ET_DYN || pModElf->Ehdr.e_type == ET_EXEC))
3036 rc = RTLDRELF_NAME(ValidateAndProcessDynamicInfo)(pModElf, cbRawImage, fFlags, pszLogName, pErrInfo);
3037
3038 /*
3039 * Massage the section headers.
3040 */
3041 if (RT_SUCCESS(rc))
3042 {
3043 if (pModElf->Ehdr.e_type == ET_REL)
3044 {
3045 /* Do allocations and figure the image size: */
3046 pModElf->LinkAddress = 0;
3047 for (unsigned i = 1; i < pModElf->Ehdr.e_shnum; i++)
3048 if (paShdrs[i].sh_flags & SHF_ALLOC)
3049 {
3050 paShdrs[i].sh_addr = paShdrs[i].sh_addralign
3051 ? RT_ALIGN_T(pModElf->cbImage, paShdrs[i].sh_addralign, Elf_Addr)
3052 : (Elf_Addr)pModElf->cbImage;
3053 Elf_Addr EndAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
3054 if (pModElf->cbImage < EndAddr)
3055 {
3056 pModElf->cbImage = (size_t)EndAddr;
3057 AssertMsgBreakStmt(pModElf->cbImage == EndAddr, (FMT_ELF_ADDR "\n", EndAddr), rc = VERR_IMAGE_TOO_BIG);
3058 }
3059 Log2(("RTLdrElf: %s: Assigned " FMT_ELF_ADDR " to section #%d\n", pszLogName, paShdrs[i].sh_addr, i));
3060 }
3061 }
3062 else
3063 {
3064 /* Convert sh_addr to RVA: */
3065 Assert(pModElf->LinkAddress != ~(Elf_Addr)0);
3066 for (unsigned i = 0 /*!*/; i < pModElf->Ehdr.e_shnum; i++)
3067 if (paShdrs[i].sh_flags & SHF_ALLOC)
3068 paShdrs[i].sh_addr -= pModElf->LinkAddress;
3069 }
3070 }
3071
3072 /*
3073 * Check if the sections are in order by address, as that will simplify
3074 * enumeration and address translation.
3075 */
3076 pModElf->fShdrInOrder = true;
3077 Elf_Addr uEndAddr = 0;
3078 for (unsigned i = pModElf->iFirstSect; i < pModElf->Ehdr.e_shnum; i++)
3079 if (paShdrs[i].sh_flags & SHF_ALLOC)
3080 {
3081 if (uEndAddr <= paShdrs[i].sh_addr)
3082 uEndAddr = paShdrs[i].sh_addr + paShdrs[i].sh_size;
3083 else
3084 {
3085 pModElf->fShdrInOrder = false;
3086 break;
3087 }
3088 }
3089
3090 Log2(("RTLdrElf: iSymSh=%u cSyms=%u iStrSh=%u cbStr=%u rc=%Rrc cbImage=%#zx LinkAddress=" FMT_ELF_ADDR " fShdrInOrder=%RTbool\n",
3091 pModElf->Rel.iSymSh, pModElf->Rel.cSyms, pModElf->Rel.iStrSh, pModElf->Rel.cbStr, rc,
3092 pModElf->cbImage, pModElf->LinkAddress, pModElf->fShdrInOrder));
3093 if (RT_SUCCESS(rc))
3094 {
3095 pModElf->Core.pOps = &RTLDRELF_MID(s_rtldrElf,Ops);
3096 pModElf->Core.eState = LDR_STATE_OPENED;
3097 *phLdrMod = &pModElf->Core;
3098
3099 LogFlow(("%s: %s: returns VINF_SUCCESS *phLdrMod=%p\n", __FUNCTION__, pszLogName, *phLdrMod));
3100 return VINF_SUCCESS;
3101 }
3102 }
3103
3104 RTMemFree(paShdrs);
3105 }
3106 else
3107 rc = VERR_NO_MEMORY;
3108 }
3109
3110 RTMemFree(pModElf);
3111 LogFlow(("%s: returns %Rrc\n", __FUNCTION__, rc));
3112 return rc;
3113}
3114
3115
3116
3117
3118/*******************************************************************************
3119* Cleanup Constants And Macros *
3120*******************************************************************************/
3121#undef RTLDRELF_NAME
3122#undef RTLDRELF_SUFF
3123#undef RTLDRELF_MID
3124
3125#undef FMT_ELF_ADDR
3126#undef FMT_ELF_ADDR7
3127#undef FMT_ELF_HALF
3128#undef FMT_ELF_SHALF
3129#undef FMT_ELF_OFF
3130#undef FMT_ELF_SIZE
3131#undef FMT_ELF_SWORD
3132#undef FMT_ELF_WORD
3133#undef FMT_ELF_XWORD
3134#undef FMT_ELF_SXWORD
3135
3136#undef Elf_Ehdr
3137#undef Elf_Phdr
3138#undef Elf_Shdr
3139#undef Elf_Sym
3140#undef Elf_Rel
3141#undef Elf_Rela
3142#undef Elf_Reloc
3143#undef Elf_Nhdr
3144#undef Elf_Dyn
3145
3146#undef Elf_Addr
3147#undef Elf_Half
3148#undef Elf_Off
3149#undef Elf_Size
3150#undef Elf_Sword
3151#undef Elf_Word
3152#undef Elf_Xword
3153#undef Elf_Sxword
3154
3155#undef RTLDRMODELF
3156#undef PRTLDRMODELF
3157
3158#undef ELF_R_SYM
3159#undef ELF_R_TYPE
3160#undef ELF_R_INFO
3161
3162#undef ELF_ST_BIND
3163
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use