1 /******************************************************************************
2 * mkelf32.c
3 *
4 * Usage: elf-prefix <in-image> <out-image> <load-base>
5 *
6 * Converts an Elf64 executable binary <in-image> into a simple Elf32
7 * image <out-image> comprising a single chunk to be loaded at <load-base>.
8 */
9
10 #include <errno.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <inttypes.h>
19
20 #define u8 uint8_t
21 #define u16 uint16_t
22 #define u32 uint32_t
23 #define u64 uint64_t
24 #define s8 int8_t
25 #define s16 int16_t
26 #define s32 int32_t
27 #define s64 int64_t
28 #include "../../../include/xen/elfstructs.h"
29
30 #define DYNAMICALLY_FILLED 0
31 #define RAW_OFFSET 128
32
33 static Elf32_Ehdr out_ehdr = {
34 { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, /* EI_MAG{0-3} */
35 ELFCLASS32, /* EI_CLASS */
36 ELFDATA2LSB, /* EI_DATA */
37 EV_CURRENT, /* EI_VERSION */
38 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* e_ident */
39 ET_EXEC, /* e_type */
40 EM_386, /* e_machine */
41 EV_CURRENT, /* e_version */
42 DYNAMICALLY_FILLED, /* e_entry */
43 sizeof(Elf32_Ehdr), /* e_phoff */
44 DYNAMICALLY_FILLED, /* e_shoff */
45 0, /* e_flags */
46 sizeof(Elf32_Ehdr), /* e_ehsize */
47 sizeof(Elf32_Phdr), /* e_phentsize */
48 1, /* modify based on num_phdrs */ /* e_phnum */
49 sizeof(Elf32_Shdr), /* e_shentsize */
50 3, /* modify based on num_phdrs */ /* e_shnum */
51 2 /* e_shstrndx */
52 };
53
54 static Elf32_Phdr out_phdr = {
55 PT_LOAD, /* p_type */
56 RAW_OFFSET, /* p_offset */
57 DYNAMICALLY_FILLED, /* p_vaddr */
58 DYNAMICALLY_FILLED, /* p_paddr */
59 DYNAMICALLY_FILLED, /* p_filesz */
60 DYNAMICALLY_FILLED, /* p_memsz */
61 PF_R|PF_W|PF_X, /* p_flags */
62 64 /* p_align */
63 };
64 static Elf32_Phdr note_phdr = {
65 PT_NOTE, /* p_type */
66 DYNAMICALLY_FILLED, /* p_offset */
67 DYNAMICALLY_FILLED, /* p_vaddr */
68 DYNAMICALLY_FILLED, /* p_paddr */
69 DYNAMICALLY_FILLED, /* p_filesz */
70 DYNAMICALLY_FILLED, /* p_memsz */
71 PF_R, /* p_flags */
72 4 /* p_align */
73 };
74
75 static u8 out_shstrtab[] = "\0.text\0.shstrtab";
76 /* If num_phdrs >= 2, we need to tack the .note. */
77 static u8 out_shstrtab_extra[] = ".note\0";
78
79 static Elf32_Shdr out_shdr[] = {
80 { 0 },
81 { 1, /* sh_name */
82 SHT_PROGBITS, /* sh_type */
83 SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR, /* sh_flags */
84 DYNAMICALLY_FILLED, /* sh_addr */
85 RAW_OFFSET, /* sh_offset */
86 DYNAMICALLY_FILLED, /* sh_size */
87 0, /* sh_link */
88 0, /* sh_info */
89 64, /* sh_addralign */
90 0 /* sh_entsize */
91 },
92 { 7, /* sh_name */
93 SHT_STRTAB, /* sh_type */
94 0, /* sh_flags */
95 0, /* sh_addr */
96 DYNAMICALLY_FILLED, /* sh_offset */
97 sizeof(out_shstrtab), /* sh_size */
98 0, /* sh_link */
99 0, /* sh_info */
100 1, /* sh_addralign */
101 0 /* sh_entsize */
102 }
103 };
104
105 /*
106 * The 17 points to the '.note' in the out_shstrtab and out_shstrtab_extra
107 * laid out in the file.
108 */
109 static Elf32_Shdr out_shdr_note = {
110 17, /* sh_name */
111 SHT_NOTE, /* sh_type */
112 0, /* sh_flags */
113 DYNAMICALLY_FILLED, /* sh_addr */
114 DYNAMICALLY_FILLED, /* sh_offset */
115 DYNAMICALLY_FILLED, /* sh_size */
116 0, /* sh_link */
117 0, /* sh_info */
118 4, /* sh_addralign */
119 0 /* sh_entsize */
120 };
121
122 /* Some system header files define these macros and pollute our namespace. */
123 #undef swap16
124 #undef swap32
125 #undef swap64
126
127 #define swap16(_v) ((((u16)(_v)>>8)&0xff)|(((u16)(_v)&0xff)<<8))
128 #define swap32(_v) (((u32)swap16((u16)(_v))<<16)|(u32)swap16((u32)((_v)>>16)))
129 #define swap64(_v) (((u64)swap32((u32)(_v))<<32)|(u64)swap32((u32)((_v)>>32)))
130
131 static int big_endian;
132
endianadjust_ehdr32(Elf32_Ehdr * eh)133 static void endianadjust_ehdr32(Elf32_Ehdr *eh)
134 {
135 if ( !big_endian )
136 return;
137 eh->e_type = swap16(eh->e_type);
138 eh->e_machine = swap16(eh->e_machine);
139 eh->e_version = swap32(eh->e_version);
140 eh->e_entry = swap32(eh->e_entry);
141 eh->e_phoff = swap32(eh->e_phoff);
142 eh->e_shoff = swap32(eh->e_shoff);
143 eh->e_flags = swap32(eh->e_flags);
144 eh->e_ehsize = swap16(eh->e_ehsize);
145 eh->e_phentsize = swap16(eh->e_phentsize);
146 eh->e_phnum = swap16(eh->e_phnum);
147 eh->e_shentsize = swap16(eh->e_shentsize);
148 eh->e_shnum = swap16(eh->e_shnum);
149 eh->e_shstrndx = swap16(eh->e_shstrndx);
150 }
151
endianadjust_ehdr64(Elf64_Ehdr * eh)152 static void endianadjust_ehdr64(Elf64_Ehdr *eh)
153 {
154 if ( !big_endian )
155 return;
156 eh->e_type = swap16(eh->e_type);
157 eh->e_machine = swap16(eh->e_machine);
158 eh->e_version = swap32(eh->e_version);
159 eh->e_entry = swap64(eh->e_entry);
160 eh->e_phoff = swap64(eh->e_phoff);
161 eh->e_shoff = swap64(eh->e_shoff);
162 eh->e_flags = swap32(eh->e_flags);
163 eh->e_ehsize = swap16(eh->e_ehsize);
164 eh->e_phentsize = swap16(eh->e_phentsize);
165 eh->e_phnum = swap16(eh->e_phnum);
166 eh->e_shentsize = swap16(eh->e_shentsize);
167 eh->e_shnum = swap16(eh->e_shnum);
168 eh->e_shstrndx = swap16(eh->e_shstrndx);
169 }
170
endianadjust_phdr32(Elf32_Phdr * ph)171 static void endianadjust_phdr32(Elf32_Phdr *ph)
172 {
173 if ( !big_endian )
174 return;
175 ph->p_type = swap32(ph->p_type);
176 ph->p_offset = swap32(ph->p_offset);
177 ph->p_vaddr = swap32(ph->p_vaddr);
178 ph->p_paddr = swap32(ph->p_paddr);
179 ph->p_filesz = swap32(ph->p_filesz);
180 ph->p_memsz = swap32(ph->p_memsz);
181 ph->p_flags = swap32(ph->p_flags);
182 ph->p_align = swap32(ph->p_align);
183 }
184
endianadjust_phdr64(Elf64_Phdr * ph)185 static void endianadjust_phdr64(Elf64_Phdr *ph)
186 {
187 if ( !big_endian )
188 return;
189 ph->p_type = swap32(ph->p_type);
190 ph->p_flags = swap32(ph->p_flags);
191 ph->p_offset = swap64(ph->p_offset);
192 ph->p_vaddr = swap64(ph->p_vaddr);
193 ph->p_paddr = swap64(ph->p_paddr);
194 ph->p_filesz = swap64(ph->p_filesz);
195 ph->p_memsz = swap64(ph->p_memsz);
196 ph->p_align = swap64(ph->p_align);
197 }
198
endianadjust_shdr32(Elf32_Shdr * sh)199 static void endianadjust_shdr32(Elf32_Shdr *sh)
200 {
201 if ( !big_endian )
202 return;
203 sh->sh_name = swap32(sh->sh_name);
204 sh->sh_type = swap32(sh->sh_type);
205 sh->sh_flags = swap32(sh->sh_flags);
206 sh->sh_addr = swap32(sh->sh_addr);
207 sh->sh_offset = swap32(sh->sh_offset);
208 sh->sh_size = swap32(sh->sh_size);
209 sh->sh_link = swap32(sh->sh_link);
210 sh->sh_info = swap32(sh->sh_info);
211 sh->sh_addralign = swap32(sh->sh_addralign);
212 sh->sh_entsize = swap32(sh->sh_entsize);
213 }
214
do_write(int fd,void * data,int len)215 static void do_write(int fd, void *data, int len)
216 {
217 int done, left = len;
218 char *p = data;
219
220 while ( left != 0 )
221 {
222 if ( (done = write(fd, p, left)) == -1 )
223 {
224 if ( errno == EINTR )
225 continue;
226 fprintf(stderr, "Error writing output image: %d (%s).\n",
227 errno, strerror(errno));
228 exit(1);
229 }
230
231 left -= done;
232 p += done;
233 }
234 }
235
do_read(int fd,void * data,int len)236 static void do_read(int fd, void *data, int len)
237 {
238 int done, left = len;
239 char *p = data;
240
241 while ( left != 0 )
242 {
243 if ( (done = read(fd, p, left)) == -1 )
244 {
245 if ( errno == EINTR )
246 continue;
247 fprintf(stderr, "Error reading input image: %d (%s).\n",
248 errno, strerror(errno));
249 exit(1);
250 }
251
252 left -= done;
253 p += done;
254 }
255 }
256
main(int argc,char ** argv)257 int main(int argc, char **argv)
258 {
259 u64 final_exec_addr;
260 u32 loadbase, dat_siz, mem_siz, note_base, note_sz, offset;
261 char *inimage, *outimage;
262 int infd, outfd;
263 char buffer[1024] = {};
264 int bytes, todo, i = 1;
265 int num_phdrs = 1;
266
267 Elf32_Ehdr in32_ehdr;
268
269 Elf64_Ehdr in64_ehdr;
270 Elf64_Phdr in64_phdr;
271
272 if ( argc < 5 )
273 {
274 fprintf(stderr, "Usage: mkelf32 [--notes] <in-image> <out-image> "
275 "<load-base> <final-exec-addr>\n");
276 return 1;
277 }
278
279 if ( !strcmp(argv[1], "--notes") )
280 {
281 i = 2;
282 num_phdrs = 2;
283 }
284 inimage = argv[i++];
285 outimage = argv[i++];
286 loadbase = strtoul(argv[i++], NULL, 16);
287 final_exec_addr = strtoull(argv[i++], NULL, 16);
288
289 infd = open(inimage, O_RDONLY);
290 if ( infd == -1 )
291 {
292 fprintf(stderr, "Failed to open input image '%s': %d (%s).\n",
293 inimage, errno, strerror(errno));
294 return 1;
295 }
296
297 do_read(infd, &in32_ehdr, sizeof(in32_ehdr));
298 if ( !IS_ELF(in32_ehdr) ||
299 (in32_ehdr.e_ident[EI_DATA] != ELFDATA2LSB) )
300 {
301 fprintf(stderr, "Input image must be a little-endian Elf image.\n");
302 return 1;
303 }
304
305 big_endian = (*(u16 *)in32_ehdr.e_ident == ((ELFMAG0 << 8) | ELFMAG1));
306
307 endianadjust_ehdr32(&in32_ehdr);
308 if ( in32_ehdr.e_ident[EI_CLASS] != ELFCLASS64 )
309 {
310 fprintf(stderr, "Bad program header class - we only do 64-bit!.\n");
311 return 1;
312 }
313 (void)lseek(infd, 0, SEEK_SET);
314 do_read(infd, &in64_ehdr, sizeof(in64_ehdr));
315 endianadjust_ehdr64(&in64_ehdr);
316
317 if ( in64_ehdr.e_phentsize != sizeof(in64_phdr) )
318 {
319 fprintf(stderr, "Bad program header size (%d != %d).\n",
320 (int)in64_ehdr.e_phentsize, (int)sizeof(in64_phdr));
321 return 1;
322 }
323 if ( in64_ehdr.e_phnum != num_phdrs )
324 {
325 fprintf(stderr, "Expect precisly %d program header; found %d.\n",
326 num_phdrs, (int)in64_ehdr.e_phnum);
327 return 1;
328 }
329
330 (void)lseek(infd, in64_ehdr.e_phoff, SEEK_SET);
331 do_read(infd, &in64_phdr, sizeof(in64_phdr));
332 endianadjust_phdr64(&in64_phdr);
333
334 (void)lseek(infd, in64_phdr.p_offset, SEEK_SET);
335 dat_siz = (u32)in64_phdr.p_filesz;
336
337 /* Do not use p_memsz: it does not include BSS alignment padding. */
338 /*mem_siz = (u32)in64_phdr.p_memsz;*/
339 mem_siz = (u32)(final_exec_addr - in64_phdr.p_vaddr);
340
341 note_sz = note_base = offset = 0;
342 if ( num_phdrs > 1 )
343 {
344 offset = in64_phdr.p_offset;
345 note_base = in64_phdr.p_vaddr;
346
347 (void)lseek(infd, in64_ehdr.e_phoff+sizeof(in64_phdr), SEEK_SET);
348 do_read(infd, &in64_phdr, sizeof(in64_phdr));
349 endianadjust_phdr64(&in64_phdr);
350
351 (void)lseek(infd, offset, SEEK_SET);
352
353 note_sz = in64_phdr.p_memsz;
354 note_base = in64_phdr.p_vaddr - note_base;
355
356 if ( in64_phdr.p_offset > dat_siz || offset > in64_phdr.p_offset )
357 {
358 fprintf(stderr, "Expected .note section within .text section!\n" \
359 "Offset %"PRId64" not within %d!\n",
360 in64_phdr.p_offset, dat_siz);
361 return 1;
362 }
363 /* Gets us the absolute offset within the .text section. */
364 offset = in64_phdr.p_offset - offset;
365 }
366
367 /*
368 * End the image on a page boundary. This gets round alignment bugs
369 * in the boot- or chain-loader (e.g., kexec on the XenoBoot CD).
370 */
371 mem_siz += -(loadbase + mem_siz) & 0xfff;
372
373 out_ehdr.e_entry = loadbase;
374 out_ehdr.e_shoff = RAW_OFFSET + dat_siz;
375
376 out_phdr.p_vaddr = loadbase;
377 out_phdr.p_paddr = loadbase;
378 out_phdr.p_filesz = dat_siz;
379 out_phdr.p_memsz = mem_siz;
380
381 out_shdr[1].sh_addr = loadbase;
382 out_shdr[1].sh_size = dat_siz;
383 out_shdr[2].sh_offset = RAW_OFFSET + dat_siz + sizeof(out_shdr);
384
385 if ( num_phdrs > 1 )
386 {
387 /* We have two of them! */
388 out_ehdr.e_phnum = num_phdrs;
389 /* Extra .note section. */
390 out_ehdr.e_shnum++;
391
392 /* Fill out the PT_NOTE program header. */
393 note_phdr.p_vaddr = note_base;
394 note_phdr.p_paddr = note_base;
395 note_phdr.p_filesz = note_sz;
396 note_phdr.p_memsz = note_sz;
397 note_phdr.p_offset = RAW_OFFSET + offset;
398
399 /* Tack on the .note\0 */
400 out_shdr[2].sh_size += sizeof(out_shstrtab_extra);
401 /* And move it past the .note section. */
402 out_shdr[2].sh_offset += sizeof(out_shdr_note);
403
404 /* Fill out the .note section. */
405 out_shdr_note.sh_size = note_sz;
406 out_shdr_note.sh_addr = note_base;
407 out_shdr_note.sh_offset = RAW_OFFSET + offset;
408 }
409
410 outfd = open(outimage, O_WRONLY|O_CREAT|O_TRUNC, 0775);
411 if ( outfd == -1 )
412 {
413 fprintf(stderr, "Failed to open output image '%s': %d (%s).\n",
414 outimage, errno, strerror(errno));
415 return 1;
416 }
417
418 endianadjust_ehdr32(&out_ehdr);
419 do_write(outfd, &out_ehdr, sizeof(out_ehdr));
420
421 endianadjust_phdr32(&out_phdr);
422 do_write(outfd, &out_phdr, sizeof(out_phdr));
423
424 if ( num_phdrs > 1 )
425 {
426 endianadjust_phdr32(¬e_phdr);
427 do_write(outfd, ¬e_phdr, sizeof(note_phdr));
428 }
429
430 if ( (bytes = RAW_OFFSET - sizeof(out_ehdr) - (num_phdrs * sizeof(out_phdr)) ) < 0 )
431 {
432 fprintf(stderr, "Header overflow.\n");
433 return 1;
434 }
435 do_write(outfd, buffer, bytes);
436
437 for ( bytes = 0; bytes < dat_siz; bytes += todo )
438 {
439 todo = ((dat_siz - bytes) > sizeof(buffer)) ?
440 sizeof(buffer) : (dat_siz - bytes);
441 do_read(infd, buffer, todo);
442 do_write(outfd, buffer, todo);
443 }
444
445 for ( i = 0; i < (sizeof(out_shdr) / sizeof(out_shdr[0])); i++ )
446 endianadjust_shdr32(&out_shdr[i]);
447 do_write(outfd, &out_shdr[0], sizeof(out_shdr));
448
449 if ( num_phdrs > 1 )
450 {
451 endianadjust_shdr32(&out_shdr_note);
452 /* Append the .note section. */
453 do_write(outfd, &out_shdr_note, sizeof(out_shdr_note));
454 /* The normal strings - .text\0.. */
455 do_write(outfd, out_shstrtab, sizeof(out_shstrtab));
456 /* Our .note */
457 do_write(outfd, out_shstrtab_extra, sizeof(out_shstrtab_extra));
458 do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+sizeof(out_shstrtab_extra)+dat_siz)&3));
459 }
460 else
461 {
462 do_write(outfd, out_shstrtab, sizeof(out_shstrtab));
463 do_write(outfd, buffer, 4-((sizeof(out_shstrtab)+dat_siz)&3));
464 }
465 close(infd);
466 close(outfd);
467
468 return 0;
469 }
470
471 /*
472 * Local variables:
473 * mode: C
474 * c-file-style: "BSD"
475 * c-basic-offset: 4
476 * tab-width: 4
477 * indent-tabs-mode: nil
478 * End:
479 */
480