CPU = @target_cpu@
TARGET = @target_alias@
CFLAGS = @CFLAGS@
-INCLUDES = @bfd_include_dir@ @binutils_include_dir@
+INCLUDES = @bfd_include_dir@ @binutils_include_dir@ @zlib_include_dir@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
all: $(PROGS)
-$(PROG_ELF2FLT): elf2flt.c stubs.c Makefile
- $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $(srcdir)/elf2flt.c $(srcdir)/stubs.c $(LIBS)
+$(PROG_ELF2FLT): $(srcdir)/elf2flt.c compress.o $(srcdir)/stubs.c
+ $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
-$(PROG_FLTHDR): flthdr.c Makefile
- $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $(srcdir)/flthdr.c $(LIBS)
+$(PROG_FLTHDR): $(srcdir)/flthdr.c compress.o
+ $(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+Makefile: $(srcdir)/Makefile.in
+ ./config.status $@
clean:
-rm -f $(PROGS) *.$(OBJEXT)
--- /dev/null
+/*
+ * Helper functions to handle compression via zlib
+ *
+ * Copyright (C) 2007-2008 Julian Brown
+ * Copyright (C) 2008 Mike Frysinger
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <zlib.h>
+#include "compress.h"
+
+/* Open an (uncompressed) file as a stream. Return 0 on success, 1 on
+ error.
+ NOTE: The MODE argument must remain valid for the lifetime of the stream,
+ because it is referred to by reopen_stream_compressed() if it is called.
+ String constants work fine. */
+
+int
+fopen_stream_u(stream *fp, const char *path, const char *mode)
+{
+ fp->u.filep = fopen(path, mode);
+ fp->type = (fp->u.filep) ? UNCOMPRESSED : INVALID;
+ fp->mode = mode;
+ return (fp->u.filep) ? 0 : 1;
+}
+
+/* Read from stream. Return number of elements read. */
+
+size_t
+fread_stream(void *ptr, size_t size, size_t nmemb, stream *str)
+{
+ size_t read;
+
+ switch (str->type) {
+ case UNCOMPRESSED:
+ read = fread(ptr, size, nmemb, str->u.filep);
+ break;
+
+ case COMPRESSED:
+ read = gzread(str->u.gzfilep, ptr, size * nmemb) / size;
+ break;
+
+ default:
+ abort();
+ }
+
+ return read;
+}
+
+/* Write to stream. Return number of elements written. */
+
+size_t
+fwrite_stream(const void *ptr, size_t size, size_t nmemb, stream *str)
+{
+ size_t written;
+
+ switch (str->type) {
+ case UNCOMPRESSED:
+ written = fwrite(ptr, size, nmemb, str->u.filep);
+ break;
+
+ case COMPRESSED:
+ written = gzwrite(str->u.gzfilep, ptr, size * nmemb) / size;
+ break;
+
+ default:
+ abort();
+ }
+
+ return written;
+}
+
+/* Close stream. */
+
+int
+fclose_stream(stream *str)
+{
+ switch (str->type) {
+ case UNCOMPRESSED:
+ return fclose(str->u.filep);
+
+ case COMPRESSED:
+ return gzclose(str->u.gzfilep);
+
+ default:
+ abort();
+ }
+
+ return 0;
+}
+
+int
+ferror_stream(stream *str)
+{
+ switch (str->type) {
+ case UNCOMPRESSED:
+ return ferror(str->u.filep);
+
+ case COMPRESSED:
+ {
+ const char *err;
+ int errno;
+
+ err = gzerror(str->u.gzfilep, &errno);
+ if (errno == Z_OK || errno == Z_STREAM_END)
+ return 0;
+ else if (errno == Z_ERRNO)
+ return 1;
+ else {
+ fprintf(stderr, "%s\n", err);
+ return 1;
+ }
+ }
+ break;
+
+ default:
+ abort();
+ }
+
+ return 0;
+}
+
+/* Reopen a stream at the current file position. */
+
+void
+reopen_stream_compressed(stream *str)
+{
+ int fd;
+ long offset, roffset;
+
+ /* Already a compressed stream, return immediately */
+ if (str->type == COMPRESSED)
+ return;
+
+ if (str->type == INVALID)
+ abort();
+
+ fd = fileno(str->u.filep);
+ /* Get current (buffered) file position. */
+ offset = ftell(str->u.filep);
+
+ /* Make sure there's nothing left in buffers. */
+ fflush(str->u.filep);
+
+ /* Reposition underlying FD. (Might be unnecessary?) */
+ roffset = lseek(fd, offset, SEEK_SET);
+
+ assert(roffset == offset);
+
+ /* Reopen as compressed stream. */
+ str->u.gzfilep = gzdopen(fd, str->mode);
+ gzsetparams(str->u.gzfilep, 9, Z_DEFAULT_STRATEGY);
+ str->type = COMPRESSED;
+}
+
+void
+transfer(stream *ifp, stream *ofp, int count)
+{
+ char cmd[1024];
+ int n, num;
+
+ while (count == -1 || count > 0) {
+ if (count == -1 || count > sizeof(cmd))
+ num = sizeof(cmd);
+ else
+ num = count;
+ n = fread_stream(cmd, 1, num, ifp);
+ if (n == 0)
+ break;
+ if (fwrite_stream(cmd, n, 1, ofp) != 1) {
+ fprintf(stderr, "Write failed :-(\n");
+ exit(1);
+ }
+ if (count != -1)
+ count -= n;
+ }
+ if (count > 0) {
+ fprintf(stderr, "Failed to transfer %d bytes\n", count);
+ exit(1);
+ }
+}
--- /dev/null
+/*
+ * Helper functions to handle compression via zlib
+ *
+ * Copyright (C) 2007-2008 Julian Brown
+ * Copyright (C) 2008 Mike Frysinger
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __ELF2FLT_COMPRESS_H__
+#define __ELF2FLT_COMPRESS_H__
+
+#include <zlib.h>
+
+typedef enum
+{
+ INVALID,
+ UNCOMPRESSED,
+ COMPRESSED
+} stream_type;
+
+/* Tagged union holding either a regular FILE* handle or a zlib gzFile
+ handle. */
+typedef struct
+{
+ stream_type type;
+ const char *mode;
+ union
+ {
+ FILE *filep;
+ gzFile gzfilep;
+ } u;
+} stream;
+
+int fopen_stream_u(stream *fp, const char *path, const char *mode);
+size_t fread_stream(void *ptr, size_t size, size_t nmemb, stream *str);
+size_t fwrite_stream(const void *ptr, size_t size, size_t nmemb, stream *str);
+int fclose_stream(stream *str);
+int ferror_stream(stream *str);
+void reopen_stream_compressed(stream *str);
+void transfer(stream *ifp, stream *ofp, int count);
+
+#endif
dnl Process this file with autoconf to produce a configure script.
AC_INIT(elf2flt.c)
+AC_ARG_WITH(zlib-prefix,
+ [ --with-zlib-prefix=<dir> path to installed zlib ],
+ [ ac_zlib_prefix=$withval ],
+ [ ac_zlib_prefix=NONE ]
+)
+
AC_ARG_WITH(libbfd,
[ --with-libbfd=<file> path to libbfd.a library to use ],
[ ac_libbfd=$withval ],
else
LIBS="$ac_libbfd $LIBS"
fi
+if test "$ac_zlib_prefix" = "NONE"; then
+ AC_CHECK_LIB(z, deflate)
+else
+ LIBS="-L$ac_zlib_prefix/lib -lz $LIBS"
+fi
bfd_include_dir=
if test "$ac_bfd_include_dir" != "NONE"; then
binutils_include_dir="-I$ac_binutils_include_dir"
fi
+zlib_include_dir=
+if test "$ac_zlib_prefix" != "NONE"; then
+ zlib_include_dir="-I$ac_zlib_prefix/include"
+fi
+
binutils_ldscript_dir=
if test "$ac_binutils_ldscript_dir" = "NONE"; then
ac_binutils_ldscript_dir="\${TOOLDIR}/../${target_alias}/lib"
AC_SUBST(target_vendor)
AC_SUBST(bfd_include_dir)
AC_SUBST(binutils_include_dir)
+AC_SUBST(zlib_include_dir)
AC_SUBST(binutils_ldscript_dir)
AC_SUBST(got_check)
AC_SUBST(emit_relocs)
/* from uClinux-x.x.x/include/linux */
#include "flat.h" /* Binary flat header description */
+#include "compress.h"
#ifdef TARGET_e1
#include <e1.h>
int pic_with_got = 0; /* do elf/got processing with PIC code */
int load_to_ram = 0; /* instruct loader to allocate everything into RAM */
int ktrace = 0; /* instruct loader output kernel trace on load */
-int compress = 0; /* 1 = compress everything, 2 = compress data only */
+int docompress = 0; /* 1 = compress everything, 2 = compress data only */
int use_resolved = 0; /* If true, get the value of symbol references from */
/* the program contents, not from the relocation table. */
/* In this case, the input ELF file must be already */
/* Write NUM zeroes to STREAM. */
-static void write_zeroes (unsigned long num, FILE *stream)
+static void write_zeroes (unsigned long num, stream *stream)
{
char zeroes[1024];
if (num > 0) {
work for stdio output files. */
memset(zeroes, 0x00, 1024);
while (num > sizeof(zeroes)) {
- fwrite(zeroes, sizeof(zeroes), 1, stream);
+ fwrite_stream(zeroes, sizeof(zeroes), 1, stream);
num -= sizeof(zeroes);
}
if (num > 0)
- fwrite(zeroes, num, 1, stream);
+ fwrite_stream(zeroes, num, 1, stream);
}
}
int opt;
int i;
int stack;
- char cmd[1024];
- FILE *gf = NULL;
+ stream gf;
asymbol **symbol_table;
long number_of_symbols;
struct flat_hdr hdr;
- int gf_is_pipe = 0;
-
program = argv[0];
progname = argv[0];
xmalloc_set_program_name(program);
ktrace++;
break;
case 'z':
- compress = 1;
+ docompress = 1;
break;
case 'd':
- compress = 2;
+ docompress = 2;
break;
case 'p':
pfile = optarg;
| (load_to_ram ? FLAT_FLAG_RAM : 0)
| (ktrace ? FLAT_FLAG_KTRACE : 0)
| (pic_with_got ? FLAT_FLAG_GOTPIC : 0)
- | (compress ? (compress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
+ | (docompress ? (docompress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
);
hdr.build_date = htonl((unsigned long)time(NULL));
memset(hdr.filler, 0x00, sizeof(hdr.filler));
write(fd, &hdr, sizeof(hdr));
close(fd);
- /*
- * get the compression command ready
- */
- sprintf(cmd, "gzip -f -9 >> %s", ofile);
-
-#define START_COMPRESSOR do { \
- if (gf) \
- if (gf_is_pipe) \
- pclose(gf); \
- else \
- fclose(gf); \
- if (!(gf = popen(cmd, "w" BINARY_FILE_OPTS))) { \
- fprintf(stderr, "Can't run cmd %s\n", cmd); \
- exit(4); \
- } \
- gf_is_pipe = 1; \
- } while (0)
-
- gf = fopen(ofile, "ab"); /* Add 'b' to support non-posix (ie windows) */
- if (!gf) {
- fprintf(stderr, "Can't open file %s for writing\n", ofile); \
- exit(4);
+ if (fopen_stream_u(&gf, ofile, "a" BINARY_FILE_OPTS)) {
+ fprintf(stderr, "Can't open file %s for writing\n", ofile);
+ exit(4);
}
- if (compress == 1)
- START_COMPRESSOR;
+ if (docompress == 1)
+ reopen_stream_compressed(&gf);
/* Fill in any hole at the beginning of the text segment. */
if (verbose)
- printf("ZERO before text len=0x%x\n", text_offs);
- write_zeroes(text_offs, gf);
+ printf("ZERO before text len=0x%x\n", text_offs);
+ write_zeroes(text_offs, &gf);
/* Write the text segment. */
- fwrite(text, text_len, 1, gf);
+ fwrite_stream(text, text_len, 1, &gf);
- if (compress == 2)
- START_COMPRESSOR;
+ if (docompress == 2)
+ reopen_stream_compressed(&gf);
/* Write the data segment. */
- fwrite(data, data_len, 1, gf);
+ fwrite_stream(data, data_len, 1, &gf);
if (reloc)
- fwrite(reloc, reloc_len * 4, 1, gf);
+ fwrite_stream(reloc, reloc_len * 4, 1, &gf);
- if(gf_is_pipe)
- pclose(gf);
- else
- fclose(gf);
+ fclose_stream(&gf);
exit(0);
}
#include <time.h>
#include <stdlib.h> /* exit() */
#include <string.h> /* strcat(), strcpy() */
+#include <assert.h>
/* macros for conversion between host and (internet) network byte order */
#ifndef WIN32
#define BINARY_FILE_OPTS "b"
#endif
+#include "compress.h"
+#include <libiberty.h>
+
/* from uClinux-x.x.x/include/linux */
#include "flat.h" /* Binary flat header description */
char *program_name;
-static char cmd[1024];
-static int print = 0, compress = 0, ramload = 0, stacksize = 0, ktrace = 0;
-
-/****************************************************************************/
+static int print = 0, docompress = 0, ramload = 0, stacksize = 0, ktrace = 0;
-void
-transferr(FILE *ifp, FILE *ofp, int count)
-{
- int n, num;
-
- while (count == -1 || count > 0) {
- if (count == -1 || count > sizeof(cmd))
- num = sizeof(cmd);
- else
- num = count;
- n = fread(cmd, 1, num, ifp);
- if (n == 0)
- break;
- if (fwrite(cmd, n, 1, ofp) != 1) {
- fprintf(stderr, "Write failed :-(\n");
- exit(1);
- }
- if (count != -1)
- count -= n;
- }
- if (count > 0) {
- fprintf(stderr, "Failed to transferr %d bytes\n", count);
- exit(1);
- }
-}
-
/****************************************************************************/
void
process_file(char *ifile, char *ofile)
{
int old_flags, old_stack, new_flags, new_stack;
- FILE *ifp, *ofp;
- int ofp_is_pipe = 0;
+ stream ifp, ofp;
struct flat_hdr old_hdr, new_hdr;
- char tfile[256];
- char tfile2[256];
+ char *tfile, tmpbuf[256];
+ int input_error, output_error;
- *tfile = *tfile2 = '\0';
+ *tmpbuf = '\0';
- if ((ifp = fopen(ifile, "r" BINARY_FILE_OPTS)) == NULL) {
+ if (fopen_stream_u(&ifp, ifile, "r" BINARY_FILE_OPTS)) {
fprintf(stderr, "Cannot open %s\n", ifile);
return;
}
- if (fread(&old_hdr, sizeof(old_hdr), 1, ifp) != 1) {
+ if (fread_stream(&old_hdr, sizeof(old_hdr), 1, &ifp) != 1) {
fprintf(stderr, "Cannot read header of %s\n", ifile);
return;
}
new_stack = old_stack = ntohl(old_hdr.stack_size);
new_hdr = old_hdr;
- if (compress == 1) {
+ if (docompress == 1) {
new_flags |= FLAT_FLAG_GZIP;
new_flags &= ~FLAT_FLAG_GZDATA;
- } else if (compress == 2) {
+ } else if (docompress == 2) {
new_flags |= FLAT_FLAG_GZDATA;
new_flags &= ~FLAT_FLAG_GZIP;
- } else if (compress < 0)
+ } else if (docompress < 0)
new_flags &= ~(FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA);
if (ramload > 0)
printf("-----------------------------------------------------------\n");
first = 0;
}
- *tfile = '\0';
- strcat(tfile, (old_flags & FLAT_FLAG_KTRACE) ? "k" : "");
- strcat(tfile, (old_flags & FLAT_FLAG_RAM) ? "r" : "");
- strcat(tfile, (old_flags & FLAT_FLAG_GOTPIC) ? "p" : "");
- strcat(tfile, (old_flags & FLAT_FLAG_GZIP) ? "z" :
+ *tmpbuf = '\0';
+ strcat(tmpbuf, (old_flags & FLAT_FLAG_KTRACE) ? "k" : "");
+ strcat(tmpbuf, (old_flags & FLAT_FLAG_RAM) ? "r" : "");
+ strcat(tmpbuf, (old_flags & FLAT_FLAG_GOTPIC) ? "p" : "");
+ strcat(tmpbuf, (old_flags & FLAT_FLAG_GZIP) ? "z" :
((old_flags & FLAT_FLAG_GZDATA) ? "d" : ""));
- printf("-%-3.3s ", tfile);
+ printf("-%-3.3s ", tmpbuf);
printf("%3d ", ntohl(old_hdr.rev));
printf("%6d ", text=ntohl(old_hdr.data_start)-sizeof(struct flat_hdr));
printf("%6d ", data=ntohl(old_hdr.data_end)-ntohl(old_hdr.data_start));
new_hdr.flags = htonl(new_flags);
new_hdr.stack_size = htonl(new_stack);
- strcpy(tfile, "/tmp/flatXXXXXX");
- mkstemp(tfile);
- if ((ofp = fopen(tfile, "w" BINARY_FILE_OPTS)) == NULL) {
+ tfile = make_temp_file("flthdr");
+
+ if (fopen_stream_u(&ofp, tfile, "w" BINARY_FILE_OPTS)) {
fprintf(stderr, "Failed to open %s for writing\n", tfile);
unlink(tfile);
- unlink(tfile2);
exit(1);
}
- if (fwrite(&new_hdr, sizeof(new_hdr), 1, ofp) != 1) {
+ /* Copy header (always uncompressed). */
+ if (fwrite_stream(&new_hdr, sizeof(new_hdr), 1, &ofp) != 1) {
fprintf(stderr, "Failed to write to %s\n", tfile);
unlink(tfile);
- unlink(tfile2);
exit(1);
}
- /*
- * get ourselves a fully uncompressed copy of the text/data/relocs
- * so that we can manipulate it more easily
- */
- if (old_flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
- FILE *tfp;
-
- strcpy(tfile2, "/tmp/flat2XXXXXX");
- mkstemp(tfile2);
-
- if (old_flags & FLAT_FLAG_GZDATA) {
- tfp = fopen(tfile2, "w" BINARY_FILE_OPTS);
- if (!tfp) {
- fprintf(stderr, "Failed to open %s for writing\n", tfile2);
- exit(1);
- }
- transferr(ifp, tfp, ntohl(old_hdr.data_start) -
- sizeof(struct flat_hdr));
- fclose(tfp);
- }
-
- sprintf(cmd, "gunzip >> %s", tfile2);
- tfp = popen(cmd, "w" BINARY_FILE_OPTS);
- if(!tfp) {
- perror("popen");
- exit(1);
- }
- transferr(ifp, tfp, -1);
- pclose(tfp);
-
- fclose(ifp);
- ifp = fopen(tfile2, "r" BINARY_FILE_OPTS);
- if (!ifp) {
- fprintf(stderr, "Failed to open %s for reading\n", tfile2);
- unlink(tfile);
- unlink(tfile2);
- exit(1);
- }
- }
+ /* Whole input file (including text) is compressed: start decompressing
+ now. */
+ if (old_flags & FLAT_FLAG_GZIP)
+ reopen_stream_compressed(&ifp);
+ /* Likewise, output file is compressed. Start compressing now. */
if (new_flags & FLAT_FLAG_GZIP) {
printf("zflat %s --> %s\n", ifile, ofile);
- fclose(ofp);
- sprintf(cmd, "gzip -9 -f >> %s", tfile);
- ofp = popen(cmd, "w" BINARY_FILE_OPTS);
- ofp_is_pipe = 1;
- } else if (new_flags & FLAT_FLAG_GZDATA) {
- printf("zflat-data %s --> %s\n", ifile, ofile);
- transferr(ifp, ofp, ntohl(new_hdr.data_start) -
- sizeof(struct flat_hdr));
- fclose(ofp);
- sprintf(cmd, "gzip -9 -f >> %s", tfile);
- ofp = popen(cmd, "w" BINARY_FILE_OPTS);
- ofp_is_pipe = 1;
+ reopen_stream_compressed(&ofp);
}
- if (!ofp) { /* can only happen if using gzip/gunzip */
- fprintf(stderr, "Can't run cmd %s\n", cmd);
- unlink(tfile);
- unlink(tfile2);
- exit(1);
+ transfer(&ifp, &ofp,
+ ntohl(old_hdr.data_start) - sizeof(struct flat_hdr));
+
+ /* Only data and relocs were compressed in input. Start decompressing
+ from here. */
+ if (old_flags & FLAT_FLAG_GZDATA)
+ reopen_stream_compressed(&ifp);
+
+ /* Only data/relocs to be compressed in output. Start compressing
+ from here. */
+ if (new_flags & FLAT_FLAG_GZDATA) {
+ printf("zflat-data %s --> %s\n", ifile, ofile);
+ reopen_stream_compressed(&ofp);
}
- transferr(ifp, ofp, -1);
-
- if (ferror(ifp) || ferror(ofp)) {
+ transfer(&ifp, &ofp, -1);
+
+ input_error = ferror_stream(&ifp);
+ output_error = ferror_stream(&ofp);
+
+ if (input_error || output_error) {
fprintf(stderr, "Error on file pointer%s%s\n",
- ferror(ifp) ? " input" : "", ferror(ofp) ? " output" : "");
+ input_error ? " input" : "",
+ output_error ? " output" : "");
unlink(tfile);
- unlink(tfile2);
exit(1);
}
- fclose(ifp);
- if (ofp_is_pipe)
- pclose(ofp);
- else
- fclose(ofp);
+ fclose_stream(&ifp);
+ fclose_stream(&ofp);
+
+ /* Copy temporary file to output location. */
+ fopen_stream_u(&ifp, tfile, "r" BINARY_FILE_OPTS);
+ fopen_stream_u(&ofp, ofile, "w" BINARY_FILE_OPTS);
+
+ transfer(&ifp, &ofp, -1);
+
+ fclose_stream(&ifp);
+ fclose_stream(&ofp);
- /* cheat a little here to preserve file permissions */
- sprintf(cmd, "cp %s %s", tfile, ofile);
- system(cmd);
unlink(tfile);
- unlink(tfile2);
+ free(tfile);
}
/****************************************************************************/
while ((c = getopt(argc, argv, "pdzZrRkKs:o:")) != EOF) {
switch (c) {
case 'p': print = 1; break;
- case 'z': compress = 1; break;
- case 'd': compress = 2; break;
- case 'Z': compress = -1; break;
+ case 'z': docompress = 1; break;
+ case 'd': docompress = 2; break;
+ case 'Z': docompress = -1; break;
case 'r': ramload = 1; break;
case 'R': ramload = -1; break;
case 'k': ktrace = 1; break;
if (ofile && argc - optind > 1)
usage("-o can only be used with a single file");
-
- if (!print && !compress && !ramload && !stacksize) /* no args == print */
+
+ if (!print && !docompress && !ramload && !stacksize) /* no args == print */
print = argc - optind; /* greater than 1 is short format */
for (c = optind; c < argc; c++) {