Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / elf2exe / elf2exe.c
1 /*-
2  * Copyright (c) 1999 Stefan Esser
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * Make an ARC firmware executable from an ELF file.
29  */
30
31 #ifndef lint
32 static const char rcsid[] =
33   "$FreeBSD: src/usr.sbin/elf2exe/elf2exe.c,v 1.6.2.1 2000/07/20 10:35:23 kris Exp $";
34 #endif /* not lint */
35
36 #include <sys/types.h>
37 #include <sys/elf64.h>
38 #include <err.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <time.h>
44 #include <unistd.h>
45
46 #define ALPHA_FMAGIC    0x184
47
48 #define TOTHSZ          0x200
49
50 typedef struct filehdr {
51     u_int16_t           f_magic;
52     u_int16_t           f_nscns;
53     u_int32_t           f_timdat;
54     u_int32_t           f_symptr;
55     u_int32_t           f_nsyms;
56     u_int16_t           f_opthdr;
57     u_int16_t           f_flags;
58 } FILHDR;
59 #define FILHSZ  20
60
61 #define ALPHA_AMAGIC    0407
62
63 typedef struct aouthdr {
64     u_int16_t           a_magic;
65     u_int16_t           a_vstamp;
66     u_int32_t           a_tsize;
67     u_int32_t           a_dsize;
68     u_int32_t           a_bsize;
69     u_int32_t           a_entry;
70     u_int32_t           a_text_start;
71     u_int32_t           a_data_start;
72     u_int32_t           a_bss_start;
73     u_int32_t           a_gprmask;
74     u_int32_t           a_cprmask[4];
75     u_int32_t           a_gp_value;
76 } AOUTHDR;
77 #define AOUTSZ  56
78
79 typedef struct scnhdr {
80     char                s_name[8];
81     u_int32_t           s_fill;
82     u_int32_t           s_vaddr;
83     u_int32_t           s_size;
84     u_int32_t           s_scnptr;
85     u_int32_t           s_relptr;
86     u_int32_t           s_lnnoptr;
87     u_int16_t           s_nreloc;
88     u_int16_t           s_nlnno;
89     u_int32_t           s_flags;
90 } SCNHDR;
91 #define SCNHSZ  40
92
93 #define ROUNDUP(a,b)    ((((a) -1) | ((b) -1)) +1)
94
95 /*
96  * initialization subroutines
97  */
98
99 int 
100 open_elffile(char *filename)
101 {
102         int fileno = open(filename, O_RDONLY);
103
104         if (fileno < 0)
105                 err(1, "%s", filename);
106         return (fileno);
107 }
108
109
110 Elf64_Ehdr *
111 load_ehdr(int fileno)
112 {
113         Elf64_Ehdr *ehdr;
114         size_t bytes = sizeof(*ehdr);
115
116         ehdr = malloc(bytes);
117         if (ehdr) {
118                 lseek(fileno, 0, SEEK_SET);
119                 if (read(fileno, ehdr, bytes) != bytes)
120                         errx(1, "file truncated (ehdr)");
121         }
122         return (ehdr);
123 }
124
125 Elf64_Phdr *
126 load_phdr(int fileno, Elf64_Ehdr *ehdr)
127 {
128         size_t bytes = ehdr->e_phentsize * ehdr->e_phnum;
129         Elf64_Phdr *phdr = malloc(bytes);
130
131         if (phdr) {
132                 lseek(fileno, ehdr->e_phoff, SEEK_SET);
133                 if (read(fileno, phdr, bytes) != bytes)
134                         errx(1, "file truncated (phdr)");
135         }
136         return (phdr);
137 }
138
139 Elf64_Shdr *
140 load_shdr(int fileno, Elf64_Ehdr *ehdr)
141 {
142         size_t bytes = ehdr->e_shentsize * ehdr->e_shnum;
143         Elf64_Shdr *shdr = malloc(bytes);
144
145         if (shdr) {
146                 lseek(fileno, ehdr->e_shoff, SEEK_SET);
147                 if (read(fileno, shdr, bytes) != bytes)
148                         errx(1, "file truncated (shdr)");
149         }
150         return (shdr);
151 }
152
153 char *
154 find_shstrtable(int fileno, int sections, Elf64_Shdr *shdr)
155 {
156         size_t bytes;
157         char *shstrtab = NULL;
158         int i, shstrtabindex;
159
160         for (i = 0; shstrtab == NULL && i < sections; i++) {
161                 if (shdr[i].sh_type == 3 && shdr[i].sh_flags == 0) {
162                         shstrtabindex = i;
163
164                         bytes = shdr[shstrtabindex].sh_size;
165                         shstrtab = malloc(bytes);
166                         if (shstrtab == NULL)
167                                 errx(1, "malloc failed");
168                         lseek(fileno, shdr[shstrtabindex].sh_offset, SEEK_SET);
169                         read(fileno, shstrtab, bytes);
170
171                         if (strcmp (shstrtab + shdr[i].sh_name, ".shstrtab")) {
172                                 free(shstrtab);
173                                 shstrtab = NULL;
174                         }
175                 }
176         }
177         return (shstrtab);
178 }
179
180 int
181 open_exefile(char *filename)
182 {
183         int fileno = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0666);
184
185         if (fileno < 0)
186                 err(1, "%s", filename);
187         return (fileno);
188 }
189
190 /*
191  * utility subroutines 
192  */
193
194 static char *shstrtab;
195
196 char *
197 section_name(Elf64_Shdr *shdr, int i)
198 {
199         return (shstrtab + shdr[i].sh_name);
200 }
201
202 int
203 section_index(Elf64_Shdr *shdr, int sections, char *name)
204 {
205         int i;
206
207         for (i = 0; i < sections; i++)
208                 if (strcmp (name, section_name(shdr, i)) == 0)
209                         return (i);
210         return (-1);
211 }
212
213 /* first byte of section */
214 u_int64_t
215 section_start(Elf64_Shdr *shdr, int sections, char *name)
216 {
217         int i = section_index(shdr, sections, name);
218
219         if (i < 0)
220                 return (-1);
221         return (shdr[i].sh_addr);
222 }
223
224 /* last byte of section */
225 u_int64_t
226 section_end(Elf64_Shdr *shdr, int sections, char *name)
227 {
228         int i = section_index(shdr, sections, name);
229
230         if (i < 0)
231                 return (-1);
232         return (shdr[i].sh_addr + shdr[i].sh_size -1);
233 }
234
235 /* last byte of section */
236 u_int64_t
237 section_size(Elf64_Shdr *shdr, int sections, char *name)
238 {
239         int i = section_index(shdr, sections, name);
240
241         if (i < 0)
242                 return (-1);
243
244         return (shdr[i].sh_size);
245 }
246
247 /* file position of section start */
248 u_int64_t
249 section_fpos(Elf64_Shdr *shdr, int sections, char *name)
250 {
251         int i = section_index(shdr, sections, name);
252
253         if (i < 0)
254                 return (-1);
255         return (shdr[i].sh_offset);
256 }
257
258 void
259 usage(void)
260 {
261         fprintf(stderr, "usage: elf2exe infile outfile\n");
262         exit(1);
263 }
264
265 int
266 main(int argc, char** argv)
267 {
268         int infd, outfd, i;
269         Elf64_Ehdr *ehdr;
270         Elf64_Phdr *phdr;
271         Elf64_Shdr *shdr;
272         FILHDR filehdr;
273         AOUTHDR aouthdr;
274         SCNHDR textscn, datascn;
275         u_int64_t textstart, textsize, textsize2, textfsize, textfpos;
276         u_int64_t datastart, datasize, datafsize, datafpos;
277         u_int64_t bssstart, bsssize;
278         u_int64_t progentry;
279         char* p;
280         int sections;
281
282         if (argc != 3)
283                 usage();
284
285         infd = open_elffile(argv[1]);
286         ehdr = load_ehdr(infd);
287
288         if (ehdr == NULL)
289                 errx(1, "cannot read Elf Header\n");
290
291         sections = ehdr->e_shnum;
292         progentry = ehdr->e_entry;
293
294         phdr = load_phdr(infd, ehdr);
295         shdr = load_shdr(infd, ehdr);
296         outfd = open_exefile(argv[2]);
297
298         shstrtab = find_shstrtable(infd, sections, shdr);
299
300         for (i = 1; i < sections; i++) {
301                 printf("section %d (%s): "
302                     "type=%x flags=0%llx "
303                     "offs=%llx size=%llx addr=%llx\n",
304                     i, shstrtab + shdr[i].sh_name,
305                     shdr[i].sh_type, (long long)shdr[i].sh_flags,
306                     (long long)shdr[i].sh_offset, (long long)shdr[i].sh_size,
307                     (long long)shdr[i].sh_addr);
308         }
309
310         textstart = section_start(shdr, sections, ".text");
311         textsize  = section_size(shdr, sections,  ".text");
312         textsize2 = section_end(shdr, sections,  ".rodata") - textstart +1;
313         if (textsize < textsize2)
314                 textsize = textsize2;
315         textfsize = ROUNDUP(textsize, 512);
316         textfpos  = section_fpos(shdr, sections, ".text");
317
318         datastart = section_start(shdr, sections, ".data");
319         datasize  = section_start(shdr, sections, ".bss") - datastart;
320         datafsize = ROUNDUP(datasize, 512);
321         datafpos  = section_fpos(shdr, sections, ".data");
322
323         bssstart  = section_start(shdr, sections, ".bss");
324         bsssize   = section_size(shdr, sections, ".bss");
325
326         printf("text: %llx(%llx) @%llx  data: %llx(%llx) @%llx  "
327             "bss: %llx(%llx)\n",
328             (long long)textstart, (long long)textsize, (long long)textfpos,
329             (long long)datastart, (long long)datasize, (long long)datafpos,
330             (long long)bssstart, (long long)bsssize);
331
332         memset(&filehdr, 0, sizeof filehdr);
333         memset(&aouthdr, 0, sizeof aouthdr);
334         memset(&textscn, 0, sizeof textscn);
335         memset(&datascn, 0, sizeof datascn);
336
337         filehdr.f_magic = ALPHA_FMAGIC;
338         filehdr.f_nscns = 2;
339         filehdr.f_timdat = time(0);
340         filehdr.f_symptr = 0;
341         filehdr.f_nsyms = 0;
342         filehdr.f_opthdr = AOUTSZ;
343         filehdr.f_flags = 0x010f;
344
345         aouthdr.a_magic = ALPHA_AMAGIC;
346         aouthdr.a_vstamp = 0x5004;
347         aouthdr.a_tsize = textfsize;
348         aouthdr.a_dsize = datafsize;
349         aouthdr.a_bsize = bsssize;
350         aouthdr.a_entry = progentry;
351         aouthdr.a_text_start = textstart;
352         aouthdr.a_data_start = datastart;
353         aouthdr.a_bss_start = bssstart;
354
355         strcpy(textscn.s_name, ".text");
356         textscn.s_fill = textsize;
357         textscn.s_vaddr = textstart;
358         textscn.s_size = textfsize;
359         textscn.s_scnptr = 0x200;
360         textscn.s_relptr = 0;
361         textscn.s_lnnoptr = 0;
362         textscn.s_nreloc = 0;
363         textscn.s_nlnno = 0;
364         textscn.s_flags = 0x20;
365
366         strcpy(datascn.s_name, ".data");
367         datascn.s_fill = datasize;
368         datascn.s_vaddr = datastart;
369         datascn.s_size = datafsize;
370         datascn.s_scnptr = 0x200 + textfsize;
371         datascn.s_relptr = 0;
372         datascn.s_lnnoptr = 0;
373         datascn.s_nreloc = 0;
374         datascn.s_nlnno = 0;
375         datascn.s_flags = 0x40;
376
377         write(outfd, &filehdr, FILHSZ);
378         write(outfd, &aouthdr, AOUTSZ);
379         write(outfd, &textscn, SCNHSZ);
380         write(outfd, &datascn, SCNHSZ);
381
382         lseek(outfd, textscn.s_scnptr, SEEK_SET);
383         p = malloc(ROUNDUP(textsize, 512));
384         if (p == NULL)
385                 errx(1, "malloc failed");
386         memset(p, 0, ROUNDUP(textsize, 512));
387         lseek(infd, textfpos, SEEK_SET);
388         read(infd, p, textsize);
389         write(outfd, p, ROUNDUP(textsize, 512));
390         free(p);
391
392         lseek(outfd, datascn.s_scnptr, SEEK_SET);
393         p = malloc(ROUNDUP(datasize, 512));
394         if (p == NULL)
395                 errx(1, "malloc failed");
396         memset(p, 0, ROUNDUP(datasize, 512));
397         lseek(infd, datafpos, SEEK_SET);
398         read(infd, p, datasize);
399         write(outfd, p, ROUNDUP(datasize, 512));
400         free(p);
401
402         return (0);
403 }