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 | format: "usage: %s [-v] -p file primary\n" |
47 | " %s [-vb] file [secondary]\n" , prog_name, prog_name); |
48 | exit(status: 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(file: inname, O_RDONLY); |
92 | if (fd == -1) { |
93 | perror(s: "open" ); |
94 | exit(status: 1); |
95 | } |
96 | |
97 | ofd = 1; |
98 | if (i < argc) { |
99 | ofd = open(file: argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666); |
100 | if (ofd == -1) { |
101 | perror(s: "open" ); |
102 | exit(status: 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: fd, buf: &st) == -1) { |
119 | perror(s: "fstat" ); |
120 | exit(status: 1); |
121 | } |
122 | |
123 | size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1); |
124 | memset(s: bb, c: 0, n: sizeof(bb)); |
125 | strcpy(dest: (char *) bb, src: "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(fd: ofd, buf: bb, n: sizeof(bb)) != sizeof(bb)) { |
134 | perror(s: "boot-block write" ); |
135 | exit(status: 1); |
136 | } |
137 | printf(format: "%lu\n" , size); |
138 | return 0; |
139 | } |
140 | |
141 | /* read and inspect exec header: */ |
142 | |
143 | if (read(fd: fd, buf: buf, nbytes: sizeof(buf)) < 0) { |
144 | perror(s: "read" ); |
145 | exit(status: 1); |
146 | } |
147 | |
148 | #ifdef __ELF__ |
149 | elf = (struct elfhdr *) buf; |
150 | |
151 | if (memcmp(s1: &elf->e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { |
152 | if (elf->e_type != ET_EXEC) { |
153 | fprintf(stderr, format: "%s: %s is not an ELF executable\n" , |
154 | prog_name, inname); |
155 | exit(status: 1); |
156 | } |
157 | if (!elf_check_arch(elf)) { |
158 | fprintf(stderr, format: "%s: is not for this processor (e_machine=%d)\n" , |
159 | prog_name, elf->e_machine); |
160 | exit(status: 1); |
161 | } |
162 | if (elf->e_phnum != 1) { |
163 | fprintf(stderr, |
164 | format: "%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: fd, offset: elf->e_phoff, SEEK_SET); |
171 | if (read(fd: fd, buf: buf, nbytes: sizeof(*elf_phdr)) != sizeof(*elf_phdr)) { |
172 | perror(s: "read" ); |
173 | exit(status: 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, format: "%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, format: "%s: %s is not in executable format\n" , |
202 | prog_name, inname); |
203 | exit(status: 1); |
204 | } |
205 | |
206 | if (aout->fh.f_opthdr != sizeof(aout->ah)) { |
207 | fprintf(stderr, format: "%s: %s has unexpected optional header size\n" , |
208 | prog_name, inname); |
209 | exit(status: 1); |
210 | } |
211 | |
212 | if (N_MAGIC(*aout) != OMAGIC) { |
213 | fprintf(stderr, format: "%s: %s is not an OMAGIC file\n" , |
214 | prog_name, inname); |
215 | exit(status: 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, format: "%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: fd, offset: offset, SEEK_SET) != offset) { |
229 | perror(s: "lseek" ); |
230 | exit(status: 1); |
231 | } |
232 | |
233 | if (verbose) { |
234 | fprintf(stderr, format: "%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: fd, buf: buf, nbytes: n) != n) { |
246 | perror(s: "read" ); |
247 | exit(status: 1); |
248 | } |
249 | do { |
250 | nwritten = write(fd: ofd, buf: buf, n: n); |
251 | if ((ssize_t) nwritten == -1) { |
252 | perror(s: "write" ); |
253 | exit(status: 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 | format: "%s: zero-filling bss and aligning to %lu with %lu bytes\n" , |
267 | prog_name, pad, (unsigned long) tocopy); |
268 | |
269 | memset(s: buf, c: 0x00, n: sizeof(buf)); |
270 | do { |
271 | n = tocopy; |
272 | if (n > sizeof(buf)) { |
273 | n = sizeof(buf); |
274 | } |
275 | nwritten = write(fd: ofd, buf: buf, n: n); |
276 | if ((ssize_t) nwritten == -1) { |
277 | perror(s: "write" ); |
278 | exit(status: 1); |
279 | } |
280 | tocopy -= nwritten; |
281 | } while (tocopy > 0); |
282 | } |
283 | return 0; |
284 | } |
285 | |