2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) 2000, Boris Popov
5 * Copyright (c) 1998-2000 Doug Rabson
6 * Copyright (c) 2004 Peter Wemm
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Boris Popov.
20 * 4. Neither the name of the author nor the names of any co-contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/param.h>
53 int sec
; /* Original section */
71 struct elf_file
*ef_efile
;
82 GElf_Sym
*ddbsymtab
; /* The symbol table we are using */
83 size_t ddbsymcnt
; /* Number of symbols */
84 caddr_t ddbstrtab
; /* String table */
85 long ddbstrcnt
; /* number of bytes in string table */
87 caddr_t shstrtab
; /* Section name string table */
88 long shstrcnt
; /* number of bytes in string table */
93 static void ef_obj_close(elf_file_t ef
);
95 static int ef_obj_seg_read_rel(elf_file_t ef
, GElf_Addr address
,
96 size_t len
, void *dest
);
97 static int ef_obj_seg_read_string(elf_file_t ef
, GElf_Addr address
,
98 size_t len
, char *dest
);
100 static GElf_Addr
ef_obj_symaddr(elf_file_t ef
, GElf_Size symidx
);
101 static int ef_obj_lookup_set(elf_file_t ef
, const char *name
,
102 GElf_Addr
*startp
, GElf_Addr
*stopp
, long *countp
);
103 static int ef_obj_lookup_symbol(elf_file_t ef
, const char *name
,
104 GElf_Sym
**sym
, bool see_local
);
106 static struct elf_file_ops ef_obj_file_ops
= {
107 .close
= ef_obj_close
,
108 .seg_read_rel
= ef_obj_seg_read_rel
,
109 .seg_read_string
= ef_obj_seg_read_string
,
110 .symaddr
= ef_obj_symaddr
,
111 .lookup_set
= ef_obj_lookup_set
,
112 .lookup_symbol
= ef_obj_lookup_symbol
,
116 ef_obj_get_offset(elf_file_t ef
, GElf_Addr addr
)
121 for (i
= 0; i
< ef
->nprogtab
; i
++) {
122 pt
= &ef
->progtab
[i
];
123 if (pt
->offset
== (GElf_Off
)-1)
125 if (addr
>= pt
->addr
&& addr
< pt
->addr
+ pt
->size
)
126 return (pt
->offset
+ (addr
- pt
->addr
));
132 ef_obj_lookup_symbol(elf_file_t ef
, const char *name
, GElf_Sym
**sym
,
139 for (i
= 0, symp
= ef
->ddbsymtab
; i
< ef
->ddbsymcnt
; i
++, symp
++) {
140 strp
= ef
->ddbstrtab
+ symp
->st_name
;
141 if (symp
->st_shndx
!= SHN_UNDEF
&& strcmp(name
, strp
) == 0) {
143 GELF_ST_BIND(symp
->st_info
) != STB_LOCAL
) {
153 ef_obj_lookup_set(elf_file_t ef
, const char *name
, GElf_Addr
*startp
,
154 GElf_Addr
*stopp
, long *countp
)
158 for (i
= 0; i
< ef
->nprogtab
; i
++) {
159 if ((strncmp(ef
->progtab
[i
].name
, "set_", 4) == 0) &&
160 strcmp(ef
->progtab
[i
].name
+ 4, name
) == 0) {
161 *startp
= ef
->progtab
[i
].addr
;
162 *stopp
= ef
->progtab
[i
].addr
+ ef
->progtab
[i
].size
;
163 *countp
= (*stopp
- *startp
) /
164 elf_pointer_size(ef
->ef_efile
);
172 ef_obj_symaddr(elf_file_t ef
, GElf_Size symidx
)
176 if (symidx
>= ef
->ddbsymcnt
)
178 sym
= ef
->ddbsymtab
+ symidx
;
180 if (sym
->st_shndx
!= SHN_UNDEF
)
181 return (sym
->st_value
);
186 ef_obj_seg_read_rel(elf_file_t ef
, GElf_Addr address
, size_t len
, void *dest
)
191 GElf_Addr secbase
, dataoff
;
194 /* Find out which section contains the data. */
196 for (i
= 0; i
< ef
->nprogtab
; i
++) {
197 if (address
< ef
->progtab
[i
].addr
)
200 dataoff
= address
- ef
->progtab
[i
].addr
;
201 if (dataoff
+ len
> ef
->progtab
[i
].size
)
204 sec
= ef
->progtab
[i
].sec
;
205 secbase
= ef
->progtab
[i
].addr
;
206 secofs
= ef
->progtab
[i
].offset
;
212 warnx("ef_obj_seg_read_rel(%s): bad address (%jx)",
213 ef
->ef_name
, (uintmax_t)address
);
217 if (secofs
== (GElf_Off
)-1) {
218 memset(dest
, 0, len
);
220 error
= elf_read_raw_data(ef
->ef_efile
, secofs
+ dataoff
, dest
,
226 /* Now do the relocations. */
227 for (i
= 0; i
< ef
->nrel
; i
++) {
228 if (ef
->reltab
[i
].sec
!= sec
)
230 for (r
= ef
->reltab
[i
].rel
;
231 r
< &ef
->reltab
[i
].rel
[ef
->reltab
[i
].nrel
]; r
++) {
232 error
= elf_reloc(ef
->ef_efile
, r
, ELF_T_REL
, secbase
,
238 for (i
= 0; i
< ef
->nrela
; i
++) {
239 if (ef
->relatab
[i
].sec
!= sec
)
241 for (a
= ef
->relatab
[i
].rela
;
242 a
< &ef
->relatab
[i
].rela
[ef
->relatab
[i
].nrela
]; a
++) {
243 error
= elf_reloc(ef
->ef_efile
, a
, ELF_T_RELA
, secbase
,
253 ef_obj_seg_read_string(elf_file_t ef
, GElf_Addr address
, size_t len
, char *dest
)
257 ofs
= ef_obj_get_offset(ef
, address
);
260 warnx("ef_obj_seg_read_string(%s): bad address (%jx)",
261 ef
->ef_name
, (uintmax_t)address
);
265 return (elf_read_raw_string(ef
->ef_efile
, ofs
, dest
, len
));
269 ef_obj_open(struct elf_file
*efile
, int verbose
)
277 int error
, pb
, ra
, rl
;
278 int j
, nsym
, symstrindex
, symtabindex
;
280 hdr
= &efile
->ef_hdr
;
281 if (hdr
->e_type
!= ET_REL
|| hdr
->e_shnum
== 0 || hdr
->e_shoff
== 0 ||
282 hdr
->e_shentsize
!= elf_object_size(efile
, ELF_T_SHDR
))
285 ef
= calloc(1, sizeof(*ef
));
290 efile
->ef_ops
= &ef_obj_file_ops
;
292 ef
->ef_verbose
= verbose
;
293 ef
->ef_name
= strdup(efile
->ef_filename
);
294 ef
->ef_efile
= efile
;
296 error
= elf_read_shdrs(efile
, &nshdr
, &shdr
);
302 /* Scan the section headers for information and table sizing. */
306 for (i
= 0; i
< nshdr
; i
++) {
307 switch (shdr
[i
].sh_type
) {
315 symstrindex
= shdr
[i
].sh_link
;
328 if (ef
->nprogtab
== 0) {
329 warnx("%s: file has no contents", ef
->ef_name
);
333 warnx("%s: file has no valid symbol table", ef
->ef_name
);
336 if (symstrindex
< 0 || symstrindex
> nshdr
||
337 shdr
[symstrindex
].sh_type
!= SHT_STRTAB
) {
338 warnx("%s: file has invalid symbol strings", ef
->ef_name
);
342 /* Allocate space for tracking the load chunks */
343 if (ef
->nprogtab
!= 0)
344 ef
->progtab
= calloc(ef
->nprogtab
, sizeof(*ef
->progtab
));
346 ef
->reltab
= calloc(ef
->nrel
, sizeof(*ef
->reltab
));
348 ef
->relatab
= calloc(ef
->nrela
, sizeof(*ef
->relatab
));
349 if ((ef
->nprogtab
!= 0 && ef
->progtab
== NULL
) ||
350 (ef
->nrel
!= 0 && ef
->reltab
== NULL
) ||
351 (ef
->nrela
!= 0 && ef
->relatab
== NULL
)) {
352 warnx("malloc failed");
357 if (elf_read_symbols(efile
, symtabindex
, &ef
->ddbsymcnt
,
358 &ef
->ddbsymtab
) != 0) {
359 warnx("elf_read_symbols failed");
363 if (elf_read_string_table(efile
, &shdr
[symstrindex
], &ef
->ddbstrcnt
,
364 &ef
->ddbstrtab
) != 0) {
365 warnx("elf_read_string_table failed");
369 /* Do we have a string table for the section names? */
370 if (hdr
->e_shstrndx
!= 0 &&
371 shdr
[hdr
->e_shstrndx
].sh_type
== SHT_STRTAB
) {
372 if (elf_read_string_table(efile
, &shdr
[hdr
->e_shstrndx
],
373 &ef
->shstrcnt
, &ef
->shstrtab
) != 0) {
374 warnx("elf_read_string_table failed");
380 * Now allocate address space for code/data(progbits) and
381 * bss(nobits) and allocate space for and load relocs.
387 for (i
= 0; i
< nshdr
; i
++) {
388 switch (shdr
[i
].sh_type
) {
391 mapbase
= roundup2(mapbase
, shdr
[i
].sh_addralign
);
392 ef
->progtab
[pb
].addr
= mapbase
;
393 if (shdr
[i
].sh_type
== SHT_PROGBITS
) {
394 ef
->progtab
[pb
].name
= "<<PROGBITS>>";
395 ef
->progtab
[pb
].offset
= shdr
[i
].sh_offset
;
397 ef
->progtab
[pb
].name
= "<<NOBITS>>";
398 ef
->progtab
[pb
].offset
= (GElf_Off
)-1;
400 ef
->progtab
[pb
].size
= shdr
[i
].sh_size
;
401 ef
->progtab
[pb
].sec
= i
;
402 if (ef
->shstrtab
&& shdr
[i
].sh_name
!= 0)
403 ef
->progtab
[pb
].name
=
404 ef
->shstrtab
+ shdr
[i
].sh_name
;
406 /* Update all symbol values with the offset. */
407 for (j
= 0; j
< ef
->ddbsymcnt
; j
++) {
408 es
= &ef
->ddbsymtab
[j
];
409 if (es
->st_shndx
!= i
)
411 es
->st_value
+= ef
->progtab
[pb
].addr
;
413 mapbase
+= shdr
[i
].sh_size
;
417 ef
->reltab
[rl
].sec
= shdr
[i
].sh_info
;
418 if (elf_read_rel(efile
, i
, &ef
->reltab
[rl
].nrel
,
419 &ef
->reltab
[rl
].rel
) != 0) {
420 warnx("elf_read_rel failed");
426 ef
->relatab
[ra
].sec
= shdr
[i
].sh_info
;
427 if (elf_read_rela(efile
, i
, &ef
->relatab
[ra
].nrela
,
428 &ef
->relatab
[ra
].rela
) != 0) {
429 warnx("elf_read_rela failed");
445 ef_obj_close(elf_file_t ef
)
451 if (ef
->nprogtab
!= 0)
454 for (i
= 0; i
< ef
->nrel
; i
++)
455 if (ef
->reltab
[i
].rel
!= NULL
)
456 free(ef
->reltab
[i
].rel
);
459 if (ef
->nrela
!= 0) {
460 for (i
= 0; i
< ef
->nrela
; i
++)
461 if (ef
->relatab
[i
].rela
!= NULL
)
462 free(ef
->relatab
[i
].rela
);
465 if (ef
->ddbsymtab
!= NULL
)
467 if (ef
->ddbstrtab
!= NULL
)
469 if (ef
->shstrtab
!= NULL
)
471 ef
->ef_efile
->ef_ops
= NULL
;
472 ef
->ef_efile
->ef_ef
= NULL
;