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