2 * Copyright (c) 1997 Christopher G. Demetriou. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Christopher G. Demetriou
15 * for the NetBSD Project.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/types.h>
36 #include <sys/endian.h>
49 #if (defined(NLIST_ELF32) && (ELFSIZE == 32)) || \
50 (defined(NLIST_ELF64) && (ELFSIZE == 64))
52 #define __ELF_WORD_SIZE ELFSIZE
54 #include <sys/elf32.h>
55 #define xewtoh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
56 #define htoxew(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
57 #define wewtoh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
58 #define htowew(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
60 #include <sys/elf64.h>
61 #define xewtoh(x) ((data == ELFDATA2MSB) ? be64toh(x) : le64toh(x))
62 #define htoxew(x) ((data == ELFDATA2MSB) ? htobe64(x) : htole64(x))
63 /* elf64 Elf64_Word are 32 bits */
64 #define wewtoh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
65 #define htowew(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
67 #include <sys/elf_generic.h>
69 #define CONCAT(x,y) __CONCAT(x,y)
70 #define ELFNAME(x) CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
71 #define ELFNAME2(x,y) CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
72 #define ELFNAMEEND(x) CONCAT(x,CONCAT(_elf,ELFSIZE))
73 #define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
75 #define xe16toh(x) ((data == ELFDATA2MSB) ? be16toh(x) : le16toh(x))
76 #define xe32toh(x) ((data == ELFDATA2MSB) ? be32toh(x) : le32toh(x))
77 #define htoxe32(x) ((data == ELFDATA2MSB) ? htobe32(x) : htole32(x))
85 xreadatoff(int fd
, void *buf
, off_t off
, size_t size
, const char *fn
)
89 if (lseek(fd
, off
, SEEK_SET
) != off
) {
93 if ((size_t)(rv
= read(fd
, buf
, size
)) != size
) {
94 fprintf(stderr
, "%s: read error: %s\n", fn
,
95 rv
== -1 ? strerror(errno
) : "short read");
102 xwriteatoff(int fd
, void *buf
, off_t off
, size_t size
, const char *fn
)
106 if (lseek(fd
, off
, SEEK_SET
) != off
) {
110 if ((size_t)(rv
= write(fd
, buf
, size
)) != size
) {
111 fprintf(stderr
, "%s: write error: %s\n", fn
,
112 rv
== -1 ? strerror(errno
) : "short write");
119 xmalloc(size_t size
, const char *fn
, const char *use
)
125 fprintf(stderr
, "%s: out of memory (allocating for %s)\n",
131 xrealloc(void *ptr
, size_t size
, const char *fn
, const char *use
)
135 rv
= realloc(ptr
, size
);
138 fprintf(stderr
, "%s: out of memory (reallocating for %s)\n",
145 ELFNAMEEND(check
)(int fd
, const char *fn
)
152 * Check the header to maek sure it's an ELF file (of the
155 if (fstat(fd
, &sb
) == -1)
157 if (sb
.st_size
< (off_t
)(sizeof eh
))
159 if (read(fd
, &eh
, sizeof eh
) != sizeof eh
)
165 data
= eh
.e_ident
[EI_DATA
];
167 switch (xe16toh(eh
.e_machine
)) {
169 case EM_ALPHA
: break;
171 #define EM_AARCH64 183
173 case EM_AARCH64
: break;
181 #ifndef EM_MIPS_RS4_BE /* same as EM_MIPS_RS3_LE */
182 #define EM_MIPS_RS4_BE 10
185 case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE
: break;
193 case EM_PPC64
: break;
195 #define EM_SPARCV9 43
197 case EM_SPARCV9
: break;
201 case EM_X86_64
: break;
202 /* ELFDEFNNAME(MACHDEP_ID_CASES) */
212 * This function 'hides' (some of) ELF executable file's symbols.
213 * It hides them by renaming them to "_$$hide$$ <filename> <symbolname>".
214 * Symbols in the global keep list, or which are marked as being undefined,
217 * An old version of this code shuffled various tables around, turning
218 * global symbols to be hidden into local symbols. That lost on the
219 * mips, because CALL16 relocs must reference global symbols, and, if
220 * those symbols were being hidden, they were no longer global.
222 * The new renaming behaviour doesn't take global symbols out of the
223 * namespace. However, it's ... unlikely that there will ever be
224 * any collisions in practice because of the new method.
227 ELFNAMEEND(hide
)(int fd
, const char *fn
)
230 struct shlayout
*layoutp
= NULL
;
231 Elf_Shdr
*shdrp
= NULL
, *symtabshdr
, *strtabshdr
, *shstrtabshdr
;
233 Elf_Sym
*symtabp
= NULL
;
234 char *shstrtabp
= NULL
, *strtabp
= NULL
;
238 int rv
, i
, weird
, l
, m
, r
, strtabidx
;
239 size_t nstrtab_size
, nstrtab_nextoff
, fn_size
, size
;
240 char *nstrtabp
= NULL
;
242 const char *weirdreason
= NULL
;
247 if (xreadatoff(fd
, &ehdr
, 0, sizeof ehdr
, fn
) != sizeof ehdr
)
250 data
= ehdr
.e_ident
[EI_DATA
];
251 shnum
= xe16toh(ehdr
.e_shnum
);
253 shdrsize
= shnum
* xe16toh(ehdr
.e_shentsize
);
254 if ((shdrp
= xmalloc(shdrsize
, fn
, "section header table")) == NULL
)
256 if (xreadatoff(fd
, shdrp
, xewtoh(ehdr
.e_shoff
), shdrsize
, fn
) !=
260 symtabshdr
= strtabshdr
= shstrtabshdr
= NULL
;
262 for (i
= 0; i
< shnum
; i
++) {
263 switch (xe32toh(shdrp
[i
].sh_type
)) {
265 if (symtabshdr
!= NULL
) {
267 weirdreason
= "multiple symbol tables";
269 symtabshdr
= &shdrp
[i
];
270 strtabshdr
= &shdrp
[xe32toh(shdrp
[i
].sh_link
)];
273 if (i
== xe16toh(ehdr
.e_shstrndx
))
274 shstrtabshdr
= &shdrp
[i
];
278 if (symtabshdr
== NULL
)
280 if (strtabshdr
== NULL
) {
282 weirdreason
= "string table does not exist";
284 if (shstrtabshdr
== NULL
) {
286 weirdreason
= "section header string table does not exist";
288 if (weirdreason
== NULL
)
289 weirdreason
= "unsupported";
291 fprintf(stderr
, "%s: weird executable (%s)\n", fn
, weirdreason
);
296 * sort section layout table by offset
298 layoutp
= xmalloc((shnum
+ 1) * sizeof(struct shlayout
),
303 /* add a pseudo entry to represent the section header table */
304 shdrshdr
.sh_offset
= ehdr
.e_shoff
;
305 shdrshdr
.sh_size
= htoxew(shdrsize
);
306 shdrshdr
.sh_addralign
= htoxew(ELFSIZE
/ 8);
307 layoutp
[shnum
].shdr
= &shdrshdr
;
309 /* insert and sort normal section headers */
310 for (i
= shnum
; i
-- != 0;) {
315 if (xewtoh(shdrp
[i
].sh_offset
) >
316 xewtoh(layoutp
[m
].shdr
->sh_offset
))
323 memmove(&layoutp
[i
], &layoutp
[i
+ 1],
324 sizeof(struct shlayout
) * (r
- i
));
327 layoutp
[r
].shdr
= &shdrp
[i
];
328 layoutp
[r
].bufp
= NULL
;
333 * load up everything we need
336 /* load section string table for debug use */
337 if ((shstrtabp
= xmalloc(xewtoh(shstrtabshdr
->sh_size
), fn
,
338 "section string table")) == NULL
)
340 if ((size_t)xreadatoff(fd
, shstrtabp
, xewtoh(shstrtabshdr
->sh_offset
),
341 xewtoh(shstrtabshdr
->sh_size
), fn
) != xewtoh(shstrtabshdr
->sh_size
))
344 /* we need symtab, strtab, and everything behind strtab */
346 for (i
= 0; i
< shnum
; i
++) {
347 if (layoutp
[i
].shdr
== &shdrshdr
) {
348 /* not load section header again */
349 layoutp
[i
].bufp
= shdrp
;
352 if (layoutp
[i
].shdr
== shstrtabshdr
) {
353 /* not load section string table again */
354 layoutp
[i
].bufp
= shstrtabp
;
358 if (layoutp
[i
].shdr
== strtabshdr
)
360 if (layoutp
[i
].shdr
== symtabshdr
|| i
>= strtabidx
) {
361 off
= xewtoh(layoutp
[i
].shdr
->sh_offset
);
362 size
= xewtoh(layoutp
[i
].shdr
->sh_size
);
363 layoutp
[i
].bufp
= xmalloc(size
, fn
,
364 shstrtabp
+ xewtoh(layoutp
[i
].shdr
->sh_name
));
365 if (layoutp
[i
].bufp
== NULL
)
367 if ((size_t)xreadatoff(fd
, layoutp
[i
].bufp
, off
, size
, fn
) !=
371 /* set symbol table and string table */
372 if (layoutp
[i
].shdr
== symtabshdr
)
373 symtabp
= layoutp
[i
].bufp
;
374 else if (layoutp
[i
].shdr
== strtabshdr
)
375 strtabp
= layoutp
[i
].bufp
;
380 nstrtabp
= xmalloc(nstrtab_size
, fn
, "new string table");
381 if (nstrtabp
== NULL
)
385 fn_size
= strlen(fn
);
387 /* Prepare data structures for symbol movement. */
388 nsyms
= xewtoh(symtabshdr
->sh_size
) / xewtoh(symtabshdr
->sh_entsize
);
390 /* move symbols, making them local */
391 for (ewi
= 0; ewi
< nsyms
; ewi
++) {
392 Elf_Sym
*sp
= &symtabp
[ewi
];
393 const char *symname
= strtabp
+ xe32toh(sp
->st_name
);
396 * make sure there's size for the next entry, even if it's
397 * as large as it can be.
399 * "_$$hide$$ <filename> <symname><NUL>" ->
400 * 9 + 3 + sizes of fn and sym name
402 while ((nstrtab_size
- nstrtab_nextoff
) <
403 strlen(symname
) + fn_size
+ 12) {
405 nstrtabp
= xrealloc(nstrtabp
, nstrtab_size
, fn
,
407 if (nstrtabp
== NULL
)
411 sp
->st_name
= htowew(nstrtab_nextoff
);
413 /* if it's a keeper or is undefined, don't rename it. */
414 if (in_keep_list(symname
) ||
415 (xe16toh(sp
->st_shndx
) == SHN_UNDEF
)) {
416 newent_len
= sprintf(nstrtabp
+ nstrtab_nextoff
,
419 newent_len
= sprintf(nstrtabp
+ nstrtab_nextoff
,
420 "_$$hide$$ %s %s", fn
, symname
) + 1;
422 nstrtab_nextoff
+= newent_len
;
424 strtabshdr
->sh_size
= htoxew(nstrtab_nextoff
);
427 * update section header table in ascending order of offset
429 for (i
= strtabidx
+ 1; i
< shnum
; i
++) {
431 off
= xewtoh(layoutp
[i
- 1].shdr
->sh_offset
) +
432 xewtoh(layoutp
[i
- 1].shdr
->sh_size
);
433 align
= xewtoh(layoutp
[i
].shdr
->sh_addralign
);
434 off
= (off
+ (align
- 1)) & ~(align
- 1);
435 layoutp
[i
].shdr
->sh_offset
= htoxew(off
);
439 * write data to the file in descending order of offset
441 for (i
= shnum
; i
-- != 0;) {
442 if (layoutp
[i
].shdr
== strtabshdr
) {
443 /* new string table */
446 buf
= layoutp
[i
].bufp
;
448 if (layoutp
[i
].shdr
== &shdrshdr
||
449 layoutp
[i
].shdr
== symtabshdr
|| i
>= strtabidx
) {
454 * update the offset of section header table in elf
457 if (layoutp
[i
].shdr
== &shdrshdr
&&
458 ehdr
.e_shoff
!= shdrshdr
.sh_offset
) {
459 ehdr
.e_shoff
= shdrshdr
.sh_offset
;
460 off
= offsetof(Elf_Ehdr
, e_shoff
);
461 size
= sizeof(Elf_Off
);
462 if ((size_t)xwriteatoff(fd
, &ehdr
.e_shoff
, off
, size
,
467 off
= xewtoh(layoutp
[i
].shdr
->sh_offset
);
468 size
= xewtoh(layoutp
[i
].shdr
->sh_size
);
469 if ((size_t)xwriteatoff(fd
, buf
, off
, size
, fn
) != size
)
475 if (layoutp
!= NULL
) {
476 for (i
= 0; i
< shnum
; i
++) {
477 if (layoutp
[i
].bufp
!= NULL
)
478 free(layoutp
[i
].bufp
);
490 #endif /* include this size of ELF */