diff options
Diffstat (limited to 'ld/catimage.c')
-rw-r--r-- | ld/catimage.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/ld/catimage.c b/ld/catimage.c new file mode 100644 index 0000000..7d5c7a0 --- /dev/null +++ b/ld/catimage.c @@ -0,0 +1,238 @@ +/* + * This program concatenates memory images the executables specified + * on it's command line. + * + * The 'boot' image must have a symbol table any symbols that match + * the below patterns have their values patched. + * + * int __seg0_text; - Always zero + * int __seg0_data; - Segment offset of data of boot executable + * + * int __seg1_text; - Segment offset of text of first executable + * int __seg1_data; - Segment offset of data of first executable + * int __seg2_text; - Segment offset of text of second executable + * int __seg2_data; - Segment offset of data of second executable + * + * int __seg9_text; - Segment offset of text of executable nine + * int __seg9_data; - Segment offset of data of executable nine + * + * Any segment that's not an exact multiple of 16 bytes long is rounded up. + * + */ + +#include <stdio.h> +#include "x86_aout.h" + +#ifndef __OUT_OK +#error "Compile error: struct exec invalid (long not 32 bit ?)" +#endif + +unsigned long text_offt[10]; /* Locations to patch (0=don't) */ +unsigned long data_offt[10]; + +char * input_file = ""; +FILE * ofd; +FILE * ifd = 0; +struct exec header; + +main(argc, argv) +int argc; +char ** argv; +{ + long image_offset, text_off; + int image_id; + + if( argc < 3 || argc > 11 ) + fatal("Usage: catimage mem.bin boot.out [a1.out] ... [a9.out]"); + + open_obj(argv[2]); + + ofd = fopen(argv[1], "w"); + if( ofd == 0 ) fatal("Cannot open output file"); + + read_symtable(); + + image_offset = 0; + + for(image_id=0; image_id < argc-2; image_id++) + { + open_obj(argv[image_id+2]); + + printf("File %-14s seg=0x%04lx text=0x%04lx data=0x%04lx\n", + input_file, (image_offset>>4), + (header.a_text>>4), (header.a_total>>4)); + + text_off = image_offset; + if( header.a_flags & A_SEP ) + { + copy_segment(image_offset, A_TEXTPOS(header), header.a_text); + image_offset += header.a_text; + image_offset = ((image_offset+15L)&-16L); + + copy_segment(image_offset, A_DATAPOS(header), header.a_data); + } + else + { + copy_segment(image_offset, A_TEXTPOS(header), + header.a_text+header.a_data); + } + + patch_bin(text_offt[image_id], (unsigned)(text_off>>4)); + patch_bin(data_offt[image_id], (unsigned)(image_offset>>4)); + + image_offset += header.a_total; + image_offset = ((image_offset+15L)&-16L); + } + + if( fseek(ofd, image_offset-1, 0) < 0 ) + fatal("Cannot seek to end of output"); + + fputc('\0', ofd); + fclose(ofd); + + printf("Output file size %ldKb\n", ((image_offset+0x3FF)>>10)); + + if( ifd ) fclose(ifd); + exit(0); +} + +open_obj(fname) +char * fname; +{ + input_file = fname; + + if( ifd ) fclose(ifd); + + ifd = fopen(fname, "r"); + if( ifd == 0 ) fatal("Cannot open input file"); + + if( fread(&header, A_MINHDR, 1, ifd) != 1 ) + fatal("Incomplete executable header"); + + if( BADMAG(header) ) + fatal("Input file has bad magic number"); +} + +copy_segment(out_offset, in_offset, length) +long out_offset, in_offset, length; +{ + char buffer[1024]; + int ssize; + long bsize = length; + + if( fseek(ifd, in_offset, 0) < 0 ) + fatal("Cannot seek to start of input segment"); + + if( fseek(ofd, out_offset, 0) < 0 ) + fatal("Cannot seek to start of output segment"); + + while(bsize>0) + { + if( bsize > sizeof(buffer) ) ssize = sizeof(buffer); + else ssize = bsize; + + if( (ssize=fread(buffer, 1, ssize, ifd)) <= 0 ) + fatal("Error reading segment from executable"); + if( fwrite(buffer, 1, ssize, ofd) != ssize ) + fatal("Error writing output file"); + bsize -= ssize; + } +} + +patch_bin(file_off, value) +long file_off; +int value; +{ + char wbuf[4]; + if( file_off <= 0 ) return; + + printf("Patch at offset 0x%05lx = %04x\n", file_off, value); + + wbuf[0] = value; + wbuf[0] = (value>>8); + + if( fseek(ofd, file_off, 0) < 0 ) + fatal("Cannot seek to patch binary"); + + if( fwrite(wbuf, 1, 2, ofd) != 2 ) + fatal("Error patching output file"); +} + +read_symtable() +{ + struct nlist item; + int nitems; + long base_off = 0; + + if( header.a_syms == 0 ) + fatal("Input file has been stripped!"); + + if( fseek(ifd, A_SYMPOS(header), 0) < 0 ) + fatal("Cannot seek to start of symbols"); + + nitems = header.a_syms; + + /* Foreach symbol */ + while( fread(&item, sizeof(struct nlist), 1, ifd) == 1 ) + { + if( nitems-- <= 0 ) break; + + /* Match the name */ + if( memcmp(item.n_name, "__seg", 5) != 0 || item.n_name[6] != '_' ) + continue; + + /* Externals only */ + if( (item.n_sclass & N_CLASS) != C_EXT ) + continue; + + /* Data seg only */ + if( (item.n_sclass & N_SECT) != N_DATA && + (item.n_sclass & N_SECT) != N_BSS && + (item.n_sclass & N_SECT) != N_TEXT ) + continue; + + if( item.n_name[5] < '0' || item.n_name[5] > '9' ) + continue; + + if( (header.a_flags & A_SEP) && (item.n_sclass & N_SECT) != N_TEXT ) + base_off = header.a_text; + else + base_off = 0; + + switch( item.n_name[7] ) + { + case 'd': data_offt[item.n_name[5]-'0'] = base_off+item.n_value; break; + case 't': text_offt[item.n_name[5]-'0'] = base_off+item.n_value; break; + } + +#ifdef DEBUG + printf("%-8.8s ", item.n_name); + printf("%08lx ", item.n_value); + switch(item.n_sclass & N_CLASS) + { + case C_NULL: printf("C_NULL "); break; + case C_EXT: printf("C_EXT "); break; + case C_STAT: printf("C_STAT "); break; + default: printf("%-6d ", (item.n_sclass & N_CLASS)); break; + } + switch(item.n_sclass & N_SECT) + { + case N_UNDF: printf("N_UNDF "); break; + case N_ABS : printf("N_ABS "); break; + case N_TEXT: printf("N_TEXT "); break; + case N_DATA: printf("N_DATA "); break; + case N_BSS : printf("N_BSS "); break; + case N_COMM: printf("N_COMM "); break; + } + printf("\n"); +#endif + } +} + +fatal(str) +char * str; +{ + fprintf(stderr, "catimage:%s: %s\n", input_file, str); + exit(2); +} + |