source: bootcd/isolinux/syslinux-6.03/efi/wrapper.c @ 26ffad7

Last change on this file since 26ffad7 was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 8.0 KB
Line 
1/*
2 * Copyright (C) 2011 Intel Corporation; author Matt Fleming
3 *
4 * Wrap the ELF shared library in a PE32 (32bit) or PE32+ (64bit) suit.
5 *
6 * Syslinux plays some games with the ELF sections that are not easily
7 * converted to a PE32 executable. For instance, Syslinux requires
8 * that a symbol hash table be present (GNU hash or SysV) so that
9 * symbols in ELF modules can be resolved at runtime but the EFI
10 * firmware loader doesn't like that and refuses to load the file.
11 *
12 * We pretend that we have an EFI executable with a single .text
13 * section so that the EFI loader will load it and jump to the entry
14 * point. Once the Syslinux ELF shared object has control we can do
15 * whatever we want.
16 */
17#include <linux/elf.h>
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <unistd.h>
24
25#include "wrapper.h"
26
27#if __SIZEOF_POINTER__ == 4
28typedef Elf32_Ehdr Elf_Ehdr;
29typedef Elf32_Addr Elf_Addr;
30#elif __SIZEOF_POINTER__ == 8
31typedef Elf64_Ehdr Elf_Ehdr;
32typedef Elf64_Addr Elf_Addr;
33#else
34#error "unsupported architecture"
35#endif
36
37/*
38 * 'so_memsz' is the size of the ELF shared object once loaded.
39 * 'data_size' is the size of initialised data in the shared object.
40 *  'class' dictates how the header is written
41 *      For 32bit machines (class == ELFCLASS32), the optional
42 *      header includes PE32 header fields
43 *      For 64bit machines (class == ELFCLASS64), the optional
44 *      header includes PE32+header fields
45 */
46static void write_header(FILE *f, __uint32_t entry, size_t data_size,
47                         __uint32_t so_memsz, __uint8_t class)
48{
49        struct optional_hdr o_hdr;
50        struct optional_hdr_pe32p o_hdr_pe32p;
51        struct section t_sec;
52        struct extra_hdr e_hdr;
53        struct extra_hdr_pe32p e_hdr_pe32p;
54        struct coff_hdr c_hdr;
55        struct header hdr;
56        __uint32_t total_sz = data_size;
57        __uint32_t hdr_sz;
58        __uint32_t reloc_start, reloc_end;
59
60        /*
61         * The header size have to be a multiple of file_align, which currently
62         * is 512
63         */
64        hdr_sz = 512;
65        total_sz += hdr_sz;
66        entry += hdr_sz;
67
68        memset(&hdr, 0, sizeof(hdr));
69        hdr.msdos_signature = MSDOS_SIGNATURE;
70
71        /*
72         * The relocs table pointer needs to be >= 0x40 for PE files. It
73         * informs things like file(1) that we are not an MS-DOS
74         * executable.
75         */
76        hdr.relocs_ptr = 0x40;
77
78        hdr.pe_hdr = OFFSETOF(struct header, pe_signature);
79        hdr.pe_signature = PE_SIGNATURE;
80        fwrite(&hdr, sizeof(hdr), 1, f);
81
82        memset(&c_hdr, 0, sizeof(c_hdr));
83        c_hdr.nr_sections = 1;
84        c_hdr.nr_syms = 1;
85        if (class == ELFCLASS32) {
86                c_hdr.arch = IMAGE_FILE_MACHINE_I386;
87                c_hdr.characteristics = IMAGE_FILE_32BIT_MACHINE |
88                        IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
89                        IMAGE_FILE_LINE_NUMBERS_STRIPPED;
90                c_hdr.optional_hdr_sz = sizeof(o_hdr) + sizeof(e_hdr);
91                fwrite(&c_hdr, sizeof(c_hdr), 1, f);
92                memset(&o_hdr, 0, sizeof(o_hdr));
93                o_hdr.format = PE32_FORMAT;
94                o_hdr.major_linker_version = 0x02;
95                o_hdr.minor_linker_version = 0x14;
96                o_hdr.code_sz = data_size;
97                o_hdr.entry_point = entry;
98                o_hdr.initialized_data_sz = data_size;
99                fwrite(&o_hdr, sizeof(o_hdr), 1, f);
100                memset(&e_hdr, 0, sizeof(e_hdr));
101                e_hdr.section_align = 4096;
102                e_hdr.file_align = 512;
103                e_hdr.image_sz = hdr_sz + so_memsz;
104                e_hdr.headers_sz = hdr_sz;
105                e_hdr.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
106                e_hdr.rva_and_sizes_nr = sizeof(e_hdr.data_directory) / sizeof(__uint64_t);
107                fwrite(&e_hdr, sizeof(e_hdr), 1, f);
108        }
109        else if (class == ELFCLASS64) {
110                c_hdr.arch = IMAGE_FILE_MACHINE_X86_64;
111                c_hdr.characteristics = IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
112                        IMAGE_FILE_LINE_NUMBERS_STRIPPED;
113                c_hdr.optional_hdr_sz = sizeof(o_hdr_pe32p) + sizeof(e_hdr_pe32p);
114                fwrite(&c_hdr, sizeof(c_hdr), 1, f);
115                memset(&o_hdr_pe32p, 0, sizeof(o_hdr_pe32p));
116                o_hdr_pe32p.format = PE32P_FORMAT;
117                o_hdr_pe32p.major_linker_version = 0x02;
118                o_hdr_pe32p.minor_linker_version = 0x14;
119                o_hdr_pe32p.code_sz = data_size;
120                o_hdr_pe32p.entry_point = entry;
121                o_hdr.initialized_data_sz = data_size;
122                fwrite(&o_hdr_pe32p, sizeof(o_hdr_pe32p), 1, f);
123                memset(&e_hdr_pe32p, 0, sizeof(e_hdr_pe32p));
124                e_hdr_pe32p.section_align = 4096;
125                e_hdr_pe32p.file_align = 512;
126                e_hdr_pe32p.image_sz = hdr_sz + so_memsz;
127                e_hdr_pe32p.headers_sz = hdr_sz;
128                e_hdr_pe32p.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
129                e_hdr_pe32p.rva_and_sizes_nr = sizeof(e_hdr_pe32p.data_directory) / sizeof(__uint64_t);
130                fwrite(&e_hdr_pe32p, sizeof(e_hdr_pe32p), 1, f);
131        }
132
133        memset(&t_sec, 0, sizeof(t_sec));
134        strcpy((char *)t_sec.name, ".text");
135        t_sec.virtual_sz = data_size;
136        t_sec.virtual_address = hdr_sz;
137        t_sec.raw_data_sz = t_sec.virtual_sz;
138        t_sec.raw_data = t_sec.virtual_address;
139        t_sec.characteristics = IMAGE_SCN_CNT_CODE |
140                IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
141                IMAGE_SCN_MEM_READ;
142        fwrite(&t_sec, sizeof(t_sec), 1, f);
143
144        /*
145         * Add some padding to align the ELF as needed
146         */
147        if (ftell(f) > t_sec.virtual_address) {
148                /* Don't rewind! hdr_sz need to be increased. */
149                fprintf(stderr, "PE32+ headers are too large.\n");
150                exit(EXIT_FAILURE);
151        }
152
153        fseek(f, t_sec.virtual_address, SEEK_SET);
154}
155
156static void usage(char *progname)
157{
158        fprintf(stderr, "usage: %s <ELF shared object> <output file>\n",
159                progname);
160}
161
162int main(int argc, char **argv)
163{
164        Elf32_Ehdr e32_hdr;
165        Elf64_Ehdr e64_hdr;
166        __uint32_t entry;
167        __uint8_t class;
168        __uint64_t phoff = 0;
169        __uint16_t phnum = 0, phentsize = 0;
170        unsigned char *id;
171        FILE *f_in, *f_out;
172        void *buf;
173        size_t datasz, memsz, rv;
174
175        if (argc < 3) {
176                usage(argv[0]);
177                exit(0);
178        }
179
180        f_in = fopen(argv[1], "r");
181        if (!f_in) {
182                perror("fopen");
183                exit(EXIT_FAILURE);
184        }
185
186        f_out = fopen(argv[2], "w");
187        if (!f_out) {
188                perror("fopen");
189                exit(EXIT_FAILURE);
190        }
191
192        /*
193         * Parse the ELF header and find the entry point.
194         */
195        fread((void *)&e32_hdr, sizeof(e32_hdr), 1, f_in);
196        if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
197                id = e32_hdr.e_ident;
198                class = ELFCLASS32;
199                entry = e32_hdr.e_entry;
200                phoff = e32_hdr.e_phoff;
201                phnum = e32_hdr.e_phnum;
202                phentsize = e32_hdr.e_phentsize;
203        }
204        else if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS64) {
205                /* read the header again for x86_64
206                 * note that the elf header entry point is 64bit whereas
207                 * the entry point in PE/COFF format is 32bit!*/
208                class = ELFCLASS64;
209                rewind(f_in);
210                fread((void *)&e64_hdr, sizeof(e64_hdr), 1, f_in);
211                id = e64_hdr.e_ident;
212                entry = e64_hdr.e_entry;
213                phoff = e64_hdr.e_phoff;
214                phnum = e64_hdr.e_phnum;
215                phentsize = e64_hdr.e_phentsize;
216        } else {
217                fprintf(stderr, "Unsupported architecture\n");
218                exit(EXIT_FAILURE);
219        }
220
221        if (id[EI_MAG0] != ELFMAG0 ||
222            id[EI_MAG1] != ELFMAG1 ||
223            id[EI_MAG2] != ELFMAG2 ||
224            id[EI_MAG3] != ELFMAG3) {
225                fprintf(stderr, "Input file not ELF shared object\n");
226                exit(EXIT_FAILURE);
227        }
228
229        if (!phoff || !phnum) {
230                fprintf(stderr, "Cannot find segment table\n");
231                exit(EXIT_FAILURE);
232        }
233
234        /*
235         * Find the LOAD program header. Everything in this segment
236         * is copied verbatim to the output file.
237         * Although there may be several LOAD program headers, only
238         * one is currently copied.
239         */
240        if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
241                Elf32_Phdr phdr;
242                int i;
243
244                /* Find the first LOAD program header */
245                for (i = 0; i < phnum; i++) {
246                        fseek(f_in, phoff + i * phentsize, SEEK_SET);
247                        fread(&phdr, sizeof(phdr), 1, f_in);
248
249                        if (phdr.p_type == PT_LOAD)
250                                break;
251                }
252
253                datasz = phdr.p_filesz;
254                memsz = phdr.p_memsz;
255        } else if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS64) {
256                Elf64_Phdr phdr;
257                int i;
258
259                /* Find the first LOAD program header */
260                for (i = 0; i < phnum; i++) {
261                        fseek(f_in, phoff + i * phentsize, SEEK_SET);
262                        fread(&phdr, sizeof(phdr), 1, f_in);
263
264                        if (phdr.p_type == PT_LOAD)
265                                break;
266                }
267
268                datasz = phdr.p_filesz;
269                memsz = phdr.p_memsz;
270        }
271
272        buf = malloc(datasz);
273        if (!buf) {
274                perror("malloc");
275                exit(EXIT_FAILURE);
276        }
277
278        write_header(f_out, entry, datasz, memsz, class);
279
280        /* Write out the entire ELF shared object */
281        rewind(f_in);
282        rv = fread(buf, datasz, 1, f_in);
283        if (!rv && ferror(f_in)) {
284                fprintf(stderr, "Failed to read all bytes from input\n");
285                exit(EXIT_FAILURE);
286        }
287
288        fwrite(buf, datasz, rv, f_out);
289        free(buf);
290        fclose(f_out);
291        fclose(f_in);
292        return 0;
293}
Note: See TracBrowser for help on using the repository browser.