2 * Copyright (c) 2000, Boris Popov
3 * Copyright (c) 1998-2000 Doug Rabson
4 * Copyright (c) 2004 Peter Wemm
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/param.h>
38 #include <sys/linker.h>
45 #include <machine/elf.h>
56 int sec
; /* Original section */
76 struct elf_file
*ef_efile
;
91 Elf_Sym
*ddbsymtab
; /* The symbol table we are using */
92 long ddbsymcnt
; /* Number of symbols */
93 caddr_t ddbstrtab
; /* String table */
94 long ddbstrcnt
; /* number of bytes in string table */
96 caddr_t shstrtab
; /* Section name string table */
97 long shstrcnt
; /* number of bytes in string table */
102 static int ef_obj_get_type(elf_file_t ef
);
103 static int ef_obj_close(elf_file_t ef
);
104 static int ef_obj_read(elf_file_t ef
, Elf_Off offset
, size_t len
, void* dest
);
105 static int ef_obj_read_entry(elf_file_t ef
, Elf_Off offset
, size_t len
,
107 static int ef_obj_seg_read(elf_file_t ef
, Elf_Off offset
, size_t len
,
109 static int ef_obj_seg_read_rel(elf_file_t ef
, Elf_Off offset
, size_t len
,
111 static int ef_obj_seg_read_entry(elf_file_t ef
, Elf_Off offset
, size_t len
,
113 static int ef_obj_seg_read_entry_rel(elf_file_t ef
, Elf_Off offset
, size_t len
,
115 static Elf_Addr
ef_obj_symaddr(elf_file_t ef
, Elf_Size symidx
);
116 static int ef_obj_lookup_set(elf_file_t ef
, const char *name
, long *startp
,
117 long *stopp
, long *countp
);
118 static int ef_obj_lookup_symbol(elf_file_t ef
, const char* name
, Elf_Sym
** sym
);
120 static struct elf_file_ops ef_obj_file_ops
= {
127 ef_obj_seg_read_entry
,
128 ef_obj_seg_read_entry_rel
,
135 ef_obj_get_type(elf_file_t __unused ef
)
142 ef_obj_lookup_symbol(elf_file_t ef
, const char* name
, Elf_Sym
** sym
)
148 for (i
= 0, symp
= ef
->ddbsymtab
; i
< ef
->ddbsymcnt
; i
++, symp
++) {
149 strp
= ef
->ddbstrtab
+ symp
->st_name
;
150 if (symp
->st_shndx
!= SHN_UNDEF
&& strcmp(name
, strp
) == 0) {
159 ef_obj_lookup_set(elf_file_t ef
, const char *name
, long *startp
, long *stopp
,
164 for (i
= 0; i
< ef
->nprogtab
; i
++) {
165 if ((strncmp(ef
->progtab
[i
].name
, "set_", 4) == 0) &&
166 strcmp(ef
->progtab
[i
].name
+ 4, name
) == 0) {
167 *startp
= (char *)ef
->progtab
[i
].addr
- ef
->address
;
168 *stopp
= (char *)ef
->progtab
[i
].addr
+
169 ef
->progtab
[i
].size
- ef
->address
;
170 *countp
= (*stopp
- *startp
) / sizeof(void *);
178 ef_obj_symaddr(elf_file_t ef
, Elf_Size symidx
)
182 if (symidx
>= (size_t) ef
->ddbsymcnt
)
184 sym
= ef
->ddbsymtab
+ symidx
;
186 if (sym
->st_shndx
!= SHN_UNDEF
)
187 return (sym
->st_value
- (Elf_Addr
)ef
->address
);
192 ef_obj_read(elf_file_t ef
, Elf_Off offset
, size_t len
, void *dest
)
196 if (offset
!= (Elf_Off
)-1) {
197 if (lseek(ef
->ef_fd
, offset
, SEEK_SET
) == -1)
201 r
= read(ef
->ef_fd
, dest
, len
);
202 if (r
!= -1 && (size_t)r
== len
)
209 ef_obj_read_entry(elf_file_t ef
, Elf_Off offset
, size_t len
, void **ptr
)
216 error
= ef_obj_read(ef
, offset
, len
, *ptr
);
223 ef_obj_seg_read(elf_file_t ef
, Elf_Off offset
, size_t len
, void *dest
)
226 if (offset
+ len
> ef
->size
) {
228 warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)",
229 ef
->ef_name
, (long)offset
, (long)len
);
232 bcopy(ef
->address
+ offset
, dest
, len
);
237 ef_obj_seg_read_rel(elf_file_t ef
, Elf_Off offset
, size_t len
, void *dest
)
242 Elf_Off secbase
, dataoff
;
245 if (offset
+ len
> ef
->size
) {
247 warnx("ef_seg_read_rel(%s): bad offset/len (%lx:%ld)",
248 ef
->ef_name
, (long)offset
, (long)len
);
251 bcopy(ef
->address
+ offset
, dest
, len
);
253 /* Find out which section contains the data. */
254 memaddr
= ef
->address
+ offset
;
256 secbase
= dataoff
= 0;
257 for (i
= 0; i
< ef
->nprogtab
; i
++) {
258 if (ef
->progtab
[i
].addr
== NULL
)
260 if (memaddr
< (char *)ef
->progtab
[i
].addr
|| memaddr
+ len
>
261 (char *)ef
->progtab
[i
].addr
+ ef
->progtab
[i
].size
)
263 sec
= ef
->progtab
[i
].sec
;
264 /* We relocate to address 0. */
265 secbase
= (char *)ef
->progtab
[i
].addr
- ef
->address
;
266 dataoff
= memaddr
- ef
->address
;
273 /* Now do the relocations. */
274 for (i
= 0; i
< ef
->nrel
; i
++) {
275 if (ef
->reltab
[i
].sec
!= sec
)
277 for (r
= ef
->reltab
[i
].rel
;
278 r
< &ef
->reltab
[i
].rel
[ef
->reltab
[i
].nrel
]; r
++) {
279 error
= ef_reloc(ef
->ef_efile
, r
, EF_RELOC_REL
, secbase
,
285 for (i
= 0; i
< ef
->nrela
; i
++) {
286 if (ef
->relatab
[i
].sec
!= sec
)
288 for (a
= ef
->relatab
[i
].rela
;
289 a
< &ef
->relatab
[i
].rela
[ef
->relatab
[i
].nrela
]; a
++) {
290 error
= ef_reloc(ef
->ef_efile
, a
, EF_RELOC_RELA
,
291 secbase
, dataoff
, len
, dest
);
300 ef_obj_seg_read_entry(elf_file_t ef
, Elf_Off offset
, size_t len
, void **ptr
)
307 error
= ef_obj_seg_read(ef
, offset
, len
, *ptr
);
314 ef_obj_seg_read_entry_rel(elf_file_t ef
, Elf_Off offset
, size_t len
,
322 error
= ef_obj_seg_read_rel(ef
, offset
, len
, *ptr
);
329 ef_obj_open(const char *filename
, struct elf_file
*efile
, int verbose
)
337 size_t mapsize
, alignmask
, max_addralign
;
338 int error
, fd
, pb
, ra
, res
, rl
;
339 int i
, j
, nbytes
, nsym
, shstrindex
, symstrindex
, symtabindex
;
341 if (filename
== NULL
)
343 if ((fd
= open(filename
, O_RDONLY
)) == -1)
346 ef
= calloc(1, sizeof(*ef
));
353 efile
->ef_ops
= &ef_obj_file_ops
;
355 ef
->ef_verbose
= verbose
;
357 ef
->ef_name
= strdup(filename
);
358 ef
->ef_efile
= efile
;
359 hdr
= (Elf_Ehdr
*)&ef
->ef_hdr
;
361 res
= read(fd
, hdr
, sizeof(*hdr
));
363 if (res
!= sizeof(*hdr
))
367 if (hdr
->e_ident
[EI_CLASS
] != ELF_TARG_CLASS
||
368 hdr
->e_ident
[EI_DATA
] != ELF_TARG_DATA
||
369 hdr
->e_ident
[EI_VERSION
] != EV_CURRENT
||
370 hdr
->e_version
!= EV_CURRENT
|| hdr
->e_machine
!= ELF_TARG_MACH
||
371 hdr
->e_type
!= ET_REL
)
374 nbytes
= hdr
->e_shnum
* hdr
->e_shentsize
;
375 if (nbytes
== 0 || hdr
->e_shoff
== 0 ||
376 hdr
->e_shentsize
!= sizeof(Elf_Shdr
))
379 if (ef_obj_read_entry(ef
, hdr
->e_shoff
, nbytes
, &vtmp
) != 0) {
380 printf("ef_read_entry failed\n");
383 ef
->e_shdr
= shdr
= vtmp
;
385 /* Scan the section header for information and table sizing. */
389 for (i
= 0; i
< hdr
->e_shnum
; i
++) {
390 switch (shdr
[i
].sh_type
) {
398 symstrindex
= shdr
[i
].sh_link
;
411 if (ef
->nprogtab
== 0) {
412 warnx("%s: file has no contents", filename
);
416 warnx("%s: file has no valid symbol table", filename
);
419 if (symstrindex
< 0 || symstrindex
> hdr
->e_shnum
||
420 shdr
[symstrindex
].sh_type
!= SHT_STRTAB
) {
421 warnx("%s: file has invalid symbol strings", filename
);
425 /* Allocate space for tracking the load chunks */
426 if (ef
->nprogtab
!= 0)
427 ef
->progtab
= calloc(ef
->nprogtab
, sizeof(*ef
->progtab
));
429 ef
->reltab
= calloc(ef
->nrel
, sizeof(*ef
->reltab
));
431 ef
->relatab
= calloc(ef
->nrela
, sizeof(*ef
->relatab
));
432 if ((ef
->nprogtab
!= 0 && ef
->progtab
== NULL
) ||
433 (ef
->nrel
!= 0 && ef
->reltab
== NULL
) ||
434 (ef
->nrela
!= 0 && ef
->relatab
== NULL
)) {
435 printf("malloc failed\n");
440 ef
->ddbsymcnt
= shdr
[symtabindex
].sh_size
/ sizeof(Elf_Sym
);
441 if (ef_obj_read_entry(ef
, shdr
[symtabindex
].sh_offset
,
442 shdr
[symtabindex
].sh_size
, (void**)&ef
->ddbsymtab
) != 0) {
443 printf("ef_read_entry failed\n");
447 ef
->ddbstrcnt
= shdr
[symstrindex
].sh_size
;
448 if (ef_obj_read_entry(ef
, shdr
[symstrindex
].sh_offset
,
449 shdr
[symstrindex
].sh_size
, (void**)&ef
->ddbstrtab
) != 0) {
450 printf("ef_read_entry failed\n");
454 /* Do we have a string table for the section names? */
456 if (hdr
->e_shstrndx
!= 0 &&
457 shdr
[hdr
->e_shstrndx
].sh_type
== SHT_STRTAB
) {
458 shstrindex
= hdr
->e_shstrndx
;
459 ef
->shstrcnt
= shdr
[shstrindex
].sh_size
;
460 if (ef_obj_read_entry(ef
, shdr
[shstrindex
].sh_offset
,
461 shdr
[shstrindex
].sh_size
, (void**)&ef
->shstrtab
) != 0) {
462 printf("ef_read_entry failed\n");
467 /* Size up code/data(progbits) and bss(nobits). */
471 for (i
= 0; i
< hdr
->e_shnum
; i
++) {
472 switch (shdr
[i
].sh_type
) {
475 alignmask
= shdr
[i
].sh_addralign
- 1;
476 if (shdr
[i
].sh_addralign
> max_addralign
)
477 max_addralign
= shdr
[i
].sh_addralign
;
478 mapsize
+= alignmask
;
479 mapsize
&= ~alignmask
;
480 mapsize
+= shdr
[i
].sh_size
;
485 /* We know how much space we need for the text/data/bss/etc. */
487 if (posix_memalign((void **)&ef
->address
, max_addralign
, mapsize
)) {
488 printf("posix_memalign failed\n");
491 mapbase
= ef
->address
;
494 * Now load code/data(progbits), zero bss(nobits), allocate
495 * space for and load relocs
501 for (i
= 0; i
< hdr
->e_shnum
; i
++) {
502 switch (shdr
[i
].sh_type
) {
505 alignmask
= shdr
[i
].sh_addralign
- 1;
506 mapbase
+= alignmask
;
507 mapbase
= (char *)((uintptr_t)mapbase
& ~alignmask
);
508 ef
->progtab
[pb
].addr
= (void *)(uintptr_t)mapbase
;
509 if (shdr
[i
].sh_type
== SHT_PROGBITS
) {
510 ef
->progtab
[pb
].name
= "<<PROGBITS>>";
511 if (ef_obj_read(ef
, shdr
[i
].sh_offset
,
513 ef
->progtab
[pb
].addr
) != 0) {
514 printf("failed to read progbits\n");
518 ef
->progtab
[pb
].name
= "<<NOBITS>>";
519 bzero(ef
->progtab
[pb
].addr
, shdr
[i
].sh_size
);
521 ef
->progtab
[pb
].size
= shdr
[i
].sh_size
;
522 ef
->progtab
[pb
].sec
= i
;
523 if (ef
->shstrtab
&& shdr
[i
].sh_name
!= 0)
524 ef
->progtab
[pb
].name
=
525 ef
->shstrtab
+ shdr
[i
].sh_name
;
527 /* Update all symbol values with the offset. */
528 for (j
= 0; j
< ef
->ddbsymcnt
; j
++) {
529 es
= &ef
->ddbsymtab
[j
];
530 if (es
->st_shndx
!= i
)
532 es
->st_value
+= (Elf_Addr
)ef
->progtab
[pb
].addr
;
534 mapbase
+= shdr
[i
].sh_size
;
538 ef
->reltab
[rl
].nrel
= shdr
[i
].sh_size
/ sizeof(Elf_Rel
);
539 ef
->reltab
[rl
].sec
= shdr
[i
].sh_info
;
540 if (ef_obj_read_entry(ef
, shdr
[i
].sh_offset
,
541 shdr
[i
].sh_size
, (void**)&ef
->reltab
[rl
].rel
) !=
543 printf("ef_read_entry failed\n");
549 ef
->relatab
[ra
].nrela
=
550 shdr
[i
].sh_size
/ sizeof(Elf_Rela
);
551 ef
->relatab
[ra
].sec
= shdr
[i
].sh_info
;
552 if (ef_obj_read_entry(ef
, shdr
[i
].sh_offset
,
553 shdr
[i
].sh_size
, (void**)&ef
->relatab
[ra
].rela
) !=
555 printf("ef_read_entry failed\n");
570 ef_obj_close(elf_file_t ef
)
577 if (ef
->e_shdr
!= NULL
)
581 if (ef
->nprogtab
!= 0)
584 for (i
= 0; i
< ef
->nrel
; i
++)
585 if (ef
->reltab
[i
].rel
!= NULL
)
586 free(ef
->reltab
[i
].rel
);
589 if (ef
->nrela
!= 0) {
590 for (i
= 0; i
< ef
->nrela
; i
++)
591 if (ef
->relatab
[i
].rela
!= NULL
)
592 free(ef
->relatab
[i
].rela
);
595 if (ef
->ddbsymtab
!= NULL
)
597 if (ef
->ddbstrtab
!= NULL
)
599 if (ef
->shstrtab
!= NULL
)
601 ef
->ef_efile
->ef_ops
= NULL
;
602 ef
->ef_efile
->ef_ef
= NULL
;