f84dec68767276fa3b4a3807e5f95a9c09716648
[mw/micromonitor-lm32.git] / umon_main / host / src / utils / elf.c
1 /* elf.c:
2  * Perform some dumps/displays/conversions on the elf file format.
3  *
4  * General notice:
5  * This code is part of a boot-monitor package developed as a generic base
6  * platform for embedded system designs.  As such, it is likely to be
7  * distributed to various projects beyond the control of the original
8  * author.  Please notify the author of any enhancements made or bugs found
9  * so that all may benefit from the changes.  In addition, notification back
10  * to the author will allow the new user to pick up changes that may have
11  * been made by other users after this version of the code was distributed.
12  *
13  * Author:      Ed Sutter
14  * email:       esutter@lucent.com
15  * phone:       908-582-2351
16  */
17 #include <stdio.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include "elf.h"
26 #include "utils.h"
27 #include "../zlib/zlib.h"
28
29 #ifndef O_BINARY
30 #define O_BINARY 0
31 #endif
32
33 #define USE_OFFSET_DELTA        0
34
35 void ZipElfSections(int), ElfToBinary(char *);
36 void StripElfFile(char *,char *), ShowElfMap(long);
37 void ShowAppend(void), ShowElfHdr(void), ShowSections(int);
38 Elf32_Half GetElfSectionHdrs(void);
39 struct elf_fhdr *GetElfFileHdr(struct elf_fhdr *);
40 char *VerboseShtype(unsigned long); 
41 char *VerboseShflags(unsigned long), *GetElfSectionName(unsigned long);
42
43 struct  elf_fhdr Ehdr;
44 struct  elf_shdr *ScnTbl;
45 struct  elf_phdr *PhdrTbl;
46 char    *elfFname;
47 unsigned char PadByte;
48 int     elfFD, debug, xdebug, Ecvt, verbose, insertPAD;
49 int             remove_zouts = 1;
50
51 /* open verbosity: */
52 #define SHOWELFHDR              0x0001
53 #define SHOWSECTIONS    0x0002
54 #define SHOWMAP                 0x0004
55 #define SHOWMAPOFFSET   0x0008
56 #define SHOWAPPEND              0x0010
57 #define SHOWPRGMHDR             0x0020
58 #define SHOWMAPNONZERO  0x0040
59
60 /* The Linux box that I tried to build this on did not have tell(),
61  * so this is a very inefficient equivalent...
62  * Originally, I thought lseek(fd,0,SEEK_CUR) would work, but
63  * that generates an error on linux due to a bad argument; apparently
64  * it doesn't like the value of 0 for the offset when 'whence' is set to
65  * SEEK_CUR.
66  */
67 #ifndef BUILD_WITH_VCC
68 long
69 tell(int fd)
70 {
71         Lseek(fd,1,SEEK_CUR);
72         return(Lseek(fd,-1,SEEK_CUR));
73 }
74 #endif
75
76 void
77 ShowAppend(void)
78 {
79         int     i;
80         char    c;
81         Elf32_Word      maxsize;
82         Elf32_Off       maxoff;
83         struct  elf_shdr        *eshdr;
84
85         /* Find the highest offset then seek to the end of that section. This */
86         /* should be the end of the REAL data in the elf file.  Any remaining */
87         /* stuff has been appended (hopefully!). */
88         maxoff = 0;
89         for(i=0;i<Ehdr.e_shnum;i++) {
90                 eshdr = &ScnTbl[i];
91                 if (eshdr->sh_offset > maxoff) {
92                         maxoff = eshdr->sh_offset;
93                         maxsize = eshdr->sh_size;
94                 }
95         }
96         Lseek(elfFD,maxoff+maxsize,SEEK_SET);
97         while(1) {
98                 if (read(elfFD,&c,1) != 1)
99                         break;
100                 putchar(c);
101         }
102 }
103
104 void
105 ShowElfHdr(void)
106 {
107         int     i, j;
108
109         printf("\t\tELF FILE HEADER\n");
110         printf("E_IDENT (hex):          ");
111         for(i=0;i<EI_NIDENT;i++)
112                 printf("%02x ",Ehdr.e_ident[i]);
113         printf("\n");
114         printf("File Type:                      0x%x\n",Ehdr.e_type);
115         printf("Machine:                        0x%x\n",Ehdr.e_machine);
116         printf("Version:                        0x%x\n",Ehdr.e_version);
117         printf("Entrypoint:                     0x%08x\n",Ehdr.e_entry);
118         printf("Program Hdr Tbl Offset:         0x%x\n",Ehdr.e_phoff);
119         printf("Section Hdr Tbl Offset:         0x%x\n",Ehdr.e_shoff);
120         printf("Processor-specific flags:       0x%08x\n",Ehdr.e_flags);
121         printf("ELF Header size:                %u\n",Ehdr.e_ehsize);
122         printf("Size of 1 Pgm Hdr Entry:        %u\n",Ehdr.e_phentsize);
123         printf("# of entries in Pgm Hdr Tbl:    %u\n",Ehdr.e_phnum);
124         printf("Size of 1 Scn Hdr Entry:        %u\n",Ehdr.e_shentsize);
125         printf("# of entries in Scn Hdr Tbl:    %u\n",Ehdr.e_shnum);
126         printf("ScnHdr string Tbl Index:        0x%x\n",Ehdr.e_shstrndx);
127 }
128
129 void
130 ShowProgramHdrTbl(int verbose)
131 {
132         int     i, j;
133
134         printf("\t\tProgram Header Table:\n");
135         for(i=0;i<Ehdr.e_phnum;i++) {
136                 printf("PHDR[%d]:\n",i);
137                 printf("p_type:      0x%lx\n",PhdrTbl[i].p_type);
138                 printf("p_offset:    0x%lx\n",PhdrTbl[i].p_offset);
139                 printf("p_vaddr:     0x%lx\n",PhdrTbl[i].p_vaddr);
140                 printf("p_paddr:     0x%lx\n",PhdrTbl[i].p_paddr);
141                 printf("p_filesz:    0x%lx\n",PhdrTbl[i].p_filesz);
142                 printf("p_memsz:     0x%lx\n",PhdrTbl[i].p_memsz);
143                 printf("p_flags:     0x%lx\n",PhdrTbl[i].p_flags);
144                 printf("p_align:     0x%lx\n",PhdrTbl[i].p_align);
145         }
146 }
147
148 void
149 ShowSections(int verbose)
150 {
151         int     i;
152         unsigned long   size;
153         char    buf[32];
154         struct  elf_shdr        *eshdr;
155
156         if (debug >= 2)
157                 fprintf(stderr,"ShowSections()\n");
158
159         for(i=0;i<Ehdr.e_shnum;i++) {
160                 eshdr = &ScnTbl[i];
161                 size = eshdr->sh_size;
162                 if (size)
163                         size--;
164                 printf("%10s: 0x%08x..0x%08x (%ld bytes) %s %s\n",
165                         GetElfSectionName(eshdr->sh_name),
166                         eshdr->sh_addr,eshdr->sh_addr+size,eshdr->sh_size,
167                         VerboseShflags(eshdr->sh_flags),
168                         VerboseShtype(eshdr->sh_type));
169                 if (verbose) {
170                         printf("         offset=   0x%08x, link=   0x%08x, info=0x%08x\n",
171                                 eshdr->sh_offset, eshdr->sh_link, eshdr->sh_info);
172                         printf("         addralign=0x%08x, entsize=0x%08x\n\n",
173                                 eshdr->sh_addralign, eshdr->sh_entsize);
174                 }
175         }
176 }
177
178 /* FindLowestSectionInFile():
179  * The section table (ScnTbl[] array) contains a list of all sections in
180  * the ELF file.  I had thought that this table listed the sections
181  * in the same order as they exist in the file (meaning that the section
182  * pointed to by ScnTbl[1] was before the section pointed to by ScnTbl[2]).
183  * Turns out that this is not necessarily the case, so this function simply
184  * returns the offset to the lowest section in the file.
185  */
186 long
187 FindLowestSectionInFile(void)
188 {
189         int     i;
190         Elf32_Off       lowest_offset;
191
192         lowest_offset = 0xffffffff;
193         for(i=1;i<Ehdr.e_shnum;i++) {
194                 if ((ScnTbl[i].sh_size) &&
195                         (ScnTbl[i].sh_offset < lowest_offset))
196                         lowest_offset = ScnTbl[i].sh_offset;
197         }
198         if (debug >= 1)
199                 fprintf(stderr,"lowest section in file = 0x%lx\n",lowest_offset);
200         return(lowest_offset);
201 }
202
203 /* ZipElfSections():
204  * First pass...
205  *   Create one file of compressed data for each section to be compressed.
206  * Second pass...
207  *   Replace each original section with the data from the compressed file
208  *   and adjust header information appropriately.
209  */
210 void
211 ZipElfSections(int zlevel)
212 {
213         uchar   *cp;
214         FILE    *zout;
215         unsigned long   phoffz, shoffz, offset_delta;
216         int             zipfd, sidx, reduction;
217         char    zoutfile[128], zipto[128], mode[16], *proghdr;
218         struct  elf_shdr *sptr, *scntbl_z, *sptr_z;
219         struct stat zstat;
220         Elf32_Off       lowest_section_offset, offset1, offset2;
221
222         sprintf(mode,"wb%d ",zlevel);
223         sprintf(zipto,"%s.ezip",elfFname);
224         fprintf(stderr,"Compressing %s into %s \n",elfFname,zipto);
225
226         /* Make a copy of the section table... */
227         scntbl_z = (struct elf_shdr *)Malloc(Ehdr.e_shnum * Ehdr.e_shentsize);
228         memcpy(scntbl_z,ScnTbl,Ehdr.e_shnum * Ehdr.e_shentsize);
229
230         reduction = 0;
231
232         /* For each section, if it is of the appropriate type, compress it to
233          * a file named "_section_name_%d.gz".
234          */
235         for(sptr=ScnTbl,sidx=0;sidx<Ehdr.e_shnum;sidx++,sptr++) {
236                 char    *name;
237                         
238                 name = GetElfSectionName(ScnTbl[sidx].sh_name);
239
240                 if ((sptr->sh_flags & SHF_ALLOC) &&
241                         (sptr->sh_type != SHT_NOBITS) && (sptr->sh_size)) {
242
243                         sprintf(zoutfile,"_%s_%d.gz",name,sidx);
244                         unlink(zoutfile);
245
246                         cp = (uchar *)Malloc(sptr->sh_size);
247                         Lseek(elfFD,sptr->sh_offset,SEEK_SET);
248                         read(elfFD,cp,sptr->sh_size);
249
250                 zout = gzopen(zoutfile, mode);
251                     if (zout == NULL) {
252                         fprintf(stderr, "can't gzopen %s\n", zoutfile);
253                         exit(1);
254                     }
255                 if (gzwrite(zout, cp, (unsigned)sptr->sh_size) != sptr->sh_size) {
256                         fprintf(stderr, "gzwrite failed\n");
257                                 exit(1);
258                         }
259                     if (gzclose(zout) != Z_OK) {
260                         fprintf(stderr, "gzclose failed\n");
261                                 exit(1);
262                         }
263         
264                         free(cp);
265                         
266                         stat(zoutfile,&zstat);
267                         printf("Sec %-8s compressed from %8d to %8d bytes.\n",
268                                 name,sptr->sh_size,zstat.st_size);
269                         reduction += (sptr->sh_size - zstat.st_size);
270                 }
271                 free(name);
272         }
273         printf("Total reduction: %d bytes\n",reduction);
274
275         /* Create the destination file... */
276         unlink(zipto);
277         if ((zipfd = open(zipto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1)
278         {
279                 perror(zipto);
280                 exit(1);
281         }
282
283         /* Do a blind copy of all data up to the start of the first
284          * section.  Note that it is not required that the sections be
285          * listed in ScnTbl[] in the same order as they are arranged within
286          * the file, so we must determine which section in the table is first
287          * in the file.  Use the lowest_section_offset variable as a pointer
288          * to the first location in the new file into which the compressed
289          * sections can be placed.
290          *
291          * Fix...
292          * Turns out that the "blind copy" approach wastes memory in certain
293          * cases... For some reason some elf files have an empty 64K
294          * block of space between the end of the program header table and the
295          * first section, so this meant that a 64k block of space was wasted.
296          * 
297          * In the first fix for the above problem, the lowest_section_offset 
298          * pointed to the address just after the end of the file header (below
299          * the wasted 64k block).  This was incorrect because it chopped off
300          * the program header; hence, now the lowest_sectino_offset points to
301          * the address just after the program header...
302          *
303          * Yet another change to this...
304          * Turns out that we can't assume that the program header will be at
305          * the beginning of the file.  I've had cases where it is at the end
306          * (after the sections, next to the section header table).
307          * So... we look at both potential offsets (offset1 & offset2).
308          * If it turns out that the lowest section is below the program
309          * header in the elf file, then the program header is at the end;
310          * hence, it must be copied to the new .ezip file after the sections
311          * have been copied.
312          */
313         offset1 = FindLowestSectionInFile();    /* orignal technique */
314         offset2 = Ehdr.e_phoff+(Ehdr.e_phentsize*Ehdr.e_phnum);
315
316         if (verbose) {
317                 fprintf(stderr,"offset1: 0x%lx\n",offset1);
318                 fprintf(stderr,"offset2: 0x%lx\n",offset2);
319         }
320
321         if (offset1 < offset2) {
322                 if (verbose)
323                         fprintf(stderr,"Copying first %ld bytes\n",offset1);
324                 lowest_section_offset = offset1;
325
326                 /* If we're here, then the program header must be AFTER the
327                  * sections area in the elf file, so we extract the program
328                  * header now so that we can re-insert it after the sections
329                  * have been copied...
330                  */
331                 Lseek(elfFD,Ehdr.e_phoff,SEEK_SET);
332                 proghdr = Malloc(Ehdr.e_phentsize*Ehdr.e_phnum);
333                 Read(elfFD,proghdr,Ehdr.e_phentsize*Ehdr.e_phnum);
334         }
335         else {
336                 if (verbose)
337                         fprintf(stderr,"Copying ELF file & program hdr\n");
338                 lowest_section_offset = offset2;
339                 proghdr = 0;
340         }
341
342         Lseek(elfFD,0,SEEK_SET);
343         cp = Malloc(lowest_section_offset);
344         Read(elfFD,cp,lowest_section_offset);
345         Write(zipfd,cp,lowest_section_offset);
346         free(cp);
347
348         offset_delta = 0;
349
350         /* For each section, copy from original file or from zipped file to */
351         /* the new file... */
352         for(sptr=&ScnTbl[1],sidx=1;sidx<Ehdr.e_shnum;sidx++,sptr++) {
353                 char    *name;
354                         
355                 sptr_z = scntbl_z+sidx;
356
357                 name = GetElfSectionName(ScnTbl[sidx].sh_name);
358                 if ((sptr->sh_flags & SHF_ALLOC) &&
359                         (sptr->sh_type != SHT_NOBITS) && (sptr->sh_size)) {
360                         int secfd;
361
362                         sprintf(zoutfile,"_%s_%d.gz",name,sidx);
363                 
364                         stat(zoutfile,&zstat);
365                         if (verbose)
366                                 fprintf(stderr,"Replacing sec %s with %s (%d bytes)\n",
367                                         name,zoutfile,zstat.st_size);
368                         sptr_z->sh_size = zstat.st_size;
369 #if USE_OFFSET_DELTA
370                         sptr_z->sh_offset -= offset_delta;
371 #else
372                         sptr_z->sh_offset = tell(zipfd);
373 #endif
374                         if(debug) {
375                                 fprintf(stderr,"offset_delta += %d (%d-%d)\n",
376                                 (sptr->sh_size - sptr_z->sh_size),sptr->sh_size,
377                                 sptr_z->sh_size);
378                         }
379                         offset_delta += (sptr->sh_size - sptr_z->sh_size);
380                         if ((secfd = open(zoutfile,O_RDONLY|O_BINARY)) == -1) {
381                                 fprintf(stderr,"Couldn't open %s\n",zoutfile);
382                                 exit(1);
383                         }
384                         cp = Malloc(zstat.st_size);
385                         Read(secfd,cp,zstat.st_size);
386                         Write(zipfd,cp,zstat.st_size);
387                         free(cp);
388                         close(secfd);
389                         if (remove_zouts)
390                                 unlink(zoutfile);
391                 }
392                 else {
393                         if ((sptr->sh_size) && (sptr->sh_type != SHT_NOBITS)) {
394                                 if (debug)
395                                         fprintf(stderr,"Read %s offset=%d size=%d\n",
396                                                 name,sptr->sh_offset,sptr->sh_size);
397                                 Lseek(elfFD,sptr->sh_offset,SEEK_SET);
398                                 cp = Malloc(sptr->sh_size);
399                                 Read(elfFD,cp,sptr->sh_size);
400 #if USE_OFFSET_DELTA
401                                 sptr_z->sh_offset -= offset_delta;
402 #else
403                                 sptr_z->sh_offset = tell(zipfd);
404 #endif
405                                 Write(zipfd,cp,sptr->sh_size);
406                                 free(cp);
407                         }
408                 }
409
410                 if ((sptr->sh_type != SHT_NOBITS) && (sptr->sh_flags & SHF_ALLOC)) {
411                         /* I found that the size of the section does not necessarily */
412                         /* correspond to the point at which the next section starts in */
413                         /* the file, so this makes sure that offset_delta is properly */
414                         /* adjusted if that correspondance does not exist... */
415                         if ((sptr->sh_size + sptr->sh_offset) != (sptr+1)->sh_offset) {
416                                 int delta;
417                                 delta=((sptr+1)->sh_offset-(sptr->sh_size+sptr->sh_offset));
418                                 offset_delta += 
419                                         ((sptr+1)->sh_offset - (sptr->sh_size + sptr->sh_offset));
420                                 if (debug)
421                                         fprintf(stderr,"offset_delta compensation = %d\n",delta); 
422                         }
423                 }
424         }
425
426         /* Now that all sections have been written to the file, insert the
427          * section header table at the end. Note that the header may be
428          * endian-converted,  so compensate for this prior to writing to file...
429          */
430         if (1) {
431                 int     i;
432                 shoffz = tell(zipfd);
433                 /* The section header table base must be 4-byte aligned.. */
434                 if (shoffz & 3) {
435                         if (debug)
436                                 fprintf(stderr,"Shifting scnhdr %d bytes up\n",
437                                         4-(shoffz&3));
438                         shoffz = Lseek(zipfd,4-(shoffz&3),SEEK_CUR);
439                 }
440                 if(debug)
441                         fprintf(stderr,"Inserting scnhdr at 0x%x\n",shoffz);
442                 for(i=0;i<Ehdr.e_shnum;i++) {
443                         scntbl_z[i].sh_name = otherEnd32(Ecvt,scntbl_z[i].sh_name);
444                         scntbl_z[i].sh_type = otherEnd32(Ecvt,scntbl_z[i].sh_type);
445                         scntbl_z[i].sh_flags = otherEnd32(Ecvt,scntbl_z[i].sh_flags);
446                         scntbl_z[i].sh_addr = otherEnd32(Ecvt,scntbl_z[i].sh_addr);
447                         scntbl_z[i].sh_offset = otherEnd32(Ecvt,scntbl_z[i].sh_offset);
448                         scntbl_z[i].sh_size = otherEnd32(Ecvt,scntbl_z[i].sh_size);
449                         scntbl_z[i].sh_link = otherEnd32(Ecvt,scntbl_z[i].sh_link);
450                         scntbl_z[i].sh_info = otherEnd32(Ecvt,scntbl_z[i].sh_info);
451                         scntbl_z[i].sh_addralign =
452                                 otherEnd32(Ecvt,scntbl_z[i].sh_addralign);
453                         scntbl_z[i].sh_entsize = otherEnd32(Ecvt,scntbl_z[i].sh_entsize);
454                 }
455                 Write(zipfd,(char *)scntbl_z,(int)(Ehdr.e_shnum*Ehdr.e_shentsize));
456                 for(i=0;i<Ehdr.e_shnum;i++) {
457                         scntbl_z[i].sh_name = otherEnd32(Ecvt,scntbl_z[i].sh_name);
458                         scntbl_z[i].sh_type = otherEnd32(Ecvt,scntbl_z[i].sh_type);
459                         scntbl_z[i].sh_flags = otherEnd32(Ecvt,scntbl_z[i].sh_flags);
460                         scntbl_z[i].sh_addr = otherEnd32(Ecvt,scntbl_z[i].sh_addr);
461                         scntbl_z[i].sh_offset = otherEnd32(Ecvt,scntbl_z[i].sh_offset);
462                         scntbl_z[i].sh_size = otherEnd32(Ecvt,scntbl_z[i].sh_size);
463                         scntbl_z[i].sh_link = otherEnd32(Ecvt,scntbl_z[i].sh_link);
464                         scntbl_z[i].sh_info = otherEnd32(Ecvt,scntbl_z[i].sh_info);
465                         scntbl_z[i].sh_addralign =
466                                 otherEnd32(Ecvt,scntbl_z[i].sh_addralign);
467                         scntbl_z[i].sh_entsize = otherEnd32(Ecvt,scntbl_z[i].sh_entsize);
468                 }
469         }
470
471         /* If the program header was buffered earlier,then we need to insert
472          * it now...
473          */
474         if (proghdr) {
475                 phoffz = tell(zipfd);
476                 Write(zipfd,proghdr,(Ehdr.e_phentsize*Ehdr.e_phnum));
477                 Lseek(zipfd,0x1c,SEEK_SET);
478                 phoffz = otherEnd32(Ecvt,phoffz);
479                 Write(zipfd,(char *)&phoffz,4);
480         }
481
482         if (debug)
483                 fprintf(stderr,"offset_delta = %d\n",offset_delta);
484
485         /* Adjust the file header to point to the new section header table.
486          */
487         Lseek(zipfd,0x20,SEEK_SET);
488         shoffz = otherEnd32(Ecvt,shoffz);
489         Write(zipfd,(char *)&shoffz,4);
490
491
492         close(zipfd);
493 }
494
495 void
496 ElfToBinary(char *binto)
497 {
498         int     fd, sidx, firstone;
499         struct  stat buf;
500         uchar   *tfrom, *dfrom, *cp;
501         unsigned long   paddr;
502         struct  elf_shdr        *sptr;
503
504         unlink(binto);
505         if ((fd = open(binto,O_RDWR|O_BINARY|O_CREAT,0777))==-1)
506         {
507                 perror(binto);
508                 exit(1);
509         }
510         fprintf(stderr,"Converting %s into %s\n",
511                 elfFname,binto);
512         firstone = 1;
513         for(sptr=ScnTbl,sidx=0;sidx<Ehdr.e_shnum;sidx++,sptr++) {
514                 char    *name, padbyte;
515                 int             padtot;
516                 unsigned long   nextpaddr;
517                 
518                 name = GetElfSectionName(ScnTbl[sidx].sh_name);
519
520                 if ((sptr->sh_flags & SHF_ALLOC) &&
521                     (sptr->sh_type != SHT_NOBITS) &&
522                     (sptr->sh_size)) {
523                         if (!firstone) {        /* Pad if necessary... */
524                                 if (nextpaddr != sptr->sh_addr) {
525                                         if (sptr->sh_addr < nextpaddr) {
526                                                 fprintf(stderr,"Unexpected section address\n");
527                                                 exit(1);
528                                         }
529                                         padtot = sptr->sh_addr-nextpaddr;
530                                         printf("Pad 0x%x bytes\n",padtot);
531                                         padbyte = PadByte;
532                                         while(padtot) {
533                                                 Write(fd,&padbyte,1);
534                                                 padtot--;
535                                         }
536                                 }
537                         }
538                         printf("Sec %-8s at 0x%-8x 0x%-6x bytes\n",
539                                 name,sptr->sh_addr,sptr->sh_size);
540                         cp = (uchar *)Malloc(sptr->sh_size);
541                         Lseek(elfFD,sptr->sh_offset,SEEK_SET);
542                         read(elfFD,cp,sptr->sh_size);
543                         Write(fd,cp,sptr->sh_size);
544                         free(cp);
545                         nextpaddr = sptr->sh_addr + sptr->sh_size;
546                         firstone = 0;
547                 }
548                 free(name);
549         }
550         /* If non-zero, then insert the specified number of bytes just prior */
551         /* to the end of the binary file.  Starting at a point 4-bytes befor */
552         /* the end.  This is needed because of a problem with GNU linker that */
553         /* does not allow a 4-byte section  to exist at 0xfffffffc (branch */
554         /* instruction location for PPC403GCX). */
555         if (insertPAD) {
556                 int i;
557                 char branch[4];
558
559                 Lseek(fd,-4,SEEK_CUR);
560                 Read(fd,branch,4);
561                 Lseek(fd,-4,SEEK_CUR);
562                 for(i=0;i<insertPAD;i++)
563                         Write(fd,&PadByte,1);
564                 Write(fd,branch,4);
565         }
566         close(fd);
567 }
568
569 /* StripElfFile():
570         This is a bit tricky for elf.  We can only strip out certain
571         sections, and the sections are not necessarily at the end of 
572         the file; hence, chunks of the file are removed and the file
573         offsets in the section header table must be adjusted.
574 */
575 void
576 StripElfFile(char *stripto,char *append)
577 {
578         uchar   *cp;
579         FILE    *zout;
580         unsigned long   shoffs, offset_delta;
581         int             stripfd, sidx, newsectot;
582         struct  elf_shdr *sptr, *scntbl_s, *sptr_s;
583         struct stat zstat;
584
585         fprintf(stderr,"Stripping %s into %s \n",elfFname,stripto);
586 fprintf(stderr,"Not working yet\n");
587 return;
588
589         /* Allocate space for new section header table that may be smaller */
590         /* than the current table... */
591         scntbl_s = (struct elf_shdr *)Malloc(Ehdr.e_shnum * Ehdr.e_shentsize);
592
593         /* Create the destination file... */
594         unlink(stripto);
595         if ((stripfd = open(stripto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1) {
596                 perror(stripto);
597                 exit(1);
598         }
599
600         /* Up to the first section, do a blind copy from original */
601         /* file to new compressed file... */
602         if (debug)
603                 fprintf(stderr,"Copying first %ld bytes\n",ScnTbl[1].sh_offset);
604         Lseek(elfFD,0,SEEK_SET);
605         cp = Malloc(ScnTbl[1].sh_offset);
606         Read(elfFD,cp,ScnTbl[1].sh_offset);
607         Write(stripfd,cp,ScnTbl[1].sh_offset);
608         free(cp);
609
610         scntbl_s[0] = ScnTbl[0];
611         newsectot = 0;
612         offset_delta = 0;
613         sptr_s = scntbl_s+1;
614
615         /* For each section, either copy it or remove it... */
616         for(sptr=&ScnTbl[1],sidx=1;sidx<Ehdr.e_shnum;sidx++,sptr++) {
617                 char    *name;
618                         
619                 name = GetElfSectionName(ScnTbl[sidx].sh_name);
620
621                 if (!strcmp(name,".comment")) {
622                         if (verbose)
623                                 fprintf(stderr,"Removing %s (%d bytes)\n",name,sptr->sh_size);
624                         offset_delta += sptr->sh_size;
625                 }
626                 else {
627
628                         *sptr_s++ = *sptr;
629                         newsectot++;
630                         if ((sptr->sh_size) && (sptr->sh_type != SHT_NOBITS)) {
631                                 if (verbose)
632                                         fprintf(stderr,"Copying %s (%d bytes)\n",
633                                                 name,sptr->sh_size);
634                                 Lseek(elfFD,sptr->sh_offset,SEEK_SET);
635                                 cp = Malloc(sptr->sh_size);
636                                 Read(elfFD,cp,sptr->sh_size);
637                                 Write(stripfd,cp,sptr->sh_size);
638                                 sptr_s->sh_offset -= offset_delta;
639                                 free(cp);
640                         }
641                 }
642                 /* Assuming the section header table comes just after the section */
643                 /* header string table section, insert the modified table... */
644                 /* Note that the header may be endian-converted,  so compensate for */
645                 /* this prior to writing to file... */
646                 if (!strcmp(name,".shstrtab")) {
647                         int     i;
648
649                         sidx++;
650                         sptr++;
651                         sptr_s++;
652
653 fprintf(stderr,"section headers at section # %d\n",sidx);
654                         /* Adjust the size of the section header table: */
655                         scntbl_s[sidx].sh_size = newsectot * Ehdr.e_shentsize;
656
657                         /* Store this current file location: */
658                         shoffs = tell(stripfd);
659
660                         if(debug)
661                                 fprintf(stderr,"Inserting scnhdr at 0x%x\n",shoffs);
662                         for(i=0;i<newsectot;i++) {
663                                 scntbl_s[i].sh_name = otherEnd32(Ecvt,scntbl_s[i].sh_name);
664                                 scntbl_s[i].sh_type = otherEnd32(Ecvt,scntbl_s[i].sh_type);
665                                 scntbl_s[i].sh_flags = otherEnd32(Ecvt,scntbl_s[i].sh_flags);
666                                 scntbl_s[i].sh_addr = otherEnd32(Ecvt,scntbl_s[i].sh_addr);
667                                 scntbl_s[i].sh_offset = otherEnd32(Ecvt,scntbl_s[i].sh_offset);
668                                 scntbl_s[i].sh_size = otherEnd32(Ecvt,scntbl_s[i].sh_size);
669                                 scntbl_s[i].sh_link = otherEnd32(Ecvt,scntbl_s[i].sh_link);
670                                 scntbl_s[i].sh_info = otherEnd32(Ecvt,scntbl_s[i].sh_info);
671                                 scntbl_s[i].sh_addralign =
672                                         otherEnd32(Ecvt,scntbl_s[i].sh_addralign);
673                                 scntbl_s[i].sh_entsize = 
674                                         otherEnd32(Ecvt,scntbl_s[i].sh_entsize);
675                         }
676                         Write(stripfd,(char *)scntbl_s,(int)(newsectot*Ehdr.e_shentsize));
677                         for(i=0;i<newsectot;i++) {
678                                 scntbl_s[i].sh_name = otherEnd32(Ecvt,scntbl_s[i].sh_name);
679                                 scntbl_s[i].sh_type = otherEnd32(Ecvt,scntbl_s[i].sh_type);
680                                 scntbl_s[i].sh_flags = otherEnd32(Ecvt,scntbl_s[i].sh_flags);
681                                 scntbl_s[i].sh_addr = otherEnd32(Ecvt,scntbl_s[i].sh_addr);
682                                 scntbl_s[i].sh_offset = otherEnd32(Ecvt,scntbl_s[i].sh_offset);
683                                 scntbl_s[i].sh_size = otherEnd32(Ecvt,scntbl_s[i].sh_size);
684                                 scntbl_s[i].sh_link = otherEnd32(Ecvt,scntbl_s[i].sh_link);
685                                 scntbl_s[i].sh_info = otherEnd32(Ecvt,scntbl_s[i].sh_info);
686                                 scntbl_s[i].sh_addralign =
687                                         otherEnd32(Ecvt,scntbl_s[i].sh_addralign);
688                                 scntbl_s[i].sh_entsize =
689                                         otherEnd32(Ecvt,scntbl_s[i].sh_entsize);
690                         }
691                         offset_delta += (Ehdr.e_shnum - newsectot) * Ehdr.e_shentsize;
692                 }
693         }
694
695         if (debug)
696                 fprintf(stderr,"offset_delta = %d\n",offset_delta);
697
698         /* Adjust the file header to point to the new section header table. */
699         Lseek(stripfd,0x20,SEEK_SET);
700         shoffs = otherEnd32(Ecvt,shoffs);
701         Write(stripfd,(char *)&shoffs,4);
702         
703         close(stripfd);
704 }
705
706 #if 0
707         if (append) {
708                 struct  stat buf;
709                 char    *aspace;
710                 if ((afd = open(append,O_RDONLY|O_BINARY))==-1)
711                 {
712                         perror(append);
713                         exit(1);
714                 }
715                 stat(append,&buf);
716                 aspace = Malloc(buf.st_size+32);
717                 read(afd,aspace,buf.st_size);
718                 Write(sfd,aspace,buf.st_size);
719                 free(aspace);
720                 close(afd);
721         }
722         close(sfd);
723 #endif
724
725 void
726 ShowElfMap(long flag)
727 {
728         int     i;
729         unsigned long   size, totsize;
730         struct  elf_shdr        *eshdr;
731
732         if (debug >= 2)
733                 fprintf(stderr,"ShowElfMap()\n");
734
735         totsize = 0;
736         for(i=0;i<Ehdr.e_shnum;i++) {
737                 eshdr = &ScnTbl[i];
738                 size = eshdr->sh_size;
739                 if (size)
740                         size--;
741                 else if (flag & SHOWMAPNONZERO)
742                         continue;
743                 if ((eshdr->sh_flags) || (flag & SHOWMAPOFFSET)) {
744                         printf("%18s: 0x%08x..0x%08x (%ld bytes) %s\n",
745                                 GetElfSectionName(eshdr->sh_name),
746                                 eshdr->sh_addr,eshdr->sh_addr+size,eshdr->sh_size,
747                                 VerboseShflags(eshdr->sh_flags));
748                                 totsize += eshdr->sh_size;
749                         if (flag & SHOWMAPOFFSET) {
750                                 printf("            ELF file offset: 0x%08x\n",
751                                         eshdr->sh_offset);
752                         }
753                 }
754         }
755         printf("Entrypoint: 0x%08x\n",Ehdr.e_entry);
756         printf("Total size: 0x%08lx (%ld)\n",totsize,totsize);
757 }
758
759 char *
760 VerboseShtype(unsigned long type)
761 {
762         switch(type) {
763         case SHT_NULL:
764                 return("null");
765         case SHT_PROGBITS:
766                 return("progbits");
767         case SHT_SYMTAB:
768                 return("symtab");
769         case SHT_STRTAB:
770                 return("strtab");
771         case SHT_RELA:
772                 return("rela");
773         case SHT_HASH:
774                 return("hash");
775         case SHT_DYNAMIC:
776                 return("dynamic");
777         case SHT_NOTE:
778                 return("note");
779         case SHT_NOBITS:
780                 return("nobits");
781         case SHT_REL:
782                 return("rel");
783         case SHT_SHLIB:
784                 return("shlib");
785         case SHT_DYNSYM:
786                 return("dynsym");
787         default:
788                 fprintf(stderr,"Unexpeced type: 0x%x\n",type);
789                 exit(1);
790         }
791 }
792
793 char *
794 VerboseShflags(unsigned long flags)
795 {
796         static  char buf[32];
797
798         *buf = 0;
799         if (flags & SHF_ALLOC)
800                 strcat(buf,"allocated ");
801         if (flags & SHF_WRITE)
802                 strcat(buf,"writeable ");
803         if (flags & SHF_EXECINSTR)
804                 strcat(buf,"text ");
805         return(buf);
806 }
807
808 char *
809 GetElfSectionName(unsigned long index)
810 {
811         static  char buf[64];
812         char    *strings, *bp, *end, *name;
813         struct  elf_shdr        *eshdr;
814
815         if (debug >= 2)
816                 fprintf(stderr,"GetElfSectionName(%d)\n",index);
817
818         buf[0] = (char)0;
819         eshdr = &ScnTbl[Ehdr.e_shstrndx];
820         Lseek(elfFD,eshdr->sh_offset,SEEK_SET);
821         strings = Malloc((unsigned)(eshdr->sh_size));
822         Read(elfFD,strings,(unsigned)(eshdr->sh_size));
823         name = Malloc(strlen(&strings[index]) + 1);
824         strcpy(name,&strings[index]);
825         free(strings);
826         return(name);
827 }
828
829 /* GetElfFileHdr():
830    Retrieve the header from the file and do a endian conversion
831    on each of its members.
832 */
833 struct elf_fhdr *
834 GetElfFileHdr(struct elf_fhdr *efhdr)
835 {
836         static int      pass = 0;
837
838         if (debug >= 2)
839                 fprintf(stderr,"GetElfFileHdr()\n");
840
841 retry:
842
843         /* Read in the elf header. */
844         Lseek(elfFD,0,SEEK_SET);
845         Read(elfFD,(char *)efhdr,(unsigned)sizeof(struct elf_fhdr));
846
847         /* If this is the first pass through this function, then
848          * read in the size of the program header.  If the size is
849          * greater than 4k, then assume we need to do an endian
850          * adjustment...
851          */
852         if (pass == 0) {
853                 pass++;
854                 efhdr->e_phentsize = otherEnd16(Ecvt,efhdr->e_phentsize);
855                 if (efhdr->e_phentsize > 0x1000) {
856                         printf("Automatic endianness adjustment\n");
857 #if HOST_IS_SOLARIS
858                         Ecvt = 1;
859 #else
860                         Ecvt = 0;
861 #endif
862                         goto retry;
863                 }
864         }
865
866         efhdr->e_type = otherEnd16(Ecvt,efhdr->e_type);
867         efhdr->e_machine = otherEnd16(Ecvt,efhdr->e_machine);
868         efhdr->e_version = otherEnd32(Ecvt,efhdr->e_version);
869         efhdr->e_entry = otherEnd32(Ecvt,efhdr->e_entry);
870         efhdr->e_phoff = otherEnd32(Ecvt,efhdr->e_phoff);
871         efhdr->e_shoff = otherEnd32(Ecvt,efhdr->e_shoff);
872         efhdr->e_flags = otherEnd32(Ecvt,efhdr->e_flags);
873         efhdr->e_ehsize = otherEnd16(Ecvt,efhdr->e_ehsize);
874         efhdr->e_phentsize = otherEnd16(Ecvt,efhdr->e_phentsize);
875         efhdr->e_phnum = otherEnd16(Ecvt,efhdr->e_phnum);
876         efhdr->e_shentsize = otherEnd16(Ecvt,efhdr->e_shentsize);
877         efhdr->e_shnum = otherEnd16(Ecvt,efhdr->e_shnum);
878         efhdr->e_shstrndx = otherEnd16(Ecvt,efhdr->e_shstrndx);
879         return(efhdr);
880 }
881
882 Elf32_Half
883 GetElfSectionHdrs(void)
884 {
885         int     i, size;
886
887         /* Allocate space for the section table in memory. */
888         size = Ehdr.e_shnum * Ehdr.e_shentsize;
889         ScnTbl = (struct elf_shdr *)Malloc(size);
890
891         /* Read in the elf section headers. */
892         Lseek(elfFD,Ehdr.e_shoff,SEEK_SET);
893         Read(elfFD,(char *)ScnTbl,size);
894
895         for(i=0;i<Ehdr.e_shnum;i++) {
896                 ScnTbl[i].sh_name = otherEnd32(Ecvt,ScnTbl[i].sh_name);
897                 ScnTbl[i].sh_type = otherEnd32(Ecvt,ScnTbl[i].sh_type);
898                 ScnTbl[i].sh_flags = otherEnd32(Ecvt,ScnTbl[i].sh_flags);
899                 ScnTbl[i].sh_addr = otherEnd32(Ecvt,ScnTbl[i].sh_addr);
900                 ScnTbl[i].sh_offset = otherEnd32(Ecvt,ScnTbl[i].sh_offset);
901                 ScnTbl[i].sh_size = otherEnd32(Ecvt,ScnTbl[i].sh_size);
902                 ScnTbl[i].sh_link = otherEnd32(Ecvt,ScnTbl[i].sh_link);
903                 ScnTbl[i].sh_info = otherEnd32(Ecvt,ScnTbl[i].sh_info);
904                 ScnTbl[i].sh_addralign = otherEnd32(Ecvt,ScnTbl[i].sh_addralign);
905                 ScnTbl[i].sh_entsize = otherEnd32(Ecvt,ScnTbl[i].sh_entsize);
906         }
907
908         return(Ehdr.e_shnum);
909 }
910
911 Elf32_Half
912 GetElfProgramHdrTbl(void)
913 {
914         int     i, size;
915
916         /* Allocate space for the program header table in memory.
917          */
918         size = Ehdr.e_phnum * Ehdr.e_phentsize;
919         PhdrTbl = (struct elf_phdr *)Malloc(size);
920
921         /* Read in the elf section headers. */
922         Lseek(elfFD,Ehdr.e_phoff,SEEK_SET);
923         Read(elfFD,(char *)PhdrTbl,size);
924
925         for(i=0;i<Ehdr.e_phnum;i++) {
926                 PhdrTbl[i].p_type = otherEnd32(Ecvt,PhdrTbl[i].p_type);
927                 PhdrTbl[i].p_offset = otherEnd32(Ecvt,PhdrTbl[i].p_offset);
928                 PhdrTbl[i].p_vaddr = otherEnd32(Ecvt,PhdrTbl[i].p_vaddr);
929                 PhdrTbl[i].p_paddr = otherEnd32(Ecvt,PhdrTbl[i].p_paddr);
930                 PhdrTbl[i].p_filesz = otherEnd32(Ecvt,PhdrTbl[i].p_filesz);
931                 PhdrTbl[i].p_memsz = otherEnd32(Ecvt,PhdrTbl[i].p_memsz);
932                 PhdrTbl[i].p_flags = otherEnd32(Ecvt,PhdrTbl[i].p_flags);
933                 PhdrTbl[i].p_align = otherEnd32(Ecvt,PhdrTbl[i].p_align);
934         }
935
936         return(Ehdr.e_phnum);
937 }
938
939 char *usage_txt[] = {
940         "Usage: elf [options] {filename}",
941         " Options:",
942         " -a{filename}  append file to end of -S file",
943         " -A            print what was appended by -a",
944         " -B{filename}  elf-2-bin to filename",
945         " -c            endian convert",
946         " -d            debug mode (for development only)",
947         " -f            show elf file header",
948         " -i#           insert '#' pad bytes, 4 bytes prior to end of binary",
949         " -M            show elf map with file offsets",
950         " -m            show elf map without file offsets",
951         " -p            dump program header table.",
952         " -P{pad byte}  byte to use for padding (default = 0xff)",
953         " -s            show elf section headers",
954         " -S{filename}  strip to specified file",
955         " -V            display version of tool",
956         " -v            verbose mode",
957         " -z{zlvl}      compress sections of filename to 'filename.ezip'",
958         "               zlvl can range from 1-9 (typically 6) where...",
959         "               1 is faster/lighter compression",
960         "               9 is slower/heavier compression",
961         " -Z{zlvl}      same as -z, but compressed section files are not removed",
962         "",
963         " Note:",
964         "  The GNU-equivalent for 'elf -B outfile.bin infile.elf' is:",
965         "    objcopy --output-target=binary --gap-fill 0xff infile.elf outfile.bin",
966         0,
967 };
968
969 main(argc,argv)
970 int     argc;
971 char    *argv[];
972 {
973         extern  int optind;
974         extern  char *optarg;
975         char    fname[128], buf[16], *append, *binto, *stripto;
976         int     i, opt, showstuff, zlevel;
977
978         elfFD = 0;
979         zlevel = 0;
980         debug = 0;
981         xdebug = 0;
982         verbose = 0;
983         insertPAD = 0;
984         showstuff = 0;
985 #if HOST_IS_SOLARIS
986         Ecvt = 0;
987 #else
988         Ecvt = 1;
989 #endif
990         PadByte = 0xff;
991         binto = (char *)0;
992         append = (char *)0;
993         stripto = (char *)0;
994         elfFname = (char *)0;
995
996         while ((opt=getopt(argc,argv,"Aa:B:cdfi:mMpP:S:sVvxz:Z:")) != EOF) {
997                 switch(opt) {
998                 case 'a':
999                         append = optarg;
1000                         break;
1001                 case 'A':
1002                         showstuff |= SHOWAPPEND;
1003                         break;
1004                 case 'B':
1005                         binto = optarg;
1006                         break;
1007                 case 'c':
1008 #if HOST_IS_SOLARIS
1009                         Ecvt = 1;
1010 #else
1011                         Ecvt = 0;
1012 #endif
1013                         break;
1014                 case 'd':
1015                         debug++;
1016                         break;
1017                 case 'f':
1018                         showstuff |= SHOWELFHDR;
1019                         break;
1020                 case 'i':
1021                         insertPAD = strtol(optarg,0,0);
1022                         break;
1023                 case 'M':
1024                         showstuff |= SHOWMAPOFFSET;
1025                         break;
1026                 case 'm':
1027                         if (showstuff & SHOWMAP)
1028                                 showstuff |= SHOWMAPNONZERO;
1029                         else
1030                                 showstuff |= SHOWMAP;
1031                         break;
1032                 case 'p':
1033                         showstuff |= SHOWPRGMHDR;
1034                         break;
1035                 case 'P':
1036                         PadByte = strtol(optarg,0,0);
1037                         break;
1038                 case 's':
1039                         showstuff |= SHOWSECTIONS;
1040                         break;
1041                 case 'S':
1042                         stripto = optarg;
1043                         break;
1044                 case 'V':
1045                         showVersion();
1046                         break;
1047                 case 'v':
1048                         verbose = 1;
1049                         break;
1050                 case 'x':
1051                         xdebug++;
1052                         break;
1053                 case 'Z':
1054                         remove_zouts = 0;
1055                         zlevel = atoi(optarg);
1056                         if ((zlevel < 1) || (zlevel > 9))
1057                                 usage("zlvl out of range\n");
1058                         break;
1059                 case 'z':
1060                         zlevel = atoi(optarg);
1061                         if ((zlevel < 1) || (zlevel > 9))
1062                                 usage("zlvl out of range\n");
1063                         break;
1064                 default:
1065                         usage(0);
1066                 }
1067         }
1068
1069         if (argc != (optind+1))
1070                 usage("Missing filename");
1071
1072         strcpy(fname,argv[optind]);
1073
1074         if (verbose)
1075                 printf("\n%s:\n",fname);
1076
1077         if (!fileexists(fname)) {
1078                 fprintf(stderr,"No such file: %s\n",fname);
1079                 exit(1);
1080         }
1081
1082         if ((elfFD = open(fname,O_RDONLY | O_BINARY)) == -1) {
1083                 perror(fname);
1084                 return(0);
1085         }
1086
1087         /* Start by verifying that the file is ELF format... */
1088         Read(elfFD,buf,4);
1089         if ((buf[0] != 0x7f) || (buf[1] != 'E') ||
1090             (buf[2] != 'L') || (buf[3] != 'F')) {
1091                 fprintf(stderr,"File '%s' not ELF format\n",fname);
1092                 exit(1);
1093         }
1094
1095         elfFname = StrAllocAndCopy(fname);
1096         GetElfFileHdr(&Ehdr);
1097         GetElfProgramHdrTbl();
1098         GetElfSectionHdrs();
1099
1100         if (zlevel) {
1101                 ZipElfSections(zlevel);
1102         }
1103         else if (binto) {
1104                 ElfToBinary(binto);
1105         }
1106         else if (stripto) {
1107                 StripElfFile(stripto,append);
1108         }
1109         else {
1110                 if (showstuff & SHOWAPPEND) 
1111                         ShowAppend();
1112                 if ((showstuff & SHOWMAPOFFSET) ||
1113                         (showstuff & SHOWMAP) ||
1114                         (showstuff & SHOWMAPNONZERO)) {
1115                         ShowElfMap(showstuff);
1116                 }
1117                 if (showstuff & SHOWELFHDR) 
1118                         ShowElfHdr();
1119                 if (showstuff & SHOWSECTIONS) 
1120                         ShowSections(verbose);
1121                 if (showstuff & SHOWPRGMHDR) 
1122                         ShowProgramHdrTbl(verbose);
1123         }
1124         exit(0);
1125 }