Allocate kernel and ramdisk as low as possible
[yaboot.git] / util / elfextract.c
1 /*
2  *  elfextract.c - Extract the loadable program segment from an elf file.
3  *
4  *  Copyright 1996 Paul Mackerras.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  */
20
21 #include <stdio.h>
22 #include <linux/elf.h>
23
24 FILE *fi, *fo;
25 char *ni, *no;
26 char buf[65536];
27
28 void
29 rd(void *buf, int len)
30 {
31     int nr;
32
33     nr = fread(buf, 1, len, fi);
34     if (nr == len)
35         return;
36     if (ferror(fi))
37         fprintf(stderr, "%s: read error\n", ni);
38     else
39         fprintf(stderr, "%s: short file\n", ni);
40     exit(1);
41 }
42
43 int
44 main(int ac, char **av)
45 {
46     unsigned nb, len, i;
47     Elf32_Ehdr eh;
48     Elf32_Phdr ph;
49     unsigned long phoffset = 0;
50     unsigned long phsize = 0;
51     unsigned long prevaddr = 0;
52
53     if (ac > 3 || (ac > 1 && av[1][0] == '-')) {
54         fprintf(stderr, "Usage: %s [elf-file [image-file]]\n", av[0]);
55         exit(0);
56     }
57
58     fi = stdin;
59     ni = "(stdin)";
60     fo = stdout;
61     no = "(stdout)";
62
63     if (ac > 1) {
64         ni = av[1];
65         fi = fopen(ni, "rb");
66         if (fi == NULL) {
67             perror(ni);
68             exit(1);
69         }
70     }
71
72     rd(&eh, sizeof(eh));
73     if (eh.e_ident[EI_MAG0] != ELFMAG0
74         || eh.e_ident[EI_MAG1] != ELFMAG1
75         || eh.e_ident[EI_MAG2] != ELFMAG2
76         || eh.e_ident[EI_MAG3] != ELFMAG3) {
77         fprintf(stderr, "%s: not an ELF file\n", ni);
78         exit(1);
79     }
80
81     fseek(fi, eh.e_phoff, 0);
82     phsize = 0;
83     for (i = 0; i < eh.e_phnum; ++i) {
84         rd(&ph, sizeof(ph));
85         if (ph.p_type != PT_LOAD)
86             continue;
87         if (phsize == 0 || prevaddr == 0) {
88             phoffset = ph.p_offset;
89             phsize = ph.p_filesz;
90         } else
91             phsize = ph.p_offset + ph.p_filesz - phoffset;
92         prevaddr = ph.p_vaddr;
93     }
94     if (phsize == 0) {
95         fprintf(stderr, "%s: doesn't have a loadable segment\n", ni);
96         exit(1);
97     }
98
99     if (ac > 2) {
100         no = av[2];
101         fo = fopen(no, "wb");
102         if (fo == NULL) {
103             perror(no);
104             exit(1);
105         }
106     }
107
108     fseek(fi, phoffset, 0);
109     for (len = phsize; len != 0; len -= nb) {
110         nb = len;
111         if (nb > sizeof(buf))
112             nb = sizeof(buf);
113         rd(buf, nb);
114         if (fwrite(buf, 1, nb, fo) != nb) {
115             fprintf(stderr, "%s: write error\n", no);
116             exit(1);
117         }
118     }
119
120     fclose(fo);
121     fclose(fi);
122     exit(0);
123 }