elk/src/dump-ecoff.c

220 lines
7.2 KiB
C

/* dump-ecoff.c
*
* $Id$
*
* Copyright 1990, 1991, 1992, 1993, 1994, 1995, Oliver Laumann, Berlin
* Copyright 2002, 2003 Sam Hocevar <sam@hocevar.net>, Paris
*
* This software was derived from Elk 1.2, which was Copyright 1987, 1988,
* 1989, Nixdorf Computer AG and TELES GmbH, Berlin (Elk 1.2 has been written
* by Oliver Laumann for TELES Telematic Services, Berlin, in a joint project
* between TELES and Nixdorf Microprocessor Engineering, Berlin).
*
* Oliver Laumann, TELES GmbH, Nixdorf Computer AG and Sam Hocevar, as co-
* owners or individual owners of copyright in this software, grant to any
* person or company a worldwide, royalty free, license to
*
* i) copy this software,
* ii) prepare derivative works based on this software,
* iii) distribute copies of this software or derivative works,
* iv) perform this software, or
* v) display this software,
*
* provided that this notice is not removed and that neither Oliver Laumann
* nor Teles nor Nixdorf are deemed to have made any representations as to
* the suitability of this software for any purpose nor are held responsible
* for any defects of this software.
*
* THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE.
*/
#include <fcntl.h>
#include <sys/types.h>
#include <filehdr.h>
#include <aouthdr.h>
#include <scnhdr.h>
#include <sym.h>
extern char *sbrk();
/* Find section header of section with given name.
*/
#define FIND_SECTHDR(name,ptr) {\
char err[100];\
int _i;\
for (_i = 0; _i < fhdr.f_nscns; _i++)\
if (strncmp (sect[_i].s_name, (name), sizeof(sect[_i].s_name)) == 0)\
break;\
if (_i == fhdr.f_nscns) {\
Dump_Finalize;\
sprintf (err, "running a.out doesn't have %s section", (name));\
Primitive_Error (err);\
}\
(ptr) = sect+_i;\
}
#define MAX_SECTS 20
Object P_Dump (Object ofile) {
struct filehdr fhdr;
struct aouthdr ahdr;
struct scnhdr sect[MAX_SECTS];
struct scnhdr *sp, *datap;
unsigned long int data_start, data_end, delta;
int mask, n;
HDRR shdr;
char buf[4096];
Dump_Prolog;
/* Read file header, optional header, and section headers from
* running a.out; locate .data section.
* Reading the headers is not really necessary, as they get
* mapped into the address space on startup.
* However, we do not know where exactly they get mapped and
* whether they haven't been modified.
*/
if (read (afd, (char *)&fhdr, sizeof (fhdr)) != sizeof (fhdr) ||
read (afd, (char *)&ahdr, sizeof (ahdr)) != sizeof (ahdr)) {
Dump_Finalize;
Primitive_Error ("error reading a.out headers: ~E");
}
if (fhdr.f_nscns > MAX_SECTS) {
Dump_Finalize;
Primitive_Error ("too many sections in a.out");
}
if (read (afd, (char *)sect, fhdr.f_nscns * sizeof (sect[0])) !=
fhdr.f_nscns * sizeof (sect[0])) {
Dump_Finalize;
Primitive_Error ("error reading section headers: ~E");
}
FIND_SECTHDR (_DATA, datap);
/* Adjust optional header and size of data segment
*/
data_start = datap->s_vaddr;
mask = getpagesize () - 1;
data_end = (unsigned long int)sbrk (0) + mask & ~mask;
delta = data_end - data_start - datap->s_size;
ahdr.dsize = data_end - ahdr.data_start;
ahdr.bsize = 0;
ahdr.bss_start = ahdr.data_start + ahdr.dsize;
datap->s_size += delta;
/* Deactivate sections that aren't really needed (such as bss).
* Actually, the section type should be set to STYP_DSECT (dummy section),
* but this causes the linker to complain next time an object file is
* loaded.
* Adjust offsets in section headers of all other sections (such as
* .comment). (XXX: Should s_lnnoptr be adjusted as well?)
*/
for (sp = datap+1; sp < sect+fhdr.f_nscns; sp++) {
switch (sp->s_flags & ~0xf) {
case STYP_BSS:
case STYP_SBSS:
case STYP_LIT4:
case STYP_LIT8:
case STYP_SDATA:
#ifdef DEBUG_DUMP
/* .comment is not null-terminated */
printf ("nuking %.8s\n", sp->s_name);
#endif
sp->s_paddr = sp->s_vaddr = sp->s_scnptr = sp->s_lnnoptr = 0;
sp->s_size = 0;
break;
default:
#ifdef DEBUG_DUMP
printf ("adjusting %.8s\n", sp->s_name);
#endif
sp->s_paddr += delta;
sp->s_vaddr += delta;
if (sp->s_scnptr) sp->s_scnptr += delta;
}
}
delta = ahdr.tsize + ahdr.dsize - fhdr.f_symptr;
fhdr.f_symptr += delta;
/* Write headers
*/
n = fhdr.f_nscns * sizeof (sect[0]);
if (write (ofd, (char *)&fhdr, sizeof (fhdr)) != sizeof (fhdr) ||
write (ofd, (char *)&ahdr, sizeof (ahdr)) != sizeof (ahdr) ||
write (ofd, (char *)sect, n) != n) {
Dump_Finalize;
Primitive_Error ("error writing a.out/section headers: ~E");
}
/* Write sections
*/
Was_Dumped = 1;
n += sizeof (fhdr) + sizeof (ahdr);
#ifdef DEBUG_DUMP
printf ("writing text 0x%x bytes and data 0x%x bytes\n",
ahdr.tsize-n, ahdr.dsize);
#endif
if (write (ofd, (char *)ahdr.text_start+n, ahdr.tsize-n) != ahdr.tsize-n) {
Dump_Finalize;
Primitive_Error ("error writing text section: ~E");
}
if (write (ofd, (char *)ahdr.data_start, ahdr.dsize) != ahdr.dsize) {
Dump_Finalize;
Primitive_Error ("error writing data sections: ~E");
}
/* Copy the symbol table. If an object file has been loaded into
* this invocation, copy the symbols from the ld temp file,
* otherwise from the running a.out.
* Adjust various offsets in the symbolic header.
* (XXX: Are there any offsets to be adjusted in the table proper?)
*/
if (Loader_Input) {
close (afd);
if ((afd = open (Loader_Input, O_RDONLY)) == -1) {
Dump_Finalize;
Primitive_Error ("cannot open symbol table file: ~E");
}
delta = fhdr.f_symptr;
if (read (afd, (char *)&fhdr, sizeof (fhdr)) != sizeof (fhdr)) {
Dump_Finalize;
Primitive_Error ("error reading a.out header: ~E");
}
delta -= fhdr.f_symptr;
(void)lseek (afd, (off_t)fhdr.f_symptr, SEEK_SET);
} else
(void)lseek (afd, (off_t)fhdr.f_symptr-delta, SEEK_SET);
#ifdef DEBUG_DUMP
printf ("copying symbols from %s\n", Loader_Input ? Loader_Input :
A_Out_Name);
#endif
if (read (afd, (char *)&shdr, sizeof (shdr)) != sizeof (shdr)) {
symrerr:
Dump_Finalize;
Primitive_Error ("error reading symbol table: ~E");
}
#define ADJUST(what) if (shdr.what > 0) shdr.what += delta
ADJUST (cbLineOffset);
ADJUST (cbDnOffset);
ADJUST (cbPdOffset);
ADJUST (cbSymOffset);
ADJUST (cbOptOffset);
ADJUST (cbAuxOffset);
ADJUST (cbSsOffset);
ADJUST (cbSsExtOffset);
ADJUST (cbFdOffset);
ADJUST (cbRfdOffset);
ADJUST (cbExtOffset);
if (write (ofd, (char *)&shdr, sizeof (shdr)) != sizeof (shdr)) {
symwerr:
Dump_Finalize;
Primitive_Error ("error writing symbol table: ~E");
}
while ((n = read (afd, buf, 4096)) > 0)
if (write (ofd, buf, n) != n) goto symwerr;
if (n < 0) goto symrerr;
Dump_Epilog;
}