📄 elf.c
字号:
/* elf.c:
* Perform some dumps/displays/conversions on the elf file format.
*
* General notice:
* This code is part of a boot-monitor package developed as a generic base
* platform for embedded system designs. As such, it is likely to be
* distributed to various projects beyond the control of the original
* author. Please notify the author of any enhancements made or bugs found
* so that all may benefit from the changes. In addition, notification back
* to the author will allow the new user to pick up changes that may have
* been made by other users after this version of the code was distributed.
*
* Author: Ed Sutter
* email: esutter@lucent.com (home: lesutter@worldnet.att.net)
* phone: 908-582-2351 (home: 908-889-5161)
*/
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "elf.h"
#include "utils.h"
#include "../zlib/zlib.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define USE_OFFSET_DELTA 0
void ZipElfSections(int), ElfToBinary(char *);
void StripElfFile(char *,char *), ShowElfMap(int);
void ShowAppend(void), ShowElfHdr(void), ShowSections(int);
Elf32_Half GetElfSectionHdrs(void);
struct elf_fhdr *GetElfFileHdr(struct elf_fhdr *);
char *VerboseShtype(unsigned long);
char *VerboseShflags(unsigned long), *GetElfSectionName(unsigned long);
struct elf_fhdr Ehdr;
struct elf_shdr *ScnTbl;
struct elf_phdr *PhdrTbl;
char *elfFname;
unsigned char PadByte;
int elfFD, debug, xdebug, Ecvt, verbose, insertPAD;
int remove_zouts = 1;
/* open verbosity: */
#define SHOWELFHDR 0x0001
#define SHOWSECTIONS 0x0002
#define SHOWMAP 0x0004
#define SHOWMAPOFFSET 0x0008
#define SHOWAPPEND 0x0010
#define SHOWPRGMHDR 0x0020
/* The Linux box that I tried to build this on did not have tell(),
* so this is a very inefficient equivalent...
* Originally, I thought lseek(fd,0,SEEK_CUR) would work, but
* that generates an error on linux due to a bad argument; apparently
* it doesn't like the value of 0 for the offset when 'whence' is set to
* SEEK_CUR.
*/
#ifndef BUILD_WITH_VCC
long
tell(int fd)
{
Lseek(fd,1,SEEK_CUR);
return(Lseek(fd,-1,SEEK_CUR));
}
#endif
void
ShowAppend(void)
{
int i;
char c;
Elf32_Word maxsize;
Elf32_Off maxoff;
struct elf_shdr *eshdr;
/* Find the highest offset then seek to the end of that section. This */
/* should be the end of the REAL data in the elf file. Any remaining */
/* stuff has been appended (hopefully!). */
maxoff = 0;
for(i=0;i<Ehdr.e_shnum;i++) {
eshdr = &ScnTbl[i];
if (eshdr->sh_offset > maxoff) {
maxoff = eshdr->sh_offset;
maxsize = eshdr->sh_size;
}
}
Lseek(elfFD,maxoff+maxsize,SEEK_SET);
while(1) {
if (read(elfFD,&c,1) != 1)
break;
putchar(c);
}
}
void
ShowElfHdr(void)
{
int i, j;
printf("\t\tELF FILE HEADER\n");
printf("E_IDENT (hex): ");
for(i=0;i<EI_NIDENT;i++)
printf("%02x ",Ehdr.e_ident[i]);
printf("\n");
printf("File Type: 0x%x\n",Ehdr.e_type);
printf("Machine: 0x%x\n",Ehdr.e_machine);
printf("Version: 0x%x\n",Ehdr.e_version);
printf("Entrypoint: 0x%08x\n",Ehdr.e_entry);
printf("Program Hdr Tbl Offset: 0x%x\n",Ehdr.e_phoff);
printf("Section Hdr Tbl Offset: 0x%x\n",Ehdr.e_shoff);
printf("Processor-specific flags: 0x%08x\n",Ehdr.e_flags);
printf("ELF Header size: %u\n",Ehdr.e_ehsize);
printf("Size of 1 Pgm Hdr Entry: %u\n",Ehdr.e_phentsize);
printf("# of entries in Pgm Hdr Tbl: %u\n",Ehdr.e_phnum);
printf("Size of 1 Scn Hdr Entry: %u\n",Ehdr.e_shentsize);
printf("# of entries in Scn Hdr Tbl: %u\n",Ehdr.e_shnum);
printf("ScnHdr string Tbl Index: 0x%x\n",Ehdr.e_shstrndx);
}
void
ShowProgramHdrTbl(int verbose)
{
int i, j;
printf("\t\tProgram Header Table:\n");
for(i=0;i<Ehdr.e_phnum;i++) {
printf("PHDR[%d]:\n",i);
printf("p_type: 0x%lx\n",PhdrTbl[i].p_type);
printf("p_offset: 0x%lx\n",PhdrTbl[i].p_offset);
printf("p_vaddr: 0x%lx\n",PhdrTbl[i].p_vaddr);
printf("p_paddr: 0x%lx\n",PhdrTbl[i].p_paddr);
printf("p_filesz: 0x%lx\n",PhdrTbl[i].p_filesz);
printf("p_memsz: 0x%lx\n",PhdrTbl[i].p_memsz);
printf("p_flags: 0x%lx\n",PhdrTbl[i].p_flags);
printf("p_align: 0x%lx\n",PhdrTbl[i].p_align);
}
}
void
ShowSections(int verbose)
{
int i;
unsigned long size;
char buf[32];
struct elf_shdr *eshdr;
if (debug >= 2)
fprintf(stderr,"ShowSections()\n");
for(i=0;i<Ehdr.e_shnum;i++) {
eshdr = &ScnTbl[i];
size = eshdr->sh_size;
if (size)
size--;
printf("%10s: 0x%08x..0x%08x (%ld bytes) %s %s\n",
GetElfSectionName(eshdr->sh_name),
eshdr->sh_addr,eshdr->sh_addr+size,eshdr->sh_size,
VerboseShflags(eshdr->sh_flags),
VerboseShtype(eshdr->sh_type));
if (verbose) {
printf(" offset= 0x%08x, link= 0x%08x, info=0x%08x\n",
eshdr->sh_offset, eshdr->sh_link, eshdr->sh_info);
printf(" addralign=0x%08x, entsize=0x%08x\n\n",
eshdr->sh_addralign, eshdr->sh_entsize);
}
}
}
/* FindLowestSectionInFile():
* The section table (ScnTbl[] array) contains a list of all sections in
* the ELF file. I had thought that this table listed the sections
* in the same order as they exist in the file (meaning that the section
* pointed to by ScnTbl[1] was before the section pointed to by ScnTbl[2]).
* Turns out that this is not necessarily the case, so this function simply
* returns the offset to the lowest section in the file.
*/
long
FindLowestSectionInFile(void)
{
int i;
Elf32_Off lowest_offset;
lowest_offset = 0xffffffff;
for(i=1;i<Ehdr.e_shnum;i++) {
if ((ScnTbl[i].sh_size) &&
(ScnTbl[i].sh_offset < lowest_offset))
lowest_offset = ScnTbl[i].sh_offset;
}
if (debug >= 1)
fprintf(stderr,"lowest section in file = 0x%lx\n",lowest_offset);
return(lowest_offset);
}
/* ZipElfSections():
* First pass...
* Create one file of compressed data for each section to be compressed.
* Second pass...
* Replace each original section with the data from the compressed file
* and adjust header information appropriately.
*/
void
ZipElfSections(int zlevel)
{
uchar *cp;
FILE *zout;
unsigned long shoffz, offset_delta;
int zipfd, sidx, reduction;
char zoutfile[128], zipto[128], mode[16];
struct elf_shdr *sptr, *scntbl_z, *sptr_z;
struct stat zstat;
Elf32_Off lowest_section_offset;
sprintf(mode,"wb%d ",zlevel);
sprintf(zipto,"%s.ezip",elfFname);
fprintf(stderr,"Compressing %s into %s \n",elfFname,zipto);
/* Make a copy of the section table... */
scntbl_z = (struct elf_shdr *)Malloc(Ehdr.e_shnum * Ehdr.e_shentsize);
memcpy(scntbl_z,ScnTbl,Ehdr.e_shnum * Ehdr.e_shentsize);
reduction = 0;
/* For each section, if it is of the appropriate type, compress it to
* a file named "_section_name_%d.zip".
*/
for(sptr=ScnTbl,sidx=0;sidx<Ehdr.e_shnum;sidx++,sptr++) {
char *name;
name = GetElfSectionName(ScnTbl[sidx].sh_name);
if ((sptr->sh_flags & SHF_ALLOC) &&
(sptr->sh_type != SHT_NOBITS) && (sptr->sh_size)) {
sprintf(zoutfile,"_%s_%d.zip",name,sidx);
unlink(zoutfile);
cp = (uchar *)Malloc(sptr->sh_size);
Lseek(elfFD,sptr->sh_offset,SEEK_SET);
read(elfFD,cp,sptr->sh_size);
zout = gzopen(zoutfile, mode);
if (zout == NULL) {
fprintf(stderr, "can't gzopen %s\n", zoutfile);
exit(1);
}
if (gzwrite(zout, cp, (unsigned)sptr->sh_size) != sptr->sh_size) {
fprintf(stderr, "gzwrite failed\n");
exit(1);
}
if (gzclose(zout) != Z_OK) {
fprintf(stderr, "gzclose failed\n");
exit(1);
}
free(cp);
stat(zoutfile,&zstat);
printf("Sec %-8s compressed from %8d to %8d bytes.\n",
name,sptr->sh_size,zstat.st_size);
reduction += (sptr->sh_size - zstat.st_size);
}
free(name);
}
printf("Total reduction: %d bytes\n",reduction);
/* Create the destination file... */
unlink(zipto);
if ((zipfd = open(zipto,O_WRONLY|O_BINARY|O_CREAT,0777))==-1)
{
perror(zipto);
exit(1);
}
/* Do a blind copy of all data up to the start of the first
* section. Note that it is not required that the sections be
* listed in ScnTbl[] in the same order as they are arranged within
* the file, so we must determine which section in the table is first
* in the file. Use the lowest_section_offset variable as a pointer
* to the first location in the new file into which the compressed
* sections can be placed.
*
* Fix...
* Turns out that the "blind copy" approach wastes memory in certain
* cases... For some reason some elf files have an empty 64K
* block of space between the end of the program header table and the
* first section, so this meant that a 64k block of space was wasted.
*
* In the first fix for the above problem, the lowest_section_offset
* pointed to the address just after the end of the file header (below
* the wasted 64k block). This was incorrect because it chopped off
* the program header; hence, now the lowest_sectino_offset points to
* the address just after the program header...
*/
#if 0 /* first version... */
if (verbose)
fprintf(stderr,"Copying first %ld bytes\n",ScnTbl[1].sh_offset);
Lseek(elfFD,0,SEEK_SET);
lowest_section_offset = FindLowestSectionInFile();
cp = Malloc(lowest_section_offset);
Read(elfFD,cp,lowest_section_offset);
Write(zipfd,cp,lowest_section_offset);
free(cp);
#else
if (verbose)
fprintf(stderr,"Copying ELF file & program hdr\n");
Lseek(elfFD,0,SEEK_SET);
lowest_section_offset = Ehdr.e_phoff+(Ehdr.e_phentsize*Ehdr.e_phnum);
cp = Malloc(lowest_section_offset);
Read(elfFD,cp,lowest_section_offset);
Write(zipfd,cp,lowest_section_offset);
free(cp);
#endif
offset_delta = 0;
/* For each section, copy from original file or from zipped file to */
/* the new file... */
for(sptr=&ScnTbl[1],sidx=1;sidx<Ehdr.e_shnum;sidx++,sptr++) {
char *name;
sptr_z = scntbl_z+sidx;
name = GetElfSectionName(ScnTbl[sidx].sh_name);
if ((sptr->sh_flags & SHF_ALLOC) &&
(sptr->sh_type != SHT_NOBITS) && (sptr->sh_size)) {
int secfd;
sprintf(zoutfile,"_%s_%d.zip",name,sidx);
stat(zoutfile,&zstat);
if (verbose)
fprintf(stderr,"Replacing sec %s with %s (%d bytes)\n",
name,zoutfile,zstat.st_size);
sptr_z->sh_size = zstat.st_size;
#if USE_OFFSET_DELTA
sptr_z->sh_offset -= offset_delta;
#else
sptr_z->sh_offset = tell(zipfd);
#endif
if(debug) {
fprintf(stderr,"offset_delta += %d (%d-%d)\n",
(sptr->sh_size - sptr_z->sh_size),sptr->sh_size,
sptr_z->sh_size);
}
offset_delta += (sptr->sh_size - sptr_z->sh_size);
if ((secfd = open(zoutfile,O_RDONLY|O_BINARY)) == -1) {
fprintf(stderr,"Couldn't open %s\n",zoutfile);
exit(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -