From: dtrg Date: Mon, 23 Apr 2007 23:40:10 +0000 (+0000) Subject: Added the aelflod tool for generating ELF executables. Added documentation for aelflo... X-Git-Tag: release-6-0-pre-2~8 X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=f471d2e61861f393770980b44bb09a928b6468e3;p=ack.git Added the aelflod tool for generating ELF executables. Added documentation for aelflod and ashow. Now installs the documentation when built. --- diff --git a/util/amisc/aelflod.1 b/util/amisc/aelflod.1 new file mode 100644 index 000000000..6e22d53d2 --- /dev/null +++ b/util/amisc/aelflod.1 @@ -0,0 +1,25 @@ +.TH ASLOD 1 "$Revision$" +.SH NAME +aelflod \- ACK ELF loader +.SH SYNOPSIS +aelflod [-h] inputfile outputfile +.SH DESCRIPTION +.I aelflod +converts an absolute ack.out file into a simple binary memory +dump wrapped up in an ELF executable. It is suitable for producing +executables for operating systems such as Linux. + +The input file must contain exactly four segments: TEXT, ROM, +DATA and BSS, in that order, all occupying contiguous memory. +The file must have all references resolved and be linked to a +fixed address. The fixed address must be at least 0x54 bytes +greater than a page boundary, in order to make room for the ELF +header itself. + +aelflod will write out an ELF header followed by each segment, in +order, ensuring that enough padding is inserted between each segment +to keep the offsets correct. The created executable will contain just +one rwx segment, and no sections. + +.SH "SEE ALSO" +ack.out(5) diff --git a/util/amisc/aelflod.c b/util/amisc/aelflod.c new file mode 100644 index 000000000..0e04b2421 --- /dev/null +++ b/util/amisc/aelflod.c @@ -0,0 +1,460 @@ +/* + * $Source$ + * $State$ + * + * Simple tool to produce an utterly basic ELF executable + * from an absolute ack.out file. Suitable for operating + * systems like Linux. + * + * This tool produces an executable with a program header + * only and no section header. + * + * Mostly pinched from the ARM cv (and then rewritten in + * ANSI C). Which, according to the comment, was pinched + * from m68k2; therefore I am merely continuing a time- + * honoured tradition. + * + * (I was 10 when the original for this was checked into + * CVS...) + * + * dtrg, 2006-10-17 + */ + +#include +#include +#include +#include +#include "out.h" + +#define ASSERT(x) switch (2) { case 0: case (x): ; } + +/* Global settings. */ + +int bigendian = 0; +int elfmachine; + +/* Header and section table of an ack object file. */ + +struct outhead outhead; +struct outsect outsect[S_MAX]; +char* stringarea; + +char* outputfile = NULL; /* Name of output file, or NULL */ +char* program; /* Name of current program: argv[0] */ + +FILE* input; /* Input stream */ +FILE* output; /* Output stream */ + +#define readf(a, b, c) fread((a), (b), (int)(c), input) +#define writef(a, b, c) fwrite((a), (b), (int)(c), output) + +/* Header and program header table of an ELF object file. */ + +#define ELF_HEADER_SIZE 0x34 +#define PROGRAM_HEADER_SIZE 0x20 +#define PROGRAM_HEADER_COUNT 1 +unsigned long codeoffset; + +const char elf_le_ident_string[] = { + 0x7F, 'E', 'L', 'F' +}; + +/* Output file definitions and such */ + +#define HDR_LENGTH 32 + +char hdr[HDR_LENGTH] ; + +/* Segment numbers understood by aslod. */ + +enum { + TEXT = 0, + ROM, + DATA, + BSS, + NUM_SEGMENTS +}; + +#define N_EXT 040 +#define N_UNDEF 00 +#define N_ABS 01 +#define N_TEXT 02 +#define N_DATA 03 +#define N_BSS 04 +#define N_FN 037 + +/* Produce an error message and exit. */ + +void fatal(const char* s, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ",program) ; + + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); + + fprintf(stderr, "\n"); + + if (outputfile) + unlink(outputfile); + exit(1); +} + +/* Calculate the result of a aligned to b (rounding up if necessary). + * b must be a power of two. */ + +long align(long a, long b) +{ + a += b - 1; + return a & ~(b-1); +} + +int follows(struct outsect* pa, struct outsect* pb) +{ + /* return 1 if pa follows pb */ + + return (pa->os_base == align(pb->os_base+pb->os_size, pa->os_lign)); +} + +/* Writes a byte. */ + +void emit8(unsigned char value) +{ + writef(&value, 1, 1); +} + +/* Writes out 16 and 32 bit words in the appropriate endianness. */ + +void emit16(unsigned short value) +{ + unsigned char buffer[2]; + + if (bigendian) + { + buffer[0] = (value >> 8) & 0xFF; + buffer[1] = (value >> 0) & 0xFF; + } + else + { + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + } + + writef(buffer, 1, sizeof(buffer)); +} + +void emit32(unsigned long value) +{ + unsigned char buffer[4]; + + if (bigendian) + { + buffer[0] = (value >> 24) & 0xFF; + buffer[1] = (value >> 16) & 0xFF; + buffer[2] = (value >> 8) & 0xFF; + buffer[3] = (value >> 0) & 0xFF; + } + else + { + buffer[3] = (value >> 24) & 0xFF; + buffer[2] = (value >> 16) & 0xFF; + buffer[1] = (value >> 8) & 0xFF; + buffer[0] = (value >> 0) & 0xFF; + } + + writef(buffer, 1, sizeof(buffer)); +} + +/* Copies the contents of a section from the input stream + * to the output stream. */ + +void emits(struct outsect* section) +{ + char buffer[BUFSIZ]; + long n = section->os_flen; + while (n > 0) + { + int blocksize = (n > BUFSIZ) ? BUFSIZ : n; + readf(buffer, 1, blocksize); + writef(buffer, 1, blocksize); + n -= blocksize; + } + + /* Zero fill any remaining space. */ + + if (section->os_flen != section->os_size) + { + long n = section->os_size - section->os_flen; + memset(buffer, 0, BUFSIZ); + + while (n > 0) + { + int blocksize = (n > BUFSIZ) ? BUFSIZ : n; + writef(buffer, 1, blocksize); + n -= blocksize; + } + } +} + +/* Writes out an ELF program header. */ + +void emitphdr(unsigned long address, unsigned long filesize, + unsigned int memsize, unsigned int alignment, int flags) +{ + static unsigned long fileoffset = 0; + + emit32(1); /* type = PT_LOAD */ + emit32(fileoffset); /* file offset */ + emit32(address); /* virtual address */ + emit32(0); /* physical address */ + emit32(filesize); /* file size */ + emit32(memsize); /* memory size */ + emit32(flags); /* executable, readable, writable */ + emit32(alignment); /* alignment */ + + fileoffset += filesize; +} + +void iconvert(char* buf, char* str, char* fmt) +{ + register char *nf, *ni, *no ; + int last, i ; + long value ; + ni=buf ; no=str ; nf=fmt ; + while ( last = *nf++ ) { + last -= '0' ; + if ( last<1 || last >9 ) fatal("illegal out.h format string\n"); + value=0 ; + i=last ; + while ( i-- ) { + value = (value<<8) + (ni[i]&0xFF) ; + } + switch ( last ) { + case 0 : break ; + case 1 : *no= value ; break ; + case 2 : *(unsigned short *)no = value ; break ; + case 4 : *(long *)no = value ; break ; + default : + fatal("illegal out.h format string\n"); + } + ni += last ; no += last ; + } +} + +/* Read the ack.out file header. */ + +int rhead(FILE* f, struct outhead* head) +{ + char buf[sizeof(struct outhead)]; + + if (fread(buf, sizeof(buf), 1, f) != 1) + return 0; + + iconvert(buf, (char*) head, SF_HEAD); + return 1; +} + +/* Read an ack.out section header. */ + +int rsect(FILE* f, struct outsect* sect) +{ + char buf[sizeof(struct outsect)]; + + if (fread(buf, sizeof(buf), 1, f) != 1) + return 0; + + iconvert(buf, (char*) sect, SF_SECT); + return 1 ; +} + +int main(int argc, char* argv[]) +{ + /* General housecleaning and setup. */ + + input = stdin; + output = stdout; + program = argv[0]; + + /* Read in and process any flags. */ + + while ((argc > 1) && (argv[1][0] == '-')) + { + switch (argv[1][1]) + { + case 'h': + fprintf(stderr, "%s: Syntax: aslod [-h] \n", + program); + exit(0); + + default: + syntaxerror: + fatal("syntax error --- try -h for help)"); + } + + argv++; + argc--; + } + + /* Process the rest of the arguments. */ + + switch (argc) + { + case 1: /* No parameters --- read from stdin, write to stdout. */ + break; + + case 3: /* Both input and output files specified. */ + output = fopen(argv[2], "w"); + if (!output) + fatal("unable to open output file."); + outputfile = argv[2]; + /* fall through */ + + case 2: /* Input file specified. */ + input = fopen(argv[1], "r"); + if (!input) + fatal("unable to open input file."); + break; + + default: + goto syntaxerror; + } + + /* Read and check the ack.out file header. */ + + if (!rhead(input,&outhead)) + fatal("failed to read file header."); + if (BADMAGIC(outhead)) + fatal("this isn't an ack object file."); + if (outhead.oh_nrelo > 0) + fprintf(stderr, "Warning: relocation information present."); + if (!((outhead.oh_nsect == NUM_SEGMENTS) || + (outhead.oh_nsect == (NUM_SEGMENTS+1)))) + fatal("the input file must have %d sections, not %ld.", + NUM_SEGMENTS, outhead.oh_nsect); + + /* Read in the section headers. */ + + { + int i; + for (i=0; i