1 static char rcsid[] = "$Id: elf2smx.c,v 1.1 1996/06/04 08:29:40 paul Exp $";
2
3 /*
4 * elf2smx
5 *
6 * This Solaris utility program converts a Solaris object file (in ELF
7 * format) into an smx object file. Reading through the details of
8 * the elf file, creating a header for the smx file, then writing
9 * text and data segments for the smx file. The text and read-only
10 * data segments from the elf file are combined into a single text segment
11 * in the smx file.
12 */
13
14 #include <stdio.h>
15 #include <fcntl.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <assert.h>
19 #include <limits.h>
20
21 #include <libelf.h>
22
23 #include "../../include/minix/config.h"
24 #undef NULL
25 #include "../../include/minix/const.h"
26 #include "../../include/ansi.h"
27 #include "../../include/a.out.h"
28
29
30 /*
31 * The section types that can be handled---indices into the secn_data array,
32 * which is used to hold segment details read from the elf file.
33 */
34
35 #define TEXT 0
36 #define DATA 1
37 #define RODATA 2
38 #define BSS 3
39 #define NUM_AREAS (BSS + 1)
40
41 struct secn_data {
42 int s_secnum;
43 Elf32_Addr s_addr;
44 Elf32_Word s_size;
45 } secn_data[NUM_AREAS];
46
47
48 static int debug = 0;
49
50 static char *progname;
51
52 /*
53 * Local functions
54 */
55 static int elf2smx(char *input, char *output, int stacksize);
56 static int do_scn(Elf32_Shdr *shdr, char *name, int secnum);
57 static int write_file(int outfile, Elf *prog, long entry, long stack);
58 static int advance(int outfile, long how_much);
59 static int write_secn(int outfile, Elf *prog, int sec_ind);
60 static void usage(void);
61
62
63 /*
64 * Function: main
65 * Parameters: argc, argv - see usage message for command line arguments
66 *
67 * Validates the command line arguments, then calls elf2smx to do the
68 * conversion.
69 */
70 int main(int argc, char *argv[])
71 {
72 int stacksize = -1;
73 int option;
74 char *end, *p;
75 int num;
76
77 progname = argv[0];
78
79 while ((option = getopt(argc, argv, "S:d")) != -1) {
80 switch(option) {
81 case 'S':
82 /*
83 * The following piece of code was taken from the minix
84 * install command where it processes a specified stack size.
85 */
86 p = optarg;
87 stacksize = strtol(p, &end, 0);
88 if (end == p || stacksize < 0) usage();
89 p = end;
90 while (*p != 0) {
91 switch (*p++) {
92 case 'm':
93 case 'M': num = 1024 * 1024; break;
94 case 'k':
95 case 'K': num = 1024; break;
96 case 'w':
97 case 'W': num = 4; break;
98 case 'b':
99 case 'B': num = 1; break;
100 default: usage();
101 }
102 if (stacksize > LONG_MAX / num) usage();
103 stacksize *= num;
104 }
105 break;
106
107 case 'd':
108 debug = 1;
109 break;
110
111 default:
112 /*
113 * unknown argument.
114 */
115 usage();
116 break;
117 }
118 }
119
120 argc -= optind; /* set to the number of args remaining */
121 argv += optind; /* step over already processed args */
122 if (argc != 2) {
123 /*
124 * Whoops - need exactly two files to process
125 */
126 usage();
127 }
128
129 if (elf2smx(argv[0], argv[1], stacksize) == -1) {
130 fprintf(stderr, "%s: conversion from %s to %s failed\n", progname,
131 argv[0], argv[1]);
132 unlink(argv[1]);
133 }
134 return 0;
135 }
136
137
138 /*
139 * Function: elf2smx
140 * Parameters: input - elf file to convert
141 * output - name to give the smx executable
142 * stacksize - used to calculate how the total address space
143 * needs of the smx executable.
144 * Returns: 0 on success; -1 on failure
145 *
146 * Open the input and output files. Scan through the elf file, recording
147 * details of the segments of interest, the generate the smx file from
148 * those segments.
149 */
150 static int elf2smx(char *input, char *output, int stacksize)
151 {
152 int fd;
153 int outfile;
154 int prog_cnt = 0;
155 int secnum;
156
157 Elf *prog, *file;
158 Elf32_Ehdr *ehdr;
159 Elf32_Shdr *shdr;
160 Elf_Scn *scn;
161 Elf_Cmd cmd;
162
163 /*
164 * open the Solaris object file
165 */
166 if ((fd = open(input, O_RDONLY)) == -1) {
167 fprintf(stderr, "Can't open ELF file %s\n", input);
168 return -1;
169 }
170 if (elf_version(EV_CURRENT) == EV_NONE) {
171 return -1;
172 }
173
174 /*
175 * Create the SunOS output file. Delete the current file under that
176 * name (if any).
177 */
178 (void) unlink(output);
179 outfile = open(output, O_RDWR | O_CREAT, 0666);
180 if (outfile == -1) {
181 fprintf(stderr, "Can't open %s\n", output);
182 return -1;
183 }
184
185 /*
186 * Read and get details about each program (should be only 1)
187 */
188 cmd = ELF_C_READ;
189 if ((file = elf_begin(fd, cmd, (Elf *)0)) == 0) {
190 return -1;
191 }
192 while ((prog = elf_begin(fd, cmd, file)) != 0) {
193 if (++prog_cnt > 1) {
194 fprintf(stderr,
195 "%s: second program found in ELF file; aborting after converting first\n",
196 progname);
197 break;
198 }
199
200 if ((ehdr = elf32_getehdr(prog)) == 0) {
201 return -1;
202 }
203
204 /*
205 * Read and get details about each section
206 */
207 scn = (Elf_Scn *)0;
208 secnum = 0;
209 while ((scn = elf_nextscn(prog, scn)) != 0) {
210 secnum++;
211 shdr = elf32_getshdr(scn);
212 if (do_scn(shdr, elf_strptr(file, ehdr->e_shstrndx,
213 (size_t)shdr->sh_name), secnum)== -1) {
214 return -1;
215 }
216 }
217
218 /*
219 * Write the SunOS object file
220 */
221 if (write_file(outfile, prog, ehdr->e_entry, stacksize)== -1) {
222 return -1;
223 }
224
225 cmd = elf_next(prog);
226 elf_end(prog);
227 }
228
229 elf_end(file);
230 close(outfile);
231 return prog_cnt == 1 ? 0 : -1;
232 }
233
234
235 /*
236 * Function: do_scn
237 * Parameters: shdr - elf section header struct
238 * name - elf section name
239 * secnum - section number
240 * Returns: -1 on error, 0 otherwise
241 *
242 * If the ELF section is one of the interesting ones, then record its
243 * details in the secn_data array.
244 */
245 static int do_scn(Elf32_Shdr *shdr, char *name, int secnum)
246 {
247 int arr_ind;
248
249 if (debug) printf("'%s'\n", name? name: "(null)");
250
251 /*
252 * Set arr_ind to indicate the section we are dealing with.
253 */
254 if (!strcmp(".text", name)) {
255 arr_ind = TEXT;
256 } else if (!strcmp(".rodata", name)) {
257 arr_ind = RODATA;
258 } else if (!strcmp(".data", name)) {
259 arr_ind = DATA;
260 } else if (!strcmp(".bss", name)) {
261 arr_ind = BSS;
262 } else {
263 arr_ind = -1;
264 }
265
266 if (arr_ind != -1) {
267 /*
268 * If we have one of the sections we are interested in,
269 * record its details. We only expect one segment of each type,
270 * so give an error message if we encounter a second.
271 */
272 if (secn_data[arr_ind].s_secnum != 0) {
273 fprintf(stderr, "%s: second section of type %s encountered\n",
274 progname, name);
275 return -1;
276 }
277 secn_data[arr_ind].s_secnum = secnum;
278 secn_data[arr_ind].s_addr = shdr->sh_addr;
279 secn_data[arr_ind].s_size = shdr->sh_size;
280 if (debug) {
281 printf(" Addr = 0x%x, sh_size = 0x%x\n\n",
282 (unsigned) secn_data[arr_ind].s_addr,
283 (unsigned) secn_data[arr_ind].s_size);
284 }
285 }
286 return 0;
287 }
288
289
290 /*
291 * Function: write_file
292 * Parameters: outfile - descriptor onto which the output file is to be
293 * written.
294 * prog - elf input file
295 * entry - virtual address of program entry point
296 * stack - gap to leave after bss for heap and stack
297 * Returns: 0 on success, -1 on failure
298 *
299 * The smx header is initialised and written. Then the smx text segment
300 * is written (elf text + read-only data segments), then the data segment.
301 * Both smx text and data segments musy be click-aligned, and the
302 * smx text segment must be a multiple of the click size.
303 */
304 static int write_file(int outfile, Elf *prog, long entry, long stack)
305 {
306 struct exec header;
307 long bytes_written;
308
309 /*
310 * Some sections may not have been present in the ELF file. So long as
311 * we have a text segment and a data segment we're in business.
312 */
313 if (secn_data[TEXT].s_secnum == 0 || secn_data[DATA].s_secnum == 0) {
314 fprintf(stderr, "%s: Missing text or data segment in ELF file\n",
315 progname);
316 return -1;
317 }
318 /*
319 * If there is no read-only data segment set the read-only data
320 * segment address to the end of the text segment
321 * so that the calculations below still work.
322 */
323 if (secn_data[RODATA].s_secnum == 0) {
324 secn_data[RODATA].s_addr = secn_data[TEXT].s_addr +
325 secn_data[TEXT].s_size;
326 }
327
328 /* Create the header */
329 header.a_magic[0] = A_MAGIC0;
330 header.a_magic[1] = A_MAGIC1;
331 header.a_flags = A_EXEC | A_SEP; /* Executable, separate instr and data */
332 header.a_cpu = A_SUNOS;
333 header.a_hdrlen = sizeof(header);
334 header.a_unused = 0;
335 header.a_version = 0;
336 header.a_tbase = downclick(secn_data[TEXT].s_addr);
337 header.a_text = upclick(secn_data[RODATA].s_addr +
338 secn_data[RODATA].s_size) - header.a_tbase;
339 header.a_dbase = downclick(secn_data[DATA].s_addr);
340 header.a_data = secn_data[DATA].s_addr + secn_data[DATA].s_size -
341 header.a_dbase;
342 header.a_bss = secn_data[BSS].s_size;
343 header.a_entry = entry;
344 header.a_syms = 0;
345 header.a_trsize = header.a_drsize = 0;
346 if (stack >= 0) {
347 /*
348 * Use the user specified "gap".
349 */
350 header.a_total = header.a_data + header.a_bss + stack;
351 } else {
352 /*
353 * No gap specified. Use 4 clicks or 20% of the text segment
354 * size, whichever is greater.
355 */
356 header.a_total = header.a_data + header.a_bss +
357 (((header.a_text / 5) < CLICK_SIZE * 4) ? CLICK_SIZE * 4 :
358 (header.a_text / 5));
359 }
360 write(outfile, &header, sizeof(header));
361
362 /*
363 * Write the text segment. If the elf text segment is not click aligned,
364 * then we have to leave some space before the elf text segment is
365 * written. There may be space between the text and read-only data
366 * and space after the read-only data to get the smx text segment
367 * click aligned.
368 */
369 bytes_written = advance(outfile, secn_data[TEXT].s_addr - header.a_tbase);
370 bytes_written += write_secn(outfile, prog, TEXT);
371 bytes_written += advance(outfile, secn_data[RODATA].s_addr -
372 header.a_tbase - bytes_written);
373 bytes_written += write_secn(outfile, prog, RODATA);
374 (void) advance(outfile, header.a_text - bytes_written);
375
376 /*
377 * Write the data segment, again leaving space if the data segment
378 * does not start on a click boundary,
379 */
380 (void) advance(outfile, secn_data[DATA].s_addr - header.a_dbase);
381 (void) write_secn(outfile, prog, DATA);
382 return 0;
383 }
384
385
386 /*
387 * Function: advance
388 * Parameters: outfile - file to advance in
389 * how_much - the number of bytes to advance
390 * Returns: how_much
391 */
392 static int advance(int outfile, long how_much)
393 {
394 if (how_much > 0) {
395 if (lseek(outfile, how_much, SEEK_CUR) == -1) {
396 fprintf(stderr, "%s: lseek failed\n", progname);
397 exit(1);
398 }
399 return how_much;
400 }
401 return 0;
402 }
403
404
405 /*
406 * Function: write_secn
407 * Parameters: outfile - file to write to
408 * prog - elf file to copy the segment from
409 * sec_ind - section to write
410 * Returns: the number of bytes written
411 *
412 * Write section "sec_ind" from elf file "prog" to "out_file".
413 */
414 static int write_secn(int outfile, Elf *prog, int sec_ind)
415 {
416 Elf_Scn *scn;
417 Elf_Data *data;
418
419 if (secn_data[sec_ind].s_secnum == 0) {
420 return 0; /* section is empty */
421 }
422
423 scn = elf_getscn(prog, secn_data[sec_ind].s_secnum);
424 data = elf_getdata(scn, 0);
425 if (data == 0) {
426 fprintf(stderr, "%s: error getting elf section data\n", progname);
427 exit(1);
428 }
429 assert(data->d_size == secn_data[sec_ind].s_size);
430 if (write(outfile, data->d_buf, data->d_size) != data->d_size) {
431 fprintf(stderr, "%s: error writing segment\n", progname);
432 exit(1);
433 }
434
435 return data->d_size;
436 }
437
438
439 /*
440 * Function: usage
441 */
442 static void usage(void)
443 {
444 fprintf(stderr,
445 "Usage: %s [-d] [-S stack_size] solaris-filename sunos-filename\n",
446 progname);
447 exit(1);
448 }
449
450
451
452
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.