~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Minix Cross Reference
Minix/Solaris/elf2smx.c


  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.