VirtualBox

source: vbox/trunk/src/bldprogs/VBoxEditElf.cpp@ 108518

Last change on this file since 108518 was 108518, checked in by vboxsync, 2 months ago

bldprogs/VBoxEditElf: Doh, need to copy from the start of the string of course, bugref:10874

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.2 KB
Line 
1/* $Id: VBoxEditElf.cpp 108518 2025-03-11 12:18:25Z vboxsync $ */
2/** @file
3 * VBoxEditElf - Simple ELF binary file editor.
4 */
5
6/*
7 * Copyright (C) 2025 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include <stdio.h>
33#include <string.h>
34#include <stdlib.h>
35
36#include <iprt/assert.h>
37#include <iprt/file.h>
38#include <iprt/getopt.h>
39#include <iprt/initterm.h>
40#include <iprt/mem.h>
41#include <iprt/message.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/types.h>
45#include <iprt/formats/elf64.h>
46
47
48/*********************************************************************************************************************************
49* Structures and Typedefs *
50*********************************************************************************************************************************/
51
52typedef struct
53{
54 Elf64_Half vd_version;
55 Elf64_Half vd_flags;
56 Elf64_Half vd_ndx;
57 Elf64_Half vd_cnt;
58 Elf64_Word vd_hash;
59 Elf64_Word vd_aux;
60 Elf64_Word vd_next;
61} Elf64_Verdef;
62
63
64typedef struct
65{
66 Elf64_Word vda_name;
67 Elf64_Word vda_next;
68} Elf64_Verdaux;
69
70
71#define SHT_GNU_versym UINT32_C(0x6fffffff)
72#define SHT_GNU_verdef UINT32_C(0x6ffffffd)
73#define SHT_GNU_verneed UINT32_C(0x6ffffffe)
74
75#define DT_VERDEF UINT32_C(0x6ffffffc)
76#define DT_VERDEFNUM UINT32_C(0x6ffffffd)
77#define DT_VERNEED UINT32_C(0x6ffffffe)
78#define DT_VERNEEDNUM UINT32_C(0x6fffffff)
79#define DT_VERSYM UINT32_C(0x6ffffff0)
80
81
82/*********************************************************************************************************************************
83* Global Variables *
84*********************************************************************************************************************************/
85/** @name Options
86 * @{ */
87static enum
88{
89 kVBoxEditElfAction_Nothing,
90 kVBoxEditElfAction_DeleteRunpath,
91 kVBoxEditElfAction_ChangeRunpath,
92 kVBoxEditElfAction_CreateLinkerStub
93} g_enmAction = kVBoxEditElfAction_Nothing;
94static const char *g_pszInput = NULL;
95/** Verbosity level. */
96static int g_cVerbosity = 0;
97/** New runpath. */
98static const char *g_pszRunpath = NULL;
99/** The output path for the stub library. */
100static const char *g_pszLinkerStub = NULL;
101/** @} */
102
103static const char s_achShStrTab[] = "\0.shstrtab\0.dynsym\0.dynstr\0.gnu.version\0.gnu.version_d\0.gnu.version_r\0.dynamic";
104
105
106static void verbose(const char *pszFmt, ...)
107{
108 if (g_cVerbosity == 0)
109 return;
110
111 va_list Args;
112 va_start(Args, pszFmt);
113 RTMsgInfoV(pszFmt, Args);
114 va_end(Args);
115}
116
117
118static RTEXITCODE deleteRunpath(const char *pszInput)
119{
120 RT_NOREF(pszInput);
121
122 RTFILE hFileElf = NIL_RTFILE;
123 int rc = RTFileOpen(&hFileElf, pszInput, RTFILE_O_OPEN | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE);
124 if (RT_FAILURE(rc))
125 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Filed to open file '%s': %Rrc\n", pszInput, rc);
126
127 /* Only support for 64-bit ELF files currently. */
128 Elf64_Ehdr Hdr;
129 rc = RTFileReadAt(hFileElf, 0, &Hdr, sizeof(Hdr), NULL);
130 if (RT_FAILURE(rc))
131 {
132 RTFileClose(hFileElf);
133 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF header from '%s': %Rrc\n", pszInput, rc);
134 }
135
136 if ( Hdr.e_ident[EI_MAG0] != ELFMAG0
137 || Hdr.e_ident[EI_MAG1] != ELFMAG1
138 || Hdr.e_ident[EI_MAG2] != ELFMAG2
139 || Hdr.e_ident[EI_MAG3] != ELFMAG3)
140 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid ELF magic (%.*Rhxs)", sizeof(Hdr.e_ident), Hdr.e_ident);
141 if (Hdr.e_ident[EI_CLASS] != ELFCLASS64)
142 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid ELF class (%.*Rhxs)", sizeof(Hdr.e_ident), Hdr.e_ident);
143 if (Hdr.e_ident[EI_DATA] != ELFDATA2LSB)
144 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF endian %x is unsupported", Hdr.e_ident[EI_DATA]);
145 if (Hdr.e_version != EV_CURRENT)
146 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF version %x is unsupported", Hdr.e_version);
147
148 if (sizeof(Elf64_Ehdr) != Hdr.e_ehsize)
149 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_ehsize is %d expected %d!", Hdr.e_ehsize, sizeof(Elf64_Ehdr));
150 if ( sizeof(Elf64_Phdr) != Hdr.e_phentsize
151 && ( Hdr.e_phnum != 0
152 || Hdr.e_type == ET_DYN
153 || Hdr.e_type == ET_EXEC))
154 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_phentsize is %d expected %d!", Hdr.e_phentsize, sizeof(Elf64_Phdr));
155 if (sizeof(Elf64_Shdr) != Hdr.e_shentsize)
156 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_shentsize is %d expected %d!", Hdr.e_shentsize, sizeof(Elf64_Shdr));
157
158 /* Find dynamic section. */
159 Elf64_Phdr Phdr; RT_ZERO(Phdr);
160 bool fFound = false;
161 for (uint32_t i = 0; i < Hdr.e_phnum; i++)
162 {
163 rc = RTFileReadAt(hFileElf, Hdr.e_phoff + i * sizeof(Phdr), &Phdr, sizeof(Phdr), NULL);
164 if (RT_FAILURE(rc))
165 {
166 RTFileClose(hFileElf);
167 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF program header header from '%s': %Rrc\n", pszInput, rc);
168 }
169 if (Phdr.p_type == PT_DYNAMIC)
170 {
171 if (!Phdr.p_filesz)
172 {
173 RTFileClose(hFileElf);
174 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Dynmic section in '%s' is empty\n", pszInput);
175 }
176 fFound = true;
177 break;
178 }
179 }
180
181 if (!fFound)
182 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF binary '%s' doesn't contain dynamic section\n", pszInput);
183
184 Elf64_Dyn *paDynSh = (Elf64_Dyn *)RTMemAllocZ(Phdr.p_filesz);
185 if (!paDynSh)
186 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes of memory for dynamic section of '%s'\n", Phdr.p_filesz, pszInput);
187
188 rc = RTFileReadAt(hFileElf, Phdr.p_offset, paDynSh, Phdr.p_filesz, NULL);
189 if (RT_FAILURE(rc))
190 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF program header header from '%s': %Rrc\n", pszInput, rc);
191
192 /* Remove all DT_RUNPATH entries and padd the remainder with DT_NULL. */
193 uint32_t idx = 0;
194 for (uint32_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
195 {
196 paDynSh[idx] = paDynSh[i];
197 if (paDynSh[i].d_tag != DT_RPATH && paDynSh[i].d_tag != DT_RUNPATH)
198 idx++;
199 }
200
201 while (idx < Phdr.p_filesz / sizeof(Elf64_Dyn))
202 {
203 paDynSh[idx].d_tag = DT_NULL;
204 paDynSh[idx].d_un.d_val = 0;
205 idx++;
206 }
207
208 /* Write the result. */
209 rc = RTFileWriteAt(hFileElf, Phdr.p_offset, paDynSh, Phdr.p_filesz, NULL);
210 if (RT_FAILURE(rc))
211 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write updated ELF dynamic section for '%s': %Rrc\n", pszInput, rc);
212
213 RTMemFree(paDynSh);
214 RTFileClose(hFileElf);
215 return RTEXITCODE_SUCCESS;
216}
217
218
219static RTEXITCODE changeRunpathEntry(RTFILE hFileElf, const char *pszInput, Elf64_Ehdr *pHdr, Elf64_Xword offInStrTab, const char *pszRunpath)
220{
221 /* Read section headers to find the string table. */
222 size_t const cbShdrs = pHdr->e_shnum * sizeof(Elf64_Shdr);
223 Elf64_Shdr *paShdrs = (Elf64_Shdr *)RTMemAlloc(cbShdrs);
224 if (!paShdrs)
225 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes of memory for section headers of '%s'\n", cbShdrs, pszInput);
226
227 int rc = RTFileReadAt(hFileElf, pHdr->e_shoff, paShdrs, cbShdrs, NULL);
228 if (RT_FAILURE(rc))
229 {
230 RTMemFree(paShdrs);
231 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read %zu bytes of section headers from '%s': %Rrc\n", cbShdrs, pszInput, rc);
232 }
233
234 uint32_t idx;
235 for (idx = 0; idx < pHdr->e_shnum; idx++)
236 {
237 if (paShdrs[idx].sh_type == SHT_STRTAB)
238 break;
239 }
240
241 if (idx == pHdr->e_shnum)
242 {
243 RTMemFree(paShdrs);
244 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF binary '%s' does not contain a string table\n", pszInput);
245 }
246
247 size_t const cbStrTab = paShdrs[idx].sh_size;
248 RTFOFF const offStrTab = paShdrs[idx].sh_offset;
249 RTMemFree(paShdrs);
250
251 if (offInStrTab >= cbStrTab)
252 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String table offset of runpath entry is out of bounds: got %#RX64, maximum is %zu\n", offInStrTab, cbStrTab - 1);
253
254 /* Read the string table. */
255 char *pbStrTab = (char *)RTMemAllocZ(cbStrTab + 1); /* Force a zero terminator. */
256 if (!pbStrTab)
257 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes of memory for string table of '%s'\n", cbStrTab + 1, pszInput);
258
259 rc = RTFileReadAt(hFileElf, offStrTab, pbStrTab, cbStrTab, NULL);
260 if (RT_FAILURE(rc))
261 {
262 RTMemFree(pbStrTab);
263 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read %zu bytes of the string table from '%s': %Rrc\n", cbStrTab, pszInput, rc);
264 }
265
266 /* Calculate the maximum number of characters we can replace. */
267 char *pbStr = &pbStrTab[offInStrTab];
268 size_t cchMax = strlen(pbStr);
269 while ( &pbStr[cchMax + 1] < &pbStrTab[cbStrTab]
270 && pbStr[cchMax] == '\0')
271 cchMax++;
272
273 size_t const cchNewRunpath = strlen(pszRunpath);
274 if (cchMax < cchNewRunpath)
275 {
276 RTMemFree(pbStrTab);
277 return RTMsgErrorExit(RTEXITCODE_FAILURE, "New runpath '%s' is too long to overwrite current one, maximum length is: %zu\n", cchNewRunpath, cchMax);
278 }
279
280 memcpy(pbStr, pszRunpath, cchNewRunpath);
281 rc = RTFileReadAt(hFileElf, offStrTab, pbStrTab, cbStrTab, NULL);
282 RTMemFree(pbStrTab);
283 if (RT_FAILURE(rc))
284 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Writing altered string table failed: %Rrc\n", rc);
285
286 return RTEXITCODE_SUCCESS;
287}
288
289
290static RTEXITCODE changeRunpath(const char *pszInput, const char *pszRunpath)
291{
292 RTFILE hFileElf = NIL_RTFILE;
293 int rc = RTFileOpen(&hFileElf, pszInput, RTFILE_O_OPEN | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE);
294 if (RT_FAILURE(rc))
295 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Filed to open file '%s': %Rrc\n", pszInput, rc);
296
297 /* Only support for 64-bit ELF files currently. */
298 Elf64_Ehdr Hdr;
299 rc = RTFileReadAt(hFileElf, 0, &Hdr, sizeof(Hdr), NULL);
300 if (RT_FAILURE(rc))
301 {
302 RTFileClose(hFileElf);
303 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF header from '%s': %Rrc\n", pszInput, rc);
304 }
305
306 if ( Hdr.e_ident[EI_MAG0] != ELFMAG0
307 || Hdr.e_ident[EI_MAG1] != ELFMAG1
308 || Hdr.e_ident[EI_MAG2] != ELFMAG2
309 || Hdr.e_ident[EI_MAG3] != ELFMAG3)
310 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid ELF magic (%.*Rhxs)", sizeof(Hdr.e_ident), Hdr.e_ident);
311 if (Hdr.e_ident[EI_CLASS] != ELFCLASS64)
312 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid ELF class (%.*Rhxs)", sizeof(Hdr.e_ident), Hdr.e_ident);
313 if (Hdr.e_ident[EI_DATA] != ELFDATA2LSB)
314 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF endian %x is unsupported", Hdr.e_ident[EI_DATA]);
315 if (Hdr.e_version != EV_CURRENT)
316 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF version %x is unsupported", Hdr.e_version);
317
318 if (sizeof(Elf64_Ehdr) != Hdr.e_ehsize)
319 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_ehsize is %d expected %d!", Hdr.e_ehsize, sizeof(Elf64_Ehdr));
320 if ( sizeof(Elf64_Phdr) != Hdr.e_phentsize
321 && ( Hdr.e_phnum != 0
322 || Hdr.e_type == ET_DYN
323 || Hdr.e_type == ET_EXEC))
324 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_phentsize is %d expected %d!", Hdr.e_phentsize, sizeof(Elf64_Phdr));
325 if (sizeof(Elf64_Shdr) != Hdr.e_shentsize)
326 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_shentsize is %d expected %d!", Hdr.e_shentsize, sizeof(Elf64_Shdr));
327
328 /* Find dynamic section. */
329 Elf64_Phdr Phdr; RT_ZERO(Phdr);
330 bool fFound = false;
331 for (uint32_t i = 0; i < Hdr.e_phnum; i++)
332 {
333 rc = RTFileReadAt(hFileElf, Hdr.e_phoff + i * sizeof(Phdr), &Phdr, sizeof(Phdr), NULL);
334 if (RT_FAILURE(rc))
335 {
336 RTFileClose(hFileElf);
337 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF program header header from '%s': %Rrc\n", pszInput, rc);
338 }
339 if (Phdr.p_type == PT_DYNAMIC)
340 {
341 if (!Phdr.p_filesz)
342 {
343 RTFileClose(hFileElf);
344 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Dynmic section in '%s' is empty\n", pszInput);
345 }
346 fFound = true;
347 break;
348 }
349 }
350
351 if (!fFound)
352 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF binary '%s' doesn't contain dynamic section\n", pszInput);
353
354 Elf64_Dyn *paDynSh = (Elf64_Dyn *)RTMemAllocZ(Phdr.p_filesz);
355 if (!paDynSh)
356 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes of memory for dynamic section of '%s'\n", Phdr.p_filesz, pszInput);
357
358 rc = RTFileReadAt(hFileElf, Phdr.p_offset, paDynSh, Phdr.p_filesz, NULL);
359 if (RT_FAILURE(rc))
360 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF program header header from '%s': %Rrc\n", pszInput, rc);
361
362 /* Look for the first DT_RUNPATH entry and rewrite it. */
363 for (uint32_t i = 0; i < Phdr.p_filesz / sizeof(Elf64_Dyn); i++)
364 {
365 if ( paDynSh[i].d_tag == DT_RPATH
366 || paDynSh[i].d_tag == DT_RUNPATH)
367 {
368 RTEXITCODE rcExit = changeRunpathEntry(hFileElf, pszInput, &Hdr, paDynSh[i].d_un.d_val, pszRunpath);
369 RTMemFree(paDynSh);
370 RTFileClose(hFileElf);
371 return rcExit;
372 }
373 }
374
375 RTMemFree(paDynSh);
376 RTFileClose(hFileElf);
377 return RTMsgErrorExit(RTEXITCODE_FAILURE, "No DT_RPATH or DT_RUNPATH entry found in '%s'\n", pszInput);
378}
379
380
381static RTEXITCODE createLinkerStubFrom(const char *pszInput, const char *pszStubPath)
382{
383 RTFILE hFileElf = NIL_RTFILE;
384 int rc = RTFileOpen(&hFileElf, pszInput, RTFILE_O_OPEN | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE);
385 if (RT_FAILURE(rc))
386 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Filed to open file '%s': %Rrc\n", pszInput, rc);
387
388 /* Only support for 64-bit ELF files currently. */
389 Elf64_Ehdr Hdr;
390 rc = RTFileReadAt(hFileElf, 0, &Hdr, sizeof(Hdr), NULL);
391 if (RT_FAILURE(rc))
392 {
393 RTFileClose(hFileElf);
394 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read ELF header from '%s': %Rrc\n", pszInput, rc);
395 }
396
397 if ( Hdr.e_ident[EI_MAG0] != ELFMAG0
398 || Hdr.e_ident[EI_MAG1] != ELFMAG1
399 || Hdr.e_ident[EI_MAG2] != ELFMAG2
400 || Hdr.e_ident[EI_MAG3] != ELFMAG3)
401 return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Invalid ELF magic (%.*Rhxs)", pszInput, sizeof(Hdr.e_ident), Hdr.e_ident);
402 if (Hdr.e_ident[EI_CLASS] != ELFCLASS64)
403 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid ELF class (%.*Rhxs)", sizeof(Hdr.e_ident), Hdr.e_ident);
404 if (Hdr.e_ident[EI_DATA] != ELFDATA2LSB)
405 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF endian %x is unsupported", Hdr.e_ident[EI_DATA]);
406 if (Hdr.e_version != EV_CURRENT)
407 return RTMsgErrorExit(RTEXITCODE_FAILURE, "ELF version %x is unsupported", Hdr.e_version);
408
409 if (sizeof(Elf64_Ehdr) != Hdr.e_ehsize)
410 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_ehsize is %d expected %d!", Hdr.e_ehsize, sizeof(Elf64_Ehdr));
411 if ( sizeof(Elf64_Phdr) != Hdr.e_phentsize
412 && ( Hdr.e_phnum != 0
413 || Hdr.e_type == ET_DYN
414 || Hdr.e_type == ET_EXEC))
415 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_phentsize is %d expected %d!", Hdr.e_phentsize, sizeof(Elf64_Phdr));
416 if (sizeof(Elf64_Shdr) != Hdr.e_shentsize)
417 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Elf header e_shentsize is %d expected %d!", Hdr.e_shentsize, sizeof(Elf64_Shdr));
418
419 /* Find all the dynamic sections we need. */
420 uint32_t idStrTab = UINT32_MAX;
421 uint32_t idDynamic = UINT32_MAX;
422 Elf64_Shdr ShdrDyn; RT_ZERO(ShdrDyn);
423 char *pachStrTab = NULL; size_t cbStrTab = 0;
424 Elf64_Sym *paDynSyms = NULL; size_t cbDynSyms = 0; uint32_t u32DynSymInfo = 0;
425 uint16_t *pu16GnuVerSym = NULL; size_t cbGnuVerSym = 0;
426 uint8_t *pbGnuVerDef = NULL; size_t cbGnuVerDef = 0; uint32_t cVerdefEntries = 0;
427 uint8_t *pbGnuVerNeed = NULL; size_t cbGnuVerNeed = 0; uint32_t cVerNeedEntries = 0;
428
429 for (uint32_t i = 0; i < Hdr.e_shnum; i++)
430 {
431 Elf64_Shdr Shdr; RT_ZERO(Shdr);
432 rc = RTFileReadAt(hFileElf, Hdr.e_shoff + i * sizeof(Shdr), &Shdr, sizeof(Shdr), NULL /*pcbRead*/);
433 if (RT_FAILURE(rc))
434 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read section header at %RX64 from '%s'\n", Hdr.e_shoff + i * sizeof(Shdr), pszInput);
435
436 verbose("Section header %u:\n"
437 " sh_name: %RU32\n"
438 " sh_type: %RX32\n"
439 " sh_flags: %#RX64\n"
440 " sh_addr: %#RX64\n"
441 " sh_offset: %RU64\n"
442 " sh_size: %RU64\n"
443 " sh_link: %RU16\n"
444 " sh_info: %RU16\n"
445 " sh_addralign: %#RX64\n"
446 " sh_entsize: %#RX64\n", i,
447 Shdr.sh_name, Shdr.sh_type, Shdr.sh_flags,
448 Shdr.sh_addr, Shdr.sh_offset, Shdr.sh_size,
449 Shdr.sh_link, Shdr.sh_info, Shdr.sh_addralign,
450 Shdr.sh_entsize);
451
452 switch (Shdr.sh_type)
453 {
454 case SHT_DYNSYM:
455 {
456 cbDynSyms = Shdr.sh_size;
457 u32DynSymInfo = Shdr.sh_info;
458 paDynSyms = (Elf64_Sym *)RTMemAllocZ(cbDynSyms);
459 if (!paDynSyms)
460 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes for .dynsym section in '%s'\n", cbDynSyms, pszInput);
461
462 rc = RTFileReadAt(hFileElf, Shdr.sh_offset, paDynSyms, cbDynSyms, NULL /*pcbRead*/);
463 if (RT_FAILURE(rc))
464 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .dynsym section at %RX64 from '%s'\n", Shdr.sh_offset, pszInput);
465
466 /* It should link to the string table. */
467 if (idStrTab == UINT32_MAX)
468 idStrTab = Shdr.sh_link;
469 else if (idStrTab != Shdr.sh_link)
470 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String table index %u doesn't match %u in '%s'\n", Shdr.sh_link, idStrTab, pszInput);
471 break;
472 }
473 case SHT_GNU_versym:
474 {
475 cbGnuVerSym = Shdr.sh_size;
476 pu16GnuVerSym = (uint16_t *)RTMemAllocZ(cbGnuVerSym);
477 if (!pu16GnuVerSym)
478 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes for .gnu.version section in '%s'\n", cbGnuVerSym, pszInput);
479
480 rc = RTFileReadAt(hFileElf, Shdr.sh_offset, pu16GnuVerSym, cbGnuVerSym, NULL /*pcbRead*/);
481 if (RT_FAILURE(rc))
482 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .dynsym section at %RX64 from '%s'\n", Shdr.sh_offset, pszInput);
483
484 /** @todo It should link to the .dynsym table. */
485 break;
486 }
487 case SHT_GNU_verdef:
488 {
489 cbGnuVerDef = Shdr.sh_size;
490 pbGnuVerDef = (uint8_t *)RTMemAllocZ(cbGnuVerDef);
491 cVerdefEntries = Shdr.sh_info;
492 if (!pbGnuVerDef)
493 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes for .gnu.version_d section in '%s'\n", cbGnuVerDef, pszInput);
494
495 rc = RTFileReadAt(hFileElf, Shdr.sh_offset, pbGnuVerDef, cbGnuVerDef, NULL /*pcbRead*/);
496 if (RT_FAILURE(rc))
497 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .dynsym section at %RX64 from '%s'\n", Shdr.sh_offset, pszInput);
498
499 /* It should link to the string table. */
500 if (idStrTab == UINT32_MAX)
501 idStrTab = Shdr.sh_link;
502 else if (idStrTab != Shdr.sh_link)
503 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String table index %u doesn't match %u in '%s'\n", Shdr.sh_link, idStrTab, pszInput);
504 break;
505 }
506 case SHT_GNU_verneed:
507 {
508 cbGnuVerNeed = Shdr.sh_size;
509 pbGnuVerNeed = (uint8_t *)RTMemAllocZ(cbGnuVerNeed);
510 cVerNeedEntries = Shdr.sh_info;
511 if (!pbGnuVerNeed)
512 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes for .gnu.version_r section in '%s'\n", cbGnuVerNeed, pszInput);
513
514 rc = RTFileReadAt(hFileElf, Shdr.sh_offset, pbGnuVerNeed, cbGnuVerNeed, NULL /*pcbRead*/);
515 if (RT_FAILURE(rc))
516 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .gnu.version_r section at %RX64 from '%s'\n", Shdr.sh_offset, pszInput);
517
518 /* It should link to the string table. */
519 if (idStrTab == UINT32_MAX)
520 idStrTab = Shdr.sh_link;
521 else if (idStrTab != Shdr.sh_link)
522 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String table index %u doesn't match %u in '%s'\n", Shdr.sh_link, idStrTab, pszInput);
523 break;
524 }
525 case SHT_DYNAMIC:
526 {
527 if (idDynamic != UINT32_MAX)
528 return RTMsgErrorExit(RTEXITCODE_FAILURE, "More than one .dynamic section in '%s'\n", pszInput);
529
530 idDynamic = i;
531 ShdrDyn = Shdr;
532 /* It should link to the string table. */
533 if (idStrTab == UINT32_MAX)
534 idStrTab = Shdr.sh_link;
535 else if (idStrTab != Shdr.sh_link)
536 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String table index %u doesn't match %u in '%s'\n", Shdr.sh_link, idStrTab, pszInput);
537 }
538 default:
539 break; /* Ignored. */
540 }
541 }
542
543 if (idStrTab == UINT32_MAX)
544 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String table index not found in '%s'\n", pszInput);
545 if (idDynamic == UINT32_MAX)
546 return RTMsgErrorExit(RTEXITCODE_FAILURE, ".dynamic section index not found in '%s'\n", pszInput);
547
548 if (pbGnuVerDef && !pu16GnuVerSym)
549 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Versioned library '%s' misses .gnu.version\n", pszInput);
550
551 /* Read the string table section header. */
552 Elf64_Shdr Shdr; RT_ZERO(Shdr);
553 rc = RTFileReadAt(hFileElf, Hdr.e_shoff + idStrTab * sizeof(Shdr), &Shdr, sizeof(Shdr), NULL /*pcbRead*/);
554 if (RT_FAILURE(rc))
555 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .strtab section header at %RX64 from '%s': %Rrc\n",
556 Hdr.e_shoff + idStrTab * sizeof(Shdr), pszInput, rc);
557
558 cbStrTab = Shdr.sh_size;
559 pachStrTab = (char *)RTMemAllocZ(cbStrTab + 1); /* Force termination */
560 if (!pachStrTab)
561 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes for .strtab section in '%s'\n", cbStrTab, pszInput);
562
563 rc = RTFileReadAt(hFileElf, Shdr.sh_offset, pachStrTab, cbStrTab, NULL /*pcbRead*/);
564 if (RT_FAILURE(rc))
565 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .strtab section at %RX64 from '%s'\n", Shdr.sh_offset, pszInput);
566
567 /* Read the .dynamic section. */
568 Elf64_Dyn *paDynEnt = (Elf64_Dyn *)RTMemAllocZ(ShdrDyn.sh_size);
569 if (!paDynEnt)
570 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate %zu bytes for .dynamic section in '%s'\n", ShdrDyn.sh_size, pszInput);
571
572 rc = RTFileReadAt(hFileElf, ShdrDyn.sh_offset, paDynEnt, ShdrDyn.sh_size, NULL /*pcbRead*/);
573 if (RT_FAILURE(rc))
574 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to read .dynamic section at %RX64 from '%s'\n", ShdrDyn.sh_offset, pszInput);
575
576 RTFileClose(hFileElf);
577
578 verbose("Processing symbol table\n");
579
580 /* Remove all undefined entries from .dynsym and rewrite all exposed symbols to point to the first section header in the stub. */
581 uint32_t cDynSymsExport = 0;
582 uint32_t idxFirstNonLocalSym = 0;
583 for (uint32_t i = 0; i < cbDynSyms / sizeof(*paDynSyms); i++)
584 {
585 if (1 /*paDynSyms[i].st_shndx*/)
586 {
587 paDynSyms[cDynSymsExport] = paDynSyms[i];
588 paDynSyms[cDynSymsExport].st_shndx = paDynSyms[cDynSymsExport].st_shndx ? 1 : 0;
589 paDynSyms[cDynSymsExport].st_value = 0;
590 if (pu16GnuVerSym)
591 pu16GnuVerSym[cDynSymsExport] = pu16GnuVerSym[i];
592
593 if (ELF64_ST_BIND(paDynSyms[cDynSymsExport].st_info) != STB_LOCAL)
594 idxFirstNonLocalSym = cDynSymsExport;
595
596 cDynSymsExport++;
597 }
598 else
599 verbose("Nuked symbol entry %u\n", i);
600 }
601
602#if 0
603 /* Figure out the number of .gnu.version entries. */
604 if (pbGnuVerDef)
605 {
606 cVerdefEntries = 1;
607 Elf64_Verdef *pVerDef = (Elf64_Verdef *)pbGnuVerDef;
608 for (;;)
609 {
610 if (!pVerDef->vd_next)
611 break;
612
613 cVerdefEntries++;
614 pVerDef = (Elf64_Verdef *)((uint8_t *)pVerDef + pVerDef->vd_next);
615 if ((uintptr_t)pVerDef >= (uintptr_t)pbGnuVerDef + cbGnuVerDef)
616 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Version definition next entry points outside .gnu.version section '%s': %Rrc\n", pszInput);
617 }
618 }
619#endif
620
621 /* Start writing the output ELF file. */
622
623 verbose("Writing stub binary\n");
624
625 RTFILE hFileOut = NIL_RTFILE;
626 rc = RTFileOpen(&hFileOut, pszStubPath, RTFILE_O_CREATE_REPLACE | RTFILE_O_READWRITE | RTFILE_O_DENY_NONE);
627 if (RT_FAILURE(rc))
628 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create file '%s': %Rrc\n", pszStubPath, rc);
629
630 /* Program headers. */
631 Elf64_Phdr aPhdrs[4];
632
633 /* Rewrite the header. */
634 Hdr.e_phoff = sizeof(Hdr);
635 Hdr.e_shoff = Hdr.e_phoff + sizeof(aPhdrs);
636 Hdr.e_phnum = RT_ELEMENTS(aPhdrs);
637 Hdr.e_shnum = pbGnuVerDef ? 8 : 6; /* NULL + .dynsym + .dynstr + (.gnu.version + gnu.version_d + gnu.version_r) + .dynamic + .shstrtab */
638 Hdr.e_shstrndx = pbGnuVerDef ? 7 : 5;
639
640 Elf64_Shdr aShdrs[8]; RT_ZERO(aShdrs);
641 uint32_t idx = 1;
642 /* NULL header */
643 /* .dynsym */
644 aShdrs[idx].sh_name = 11;
645 aShdrs[idx].sh_type = SHT_DYNSYM;
646 aShdrs[idx].sh_flags = SHF_ALLOC;
647 aShdrs[idx].sh_addr = 0;
648 aShdrs[idx].sh_offset = Hdr.e_shoff + Hdr.e_shnum * sizeof(aShdrs[0]);
649 aShdrs[idx].sh_size = cDynSymsExport * sizeof(*paDynSyms);
650 aShdrs[idx].sh_link = 2;
651 aShdrs[idx].sh_info = u32DynSymInfo;
652 aShdrs[idx].sh_addralign = sizeof(uint64_t);
653 aShdrs[idx].sh_entsize = sizeof(*paDynSyms);
654 uint32_t const idxDynSym = idx++;
655
656 /* .dynstr */
657 aShdrs[idx].sh_name = 19;
658 aShdrs[idx].sh_type = SHT_STRTAB;
659 aShdrs[idx].sh_flags = SHF_ALLOC;
660 aShdrs[idx].sh_addr = 0;
661 aShdrs[idx].sh_offset = aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size;
662 aShdrs[idx].sh_size = cbStrTab;
663 aShdrs[idx].sh_link = 0;
664 aShdrs[idx].sh_info = 0;
665 aShdrs[idx].sh_addralign = sizeof(uint8_t);
666 aShdrs[idx].sh_entsize = 0;
667 uint32_t const idxDynStr = idx++;
668
669 uint32_t idxGnuVerSym = 0;
670 uint32_t idxGnuVerDef = 0;
671 uint32_t idxGnuVerNeed = 0;
672 if (pbGnuVerDef || pbGnuVerNeed)
673 {
674 /* .gnu.version */
675 aShdrs[idx].sh_name = 27;
676 aShdrs[idx].sh_type = SHT_GNU_versym;
677 aShdrs[idx].sh_flags = SHF_ALLOC;
678 aShdrs[idx].sh_addr = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint16_t));
679 aShdrs[idx].sh_offset = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint16_t));
680 aShdrs[idx].sh_size = cDynSymsExport * sizeof(uint16_t);
681 aShdrs[idx].sh_link = 1; /* .dynsym */
682 aShdrs[idx].sh_info = 0;
683 aShdrs[idx].sh_addralign = sizeof(uint16_t);
684 aShdrs[idx].sh_entsize = 2;
685 idxGnuVerSym = idx++;
686
687 if (pbGnuVerDef)
688 {
689 /* .gnu.version_d */
690 aShdrs[idx].sh_name = 40;
691 aShdrs[idx].sh_type = SHT_GNU_verdef;
692 aShdrs[idx].sh_flags = SHF_ALLOC;
693 aShdrs[idx].sh_addr = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint64_t));
694 aShdrs[idx].sh_offset = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint64_t));
695 aShdrs[idx].sh_size = cbGnuVerDef;
696 aShdrs[idx].sh_link = 2; /* .dynstr */
697 aShdrs[idx].sh_info = cVerdefEntries;
698 aShdrs[idx].sh_addralign = sizeof(uint64_t);
699 aShdrs[idx].sh_entsize = 0;
700 idxGnuVerDef = idx++;
701 }
702
703 if (pbGnuVerNeed)
704 {
705 /* .gnu.version_r */
706 aShdrs[idx].sh_name = 55;
707 aShdrs[idx].sh_type = SHT_GNU_verneed;
708 aShdrs[idx].sh_flags = SHF_ALLOC;
709 aShdrs[idx].sh_addr = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint64_t));
710 aShdrs[idx].sh_offset = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint64_t));
711 aShdrs[idx].sh_size = cbGnuVerNeed;
712 aShdrs[idx].sh_link = 2; /* .dynstr */
713 aShdrs[idx].sh_info = cVerNeedEntries;
714 aShdrs[idx].sh_addralign = sizeof(uint64_t);
715 aShdrs[idx].sh_entsize = 0;
716 idxGnuVerNeed = idx++;
717 }
718 }
719
720 /* Process the .dynamic section. */
721 uint32_t cDynEntries = 0;
722 for (uint32_t i = 0; i < ShdrDyn.sh_size / sizeof(*paDynEnt); i++)
723 {
724 switch (paDynEnt[i].d_tag)
725 {
726 case DT_RUNPATH:
727 case DT_RPATH:
728 case DT_SONAME:
729 case DT_NEEDED:
730 case DT_FLAGS:
731 case DT_FLAGS_1:
732 case DT_STRSZ:
733 case DT_SYMENT:
734 case DT_VERDEFNUM:
735 case DT_VERNEEDNUM:
736 paDynEnt[cDynEntries++] = paDynEnt[i];
737 break;
738 case DT_VERDEF:
739 paDynEnt[cDynEntries] = paDynEnt[i];
740 paDynEnt[cDynEntries++].d_un.d_val = aShdrs[idxGnuVerDef].sh_offset;
741 break;
742 case DT_VERNEED:
743 paDynEnt[cDynEntries] = paDynEnt[i];
744 paDynEnt[cDynEntries++].d_un.d_val = aShdrs[idxGnuVerNeed].sh_offset;
745 break;
746 case DT_VERSYM:
747 paDynEnt[cDynEntries] = paDynEnt[i];
748 paDynEnt[cDynEntries++].d_un.d_val = aShdrs[idxGnuVerSym].sh_offset;
749 break;
750 case DT_STRTAB:
751 paDynEnt[cDynEntries] = paDynEnt[i];
752 paDynEnt[cDynEntries++].d_un.d_val = aShdrs[idxDynStr].sh_offset;
753 break;
754 case DT_SYMTAB:
755 paDynEnt[cDynEntries] = paDynEnt[i];
756 paDynEnt[cDynEntries++].d_un.d_val = aShdrs[idxDynSym].sh_offset;
757 break;
758 }
759 }
760 /* Close with 0. */
761 paDynEnt[cDynEntries].d_tag = DT_NULL;
762 paDynEnt[cDynEntries++].d_un.d_val = 0;
763
764 /* .dynamic */
765 aShdrs[idx].sh_name = 70;
766 aShdrs[idx].sh_type = SHT_DYNAMIC;
767 aShdrs[idx].sh_flags = SHF_ALLOC | SHF_WRITE;
768 aShdrs[idx].sh_addr = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint64_t));
769 aShdrs[idx].sh_offset = RT_ALIGN_64(aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size, sizeof(uint64_t));
770 aShdrs[idx].sh_size = cDynEntries * sizeof(Elf64_Dyn);
771 aShdrs[idx].sh_link = 2; /* .dynstr */
772 aShdrs[idx].sh_info = 0;
773 aShdrs[idx].sh_addralign = sizeof(uint64_t);
774 aShdrs[idx].sh_entsize = sizeof(Elf64_Dyn);
775
776 /* Build the program headers. */
777 aPhdrs[0].p_type = PT_PHDR;
778 aPhdrs[0].p_flags = PF_R;
779 aPhdrs[0].p_offset = Hdr.e_phoff;
780 aPhdrs[0].p_vaddr = Hdr.e_phoff;
781 aPhdrs[0].p_paddr = Hdr.e_phoff;
782 aPhdrs[0].p_filesz = sizeof(aPhdrs);
783 aPhdrs[0].p_memsz = sizeof(aPhdrs);
784 aPhdrs[0].p_align = sizeof(uint64_t);
785
786 aPhdrs[1].p_type = PT_LOAD;
787 aPhdrs[1].p_flags = PF_R | PF_X;
788 aPhdrs[1].p_offset = 0;
789 aPhdrs[1].p_vaddr = 0;
790 aPhdrs[1].p_paddr = 0;
791 aPhdrs[1].p_filesz = aShdrs[idx].sh_offset;
792 aPhdrs[1].p_memsz = aShdrs[idx].sh_offset;
793 aPhdrs[1].p_align = 0x10000;
794
795 aPhdrs[2].p_type = PT_LOAD;
796 aPhdrs[2].p_flags = PF_R | PF_W;
797 aPhdrs[2].p_offset = aShdrs[idx].sh_offset;
798 aPhdrs[2].p_vaddr = aShdrs[idx].sh_offset;
799 aPhdrs[2].p_paddr = aShdrs[idx].sh_offset;
800 aPhdrs[2].p_filesz = aShdrs[idx].sh_size;
801 aPhdrs[2].p_memsz = aShdrs[idx].sh_size;
802 aPhdrs[2].p_align = 0x10000;
803
804 aPhdrs[3].p_type = PT_DYNAMIC;
805 aPhdrs[3].p_flags = PF_R | PF_W;
806 aPhdrs[3].p_offset = aShdrs[idx].sh_offset;
807 aPhdrs[3].p_vaddr = aShdrs[idx].sh_offset;
808 aPhdrs[3].p_paddr = aShdrs[idx].sh_offset;
809 aPhdrs[3].p_filesz = aShdrs[idx].sh_size;
810 aPhdrs[3].p_memsz = aShdrs[idx].sh_size;
811 aPhdrs[3].p_align = sizeof(uint64_t);
812
813 idx++;
814
815 /* .shstrtab */
816 aShdrs[idx].sh_name = 1;
817 aShdrs[idx].sh_type = SHT_STRTAB;
818 aShdrs[idx].sh_flags = SHF_ALLOC;
819 aShdrs[idx].sh_addr = 0;
820 aShdrs[idx].sh_offset = aShdrs[idx - 1].sh_offset + aShdrs[idx - 1].sh_size;
821 aShdrs[idx].sh_size = sizeof(s_achShStrTab);
822 aShdrs[idx].sh_link = 0;
823 aShdrs[idx].sh_info = 0;
824 aShdrs[idx].sh_addralign = sizeof(uint8_t);
825 aShdrs[idx].sh_entsize = 0;
826 idx++;
827
828 rc = RTFileWriteAt(hFileOut, 0, &Hdr, sizeof(Hdr), NULL /*pcbWritten*/);
829 if (RT_FAILURE(rc))
830 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write ELF header to '%s': %Rrc\n", pszStubPath, rc);
831
832 rc = RTFileWriteAt(hFileOut, Hdr.e_phoff, &aPhdrs[0], sizeof(aPhdrs), NULL /*pcbWritten*/);
833 if (RT_FAILURE(rc))
834 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write section headers to '%s': %Rrc\n", pszStubPath, rc);
835
836 rc = RTFileWriteAt(hFileOut, Hdr.e_shoff, &aShdrs[0], idx * sizeof(aShdrs[0]), NULL /*pcbWritten*/);
837 if (RT_FAILURE(rc))
838 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write section headers to '%s': %Rrc\n", pszStubPath, rc);
839
840 idx = 1;
841 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, paDynSyms, cDynSymsExport * sizeof(*paDynSyms), NULL /*pcbWritten*/);
842 if (RT_FAILURE(rc))
843 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .dynsym section to '%s': %Rrc\n", pszStubPath, rc);
844
845 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, pachStrTab, cbStrTab, NULL /*pcbWritten*/);
846 if (RT_FAILURE(rc))
847 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .dynstr section to '%s': %Rrc\n", pszStubPath, rc);
848
849 if (pbGnuVerDef || pbGnuVerNeed)
850 {
851 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, pu16GnuVerSym, cDynSymsExport * sizeof(uint16_t), NULL /*pcbWritten*/);
852 if (RT_FAILURE(rc))
853 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .gnu.version section to '%s': %Rrc\n", pszStubPath, rc);
854
855 if (pbGnuVerDef)
856 {
857 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, pbGnuVerDef, cbGnuVerDef, NULL /*pcbWritten*/);
858 if (RT_FAILURE(rc))
859 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .gnu.version section to '%s': %Rrc\n", pszStubPath, rc);
860 }
861
862 if (pbGnuVerNeed)
863 {
864 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, pbGnuVerNeed, cbGnuVerNeed, NULL /*pcbWritten*/);
865 if (RT_FAILURE(rc))
866 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .gnu.version section to '%s': %Rrc\n", pszStubPath, rc);
867 }
868 }
869
870 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, paDynEnt, cDynEntries * sizeof(Elf64_Dyn), NULL /*pcbWritten*/);
871 if (RT_FAILURE(rc))
872 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .dynamic section to '%s': %Rrc\n", pszStubPath, rc);
873
874 rc = RTFileWriteAt(hFileOut, aShdrs[idx++].sh_offset, s_achShStrTab, sizeof(s_achShStrTab), NULL /*pcbWritten*/);
875 if (RT_FAILURE(rc))
876 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to write .gnu.version section to '%s': %Rrc\n", pszStubPath, rc);
877
878 RTFileClose(hFileOut);
879 return RTEXITCODE_SUCCESS;
880}
881
882
883/**
884 * Display usage
885 *
886 * @returns success if stdout, syntax error if stderr.
887 */
888static RTEXITCODE usage(FILE *pOut, const char *argv0)
889{
890 fprintf(pOut,
891 "usage: %s --input <input binary> [options and operations]\n"
892 "\n"
893 "Operations and Options (processed in place):\n"
894 " --verbose Noisier.\n"
895 " --quiet Quiet execution.\n"
896 " --delete-runpath Deletes all DT_RUNPATH entries.\n"
897 " --change-runpath <new runpath> Changes the first DT_RUNPATH entry to the new one.\n"
898 " --create-stub-library <path/to/stub> Creates a stub library used for linking.\n"
899 , argv0);
900 return pOut == stdout ? RTEXITCODE_SUCCESS : RTEXITCODE_SYNTAX;
901}
902
903
904/**
905 * Parses the arguments.
906 */
907static RTEXITCODE parseArguments(int argc, char **argv)
908{
909 /*
910 * Option config.
911 */
912 static RTGETOPTDEF const s_aOpts[] =
913 {
914 { "--input", 'i', RTGETOPT_REQ_STRING },
915 { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
916 { "--delete-runpath", 'd', RTGETOPT_REQ_NOTHING },
917 { "--change-runpath", 'c', RTGETOPT_REQ_STRING },
918 { "--create-stub-library", 's', RTGETOPT_REQ_STRING },
919 };
920
921 RTGETOPTUNION ValueUnion;
922 RTGETOPTSTATE GetOptState;
923 int rc = RTGetOptInit(&GetOptState, argc, argv, &s_aOpts[0], RT_ELEMENTS(s_aOpts), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
924 AssertReleaseRCReturn(rc, RTEXITCODE_FAILURE);
925
926 /*
927 * Process the options.
928 */
929 while ((rc = RTGetOpt(&GetOptState, &ValueUnion)) != 0)
930 {
931 switch (rc)
932 {
933 case 'h':
934 return usage(stdout, argv[0]);
935
936 case 'i':
937 if (g_pszInput)
938 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Input file is already set to '%s'", g_pszInput);
939 g_pszInput = ValueUnion.psz;
940 break;
941
942 case 'v':
943 g_cVerbosity++;
944 break;
945
946 case 'd':
947 g_enmAction = kVBoxEditElfAction_DeleteRunpath;
948 break;
949
950 case 'c':
951 g_enmAction = kVBoxEditElfAction_ChangeRunpath;
952 g_pszRunpath = ValueUnion.psz;
953 break;
954
955 case 's':
956 g_enmAction = kVBoxEditElfAction_CreateLinkerStub;
957 g_pszLinkerStub = ValueUnion.psz;
958 break;
959
960 case 'V':
961 {
962 /* The following is assuming that svn does it's job here. */
963 static const char s_szRev[] = "$Revision: 108518 $";
964 const char *psz = RTStrStripL(strchr(s_szRev, ' '));
965 RTPrintf("r%.*s\n", strchr(psz, ' ') - psz, psz);
966 return RTEXITCODE_SUCCESS;
967 }
968
969 /*
970 * Errors and bugs.
971 */
972 default:
973 return RTGetOptPrintError(rc, &ValueUnion);
974 }
975 }
976
977 /*
978 * Check that we've got all we need.
979 */
980 if (g_enmAction == kVBoxEditElfAction_Nothing)
981 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No action specified (--delete-runpath, --change-runpath or --create-stub-library)");
982 if (!g_pszInput)
983 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No input file specified (--input)");
984
985 return RTEXITCODE_SUCCESS;
986}
987
988
989int main(int argc, char **argv)
990{
991 int rc = RTR3InitExe(argc, &argv, 0);
992 if (RT_FAILURE(rc))
993 return 1;
994
995 RTEXITCODE rcExit = parseArguments(argc, argv);
996 if (rcExit == RTEXITCODE_SUCCESS)
997 {
998 /*
999 * Take action.
1000 */
1001 if (g_enmAction == kVBoxEditElfAction_DeleteRunpath)
1002 rcExit = deleteRunpath(g_pszInput);
1003 else if (g_enmAction == kVBoxEditElfAction_ChangeRunpath)
1004 rcExit = changeRunpath(g_pszInput, g_pszRunpath);
1005 else if (g_enmAction == kVBoxEditElfAction_CreateLinkerStub)
1006 rcExit = createLinkerStubFrom(g_pszInput, g_pszLinkerStub);
1007 }
1008
1009 return rcExit;
1010}
1011
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette