1 /*
2  * arch/alpha/boot/tools/objstrip.c
3  *
4  * Strip the object file headers/trailers from an executable (ELF or ECOFF).
5  *
6  * Copyright (C) 1996 David Mosberger-Tang.
7  */
8 /*
9  * Converts an ECOFF or ELF object file into a bootable file.  The
10  * object file must be a OMAGIC file (i.e., data and bss follow immediatly
11  * behind the text).  See DEC "Assembly Language Programmer's Guide"
12  * documentation for details.  The SRM boot process is documented in
13  * the Alpha AXP Architecture Reference Manual, Second Edition by
14  * Richard L. Sites and Richard T. Witek.
15  */
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 
21 #include <sys/fcntl.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 
25 #include <linux/a.out.h>
26 #include <linux/coff.h>
27 #include <linux/param.h>
28 #include <linux/string.h>
29 #ifdef __ELF__
30 # include <linux/elf.h>
31 #endif
32 
33 /* bootfile size must be multiple of BLOCK_SIZE: */
34 #define BLOCK_SIZE	512
35 
36 const char * prog_name;
37 
38 
39 void
usage(void)40 usage (void)
41 {
42     fprintf(stderr,
43 	    "usage: %s [-v] -p file primary\n"
44 	    "       %s [-vb] file [secondary]\n", prog_name, prog_name);
45     exit(1);
46 }
47 
48 
49 int
main(int argc,char * argv[])50 main (int argc, char *argv[])
51 {
52     size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0;
53     int fd, ofd, i, j, verbose = 0, primary = 0;
54     char buf[8192], *inname;
55     struct exec * aout;		/* includes file & aout header */
56     long offset;
57 #ifdef __ELF__
58     struct elfhdr *elf;
59     struct elf_phdr *elf_phdr;	/* program header */
60     unsigned long long e_entry;
61 #endif
62 
63     prog_name = argv[0];
64 
65     for (i = 1; i < argc && argv[i][0] == '-'; ++i) {
66 	for (j = 1; argv[i][j]; ++j) {
67 	    switch (argv[i][j]) {
68 	      case 'v':
69 		  verbose = ~verbose;
70 		  break;
71 
72 	      case 'b':
73 		  pad = BLOCK_SIZE;
74 		  break;
75 
76 	      case 'p':
77 		  primary = 1;		/* make primary bootblock */
78 		  break;
79 	    }
80 	}
81     }
82 
83     if (i >= argc) {
84 	usage();
85     }
86     inname = argv[i++];
87 
88     fd = open(inname, O_RDONLY);
89     if (fd == -1) {
90 	perror("open");
91 	exit(1);
92     }
93 
94     ofd = 1;
95     if (i < argc) {
96 	ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666);
97 	if (fd == -1) {
98 	    perror("open");
99 	    exit(1);
100 	}
101     }
102 
103     if (primary) {
104 	/* generate bootblock for primary loader */
105 
106 	unsigned long bb[64], sum = 0;
107 	struct stat st;
108 	off_t size;
109 	int i;
110 
111 	if (ofd == 1) {
112 	    usage();
113 	}
114 
115 	if (fstat(fd, &st) == -1) {
116 	    perror("fstat");
117 	    exit(1);
118 	}
119 
120 	size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1);
121 	memset(bb, 0, sizeof(bb));
122 	strcpy((char *) bb, "Linux SRM bootblock");
123 	bb[60] = size / BLOCK_SIZE;	/* count */
124 	bb[61] = 1;			/* starting sector # */
125 	bb[62] = 0;			/* flags---must be 0 */
126 	for (i = 0; i < 63; ++i) {
127 	    sum += bb[i];
128 	}
129 	bb[63] = sum;
130 	if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) {
131 	    perror("boot-block write");
132 	    exit(1);
133 	}
134 	printf("%lu\n", size);
135 	return 0;
136     }
137 
138     /* read and inspect exec header: */
139 
140     if (read(fd, buf, sizeof(buf)) < 0) {
141 	perror("read");
142 	exit(1);
143     }
144 
145 #ifdef __ELF__
146     elf = (struct elfhdr *) buf;
147 
148     if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) == 0) {
149 	if (elf->e_type != ET_EXEC) {
150 	    fprintf(stderr, "%s: %s is not an ELF executable\n",
151 		    prog_name, inname);
152 	    exit(1);
153 	}
154 	if (!elf_check_arch(elf)) {
155 	    fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n",
156 		    prog_name, elf->e_machine);
157 	    exit(1);
158 	}
159 	if (elf->e_phnum != 1) {
160 	    fprintf(stderr,
161 		    "%s: %d program headers (forgot to link with -N?)\n",
162 		    prog_name, elf->e_phnum);
163 	}
164 
165 	e_entry = elf->e_entry;
166 
167 	lseek(fd, elf->e_phoff, SEEK_SET);
168 	if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) {
169 	    perror("read");
170 	    exit(1);
171 	}
172 
173 	elf_phdr = (struct elf_phdr *) buf;
174 	offset	 = elf_phdr->p_offset;
175 	mem_size = elf_phdr->p_memsz;
176 	fil_size = elf_phdr->p_filesz;
177 
178 	/* work around ELF bug: */
179 	if (elf_phdr->p_vaddr < e_entry) {
180 	    unsigned long delta = e_entry - elf_phdr->p_vaddr;
181 	    offset   += delta;
182 	    mem_size -= delta;
183 	    fil_size -= delta;
184 	    elf_phdr->p_vaddr += delta;
185 	}
186 
187 	if (verbose) {
188 	    fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
189 		    prog_name, (long) elf_phdr->p_vaddr,
190 		    elf_phdr->p_vaddr + fil_size, offset);
191 	}
192     } else
193 #endif
194     {
195 	aout = (struct exec *) buf;
196 
197 	if (!(aout->fh.f_flags & COFF_F_EXEC)) {
198 	    fprintf(stderr, "%s: %s is not in executable format\n",
199 		    prog_name, inname);
200 	    exit(1);
201 	}
202 
203 	if (aout->fh.f_opthdr != sizeof(aout->ah)) {
204 	    fprintf(stderr, "%s: %s has unexpected optional header size\n",
205 		    prog_name, inname);
206 	    exit(1);
207 	}
208 
209 	if (N_MAGIC(*aout) != OMAGIC) {
210 	    fprintf(stderr, "%s: %s is not an OMAGIC file\n",
211 		    prog_name, inname);
212 	    exit(1);
213 	}
214 	offset = N_TXTOFF(*aout);
215 	fil_size = aout->ah.tsize + aout->ah.dsize;
216 	mem_size = fil_size + aout->ah.bsize;
217 
218 	if (verbose) {
219 	    fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n",
220 		    prog_name, aout->ah.text_start,
221 		    aout->ah.text_start + fil_size, offset);
222 	}
223     }
224 
225     if (lseek(fd, offset, SEEK_SET) != offset) {
226 	perror("lseek");
227 	exit(1);
228     }
229 
230     if (verbose) {
231 	fprintf(stderr, "%s: copying %lu byte from %s\n",
232 		prog_name, (unsigned long) fil_size, inname);
233     }
234 
235     tocopy = fil_size;
236     while (tocopy > 0) {
237 	n = tocopy;
238 	if (n > sizeof(buf)) {
239 	    n = sizeof(buf);
240 	}
241 	tocopy -= n;
242 	if ((size_t) read(fd, buf, n) != n) {
243 	    perror("read");
244 	    exit(1);
245 	}
246 	do {
247 	    nwritten = write(ofd, buf, n);
248 	    if ((ssize_t) nwritten == -1) {
249 		perror("write");
250 		exit(1);
251 	    }
252 	    n -= nwritten;
253 	} while (n > 0);
254     }
255 
256     if (pad) {
257 	mem_size = ((mem_size + pad - 1) / pad) * pad;
258     }
259 
260     tocopy = mem_size - fil_size;
261     if (tocopy > 0) {
262 	fprintf(stderr,
263 		"%s: zero-filling bss and aligning to %lu with %lu bytes\n",
264 		prog_name, pad, (unsigned long) tocopy);
265 
266 	memset(buf, 0x00, sizeof(buf));
267 	do {
268 	    n = tocopy;
269 	    if (n > sizeof(buf)) {
270 		n = sizeof(buf);
271 	    }
272 	    nwritten = write(ofd, buf, n);
273 	    if ((ssize_t) nwritten == -1) {
274 		perror("write");
275 		exit(1);
276 	    }
277 	    tocopy -= nwritten;
278 	} while (tocopy > 0);
279     }
280     return 0;
281 }
282