Annotation of src/usr.bin/ctfconv/elf.c, Revision 1.3
1.3 ! deraadt 1: /* $OpenBSD: elf.c,v 1.2 2017/08/11 14:58:56 jasper Exp $ */
1.2 jasper 2:
1.1 mpi 3: /*
4: * Copyright (c) 2016 Martin Pieuchot <mpi@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
1.3 ! deraadt 19: #include <sys/types.h>
1.1 mpi 20: #include <sys/exec_elf.h>
21:
22: #include <machine/reloc.h>
23:
24: #include <assert.h>
25: #include <err.h>
26: #include <string.h>
27:
28: static int elf_reloc_size(unsigned long);
29: static void elf_reloc_apply(const char *, const char *, size_t, ssize_t,
30: char *, size_t);
31:
32: int
33: iself(const char *p, size_t filesize)
34: {
35: Elf_Ehdr *eh = (Elf_Ehdr *)p;
36:
37: if (filesize < (off_t)sizeof(Elf_Ehdr)) {
38: warnx("file too small to be ELF");
39: return 0;
40: }
41:
42: if (eh->e_ehsize < sizeof(Elf_Ehdr) || !IS_ELF(*eh))
43: return 0;
44:
45: if (eh->e_ident[EI_CLASS] != ELFCLASS) {
46: warnx("unexpected word size %u", eh->e_ident[EI_CLASS]);
47: return 0;
48: }
49: if (eh->e_ident[EI_VERSION] != ELF_TARG_VER) {
50: warnx("unexpected version %u", eh->e_ident[EI_VERSION]);
51: return 0;
52: }
53: if (eh->e_ident[EI_DATA] >= ELFDATANUM) {
54: warnx("unexpected data format %u", eh->e_ident[EI_DATA]);
55: return 0;
56: }
57: if (eh->e_shoff > filesize) {
58: warnx("bogus section table offset 0x%llx", (off_t)eh->e_shoff);
59: return 0;
60: }
61: if (eh->e_shentsize < sizeof(Elf_Shdr)) {
62: warnx("bogus section header size %u", eh->e_shentsize);
63: return 0;
64: }
65: if (eh->e_shnum > (filesize - eh->e_shoff) / eh->e_shentsize) {
66: warnx("bogus section header count %u", eh->e_shnum);
67: return 0;
68: }
69: if (eh->e_shstrndx >= eh->e_shnum) {
70: warnx("bogus string table index %u", eh->e_shstrndx);
71: return 0;
72: }
73:
74: return 1;
75: }
76:
77: int
78: elf_getshstab(const char *p, size_t filesize, const char **shstab,
79: size_t *shstabsize)
80: {
81: Elf_Ehdr *eh = (Elf_Ehdr *)p;
82: Elf_Shdr *sh;
83:
84: sh = (Elf_Shdr *)(p + eh->e_shoff + eh->e_shstrndx * eh->e_shentsize);
85: if (sh->sh_type != SHT_STRTAB) {
86: warnx("unexpected string table type");
87: return -1;
88: }
89: if (sh->sh_offset > filesize) {
90: warnx("bogus string table offset");
91: return -1;
92: }
93: if (sh->sh_size > filesize - sh->sh_offset) {
94: warnx("bogus string table size");
95: return -1;
96: }
97: if (shstab != NULL)
98: *shstab = p + sh->sh_offset;
99: if (shstabsize != NULL)
100: *shstabsize = sh->sh_size;
101:
102: return 0;
103: }
104:
105: ssize_t
106: elf_getsymtab(const char *p, const char *shstab, size_t shstabsz,
107: const Elf_Sym **symtab, size_t *nsymb)
108: {
109: Elf_Ehdr *eh = (Elf_Ehdr *)p;
110: Elf_Shdr *sh;
111: size_t snlen;
112: ssize_t i;
113:
114: snlen = strlen(ELF_SYMTAB);
115:
116: for (i = 0; i < eh->e_shnum; i++) {
117: sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
118:
119: if (sh->sh_type != SHT_SYMTAB)
120: continue;
121:
122: if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
123: continue;
124:
125: if (strncmp(shstab + sh->sh_name, ELF_SYMTAB, snlen) == 0) {
126: if (symtab != NULL)
127: *symtab = (Elf_Sym *)(p + sh->sh_offset);
128: if (nsymb != NULL)
129: *nsymb = (sh->sh_size / sh->sh_entsize);
130:
131: return i;
132: }
133: }
134:
135: return -1;
136: }
137:
138: ssize_t
139: elf_getsection(char *p, const char *sname, const char *shstab,
140: size_t shstabsz, const char **psdata, size_t *pssz)
141: {
142: Elf_Ehdr *eh = (Elf_Ehdr *)p;
143: Elf_Shdr *sh;
144: char *sdata = NULL;
145: size_t snlen, ssz = 0;
146: ssize_t sidx, i;
147:
148: snlen = strlen(sname);
149: if (snlen == 0)
150: return -1;
151:
152: /* Find the given section. */
153: for (i = 0; i < eh->e_shnum; i++) {
154: sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
155:
156: if ((sh->sh_link >= eh->e_shnum) || (sh->sh_name >= shstabsz))
157: continue;
158:
159: if (strncmp(shstab + sh->sh_name, sname, snlen) == 0) {
160: sidx = i;
161: sdata = p + sh->sh_offset;
162: ssz = sh->sh_size;
163: elf_reloc_apply(p, shstab, shstabsz, sidx, sdata, ssz);
164: break;
165: }
166: }
167:
168: if (sdata == NULL)
169: return -1;
170:
171: if (psdata != NULL)
172: *psdata = sdata;
173: if (pssz != NULL)
174: *pssz = ssz;
175:
176: return sidx;
177: }
178:
179: static int
180: elf_reloc_size(unsigned long type)
181: {
182: switch (type) {
183: #ifdef R_X86_64_64
184: case R_X86_64_64:
185: return sizeof(uint64_t);
186: #endif
187: #ifdef R_X86_64_32
188: case R_X86_64_32:
189: return sizeof(uint32_t);
190: #endif
191: #ifdef RELOC_32
192: case RELOC_32:
193: return sizeof(uint32_t);
194: #endif
195: default:
196: break;
197: }
198:
199: return -1;
200: }
201:
202: #define ELF_WRITE_RELOC(buf, val, rsize) \
203: do { \
204: if (rsize == 4) { \
205: uint32_t v32 = val; \
206: memcpy(buf, &v32, sizeof(v32)); \
207: } else { \
208: uint64_t v64 = val; \
209: memcpy(buf, &v64, sizeof(v64)); \
210: } \
211: } while (0)
212:
213: static void
214: elf_reloc_apply(const char *p, const char *shstab, size_t shstabsz,
215: ssize_t sidx, char *sdata, size_t ssz)
216: {
217: Elf_Ehdr *eh = (Elf_Ehdr *)p;
218: Elf_Shdr *sh;
219: Elf_Rel *rel = NULL;
220: Elf_RelA *rela = NULL;
221: const Elf_Sym *symtab, *sym;
222: ssize_t symtabidx;
223: size_t nsymb, rsym, rtyp, roff;
224: size_t i, j;
225: uint64_t value;
226: int rsize;
227:
228: /* Find symbol table location and number of symbols. */
229: symtabidx = elf_getsymtab(p, shstab, shstabsz, &symtab, &nsymb);
230: if (symtabidx == -1) {
231: warnx("symbol table not found");
232: return;
233: }
234:
235: /* Apply possible relocation. */
236: for (i = 0; i < eh->e_shnum; i++) {
237: sh = (Elf_Shdr *)(p + eh->e_shoff + i * eh->e_shentsize);
238:
239: if (sh->sh_size == 0)
240: continue;
241:
242: if ((sh->sh_info != sidx) || (sh->sh_link != symtabidx))
243: continue;
244:
245: switch (sh->sh_type) {
246: case SHT_RELA:
247: rela = (Elf_RelA *)(p + sh->sh_offset);
248: for (j = 0; j < (sh->sh_size / sizeof(Elf_RelA)); j++) {
249: rsym = ELF_R_SYM(rela[j].r_info);
250: rtyp = ELF_R_TYPE(rela[j].r_info);
251: roff = rela[j].r_offset;
252: if (rsym >= nsymb)
253: continue;
254: sym = &symtab[rsym];
255: value = sym->st_value + rela[j].r_addend;
256:
257: rsize = elf_reloc_size(rtyp);
258: if (rsize == -1 || roff + rsize >= ssz)
259: continue;
260:
261: ELF_WRITE_RELOC(sdata + roff, value, rsize);
262: }
263: break;
264: case SHT_REL:
265: rel = (Elf_Rel *)(p + sh->sh_offset);
266: for (j = 0; j < (sh->sh_size / sizeof(Elf_Rel)); j++) {
267: rsym = ELF_R_SYM(rel[j].r_info);
268: rtyp = ELF_R_TYPE(rel[j].r_info);
269: roff = rel[j].r_offset;
270: if (rsym >= nsymb)
271: continue;
272: sym = &symtab[rsym];
273: value = sym->st_value;
274:
275: rsize = elf_reloc_size(rtyp);
276: if (rsize == -1 || roff + rsize >= ssz)
277: continue;
278:
279: ELF_WRITE_RELOC(sdata + roff, value, rsize);
280: }
281: break;
282: default:
283: continue;
284: }
285: }
286: }