From 252b5132c753830d5fd56823373aed85f2a0db63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 3 May 1999 07:29:11 +0000 Subject: 19990502 sourceware import --- bfd/coff-stgo32.c | 464 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 464 insertions(+) create mode 100644 bfd/coff-stgo32.c (limited to 'bfd/coff-stgo32.c') diff --git a/bfd/coff-stgo32.c b/bfd/coff-stgo32.c new file mode 100644 index 0000000..21724fe --- /dev/null +++ b/bfd/coff-stgo32.c @@ -0,0 +1,464 @@ +/* BFD back-end for Intel 386 COFF files (go32 variant with a stub). + Copyright 1997, 1998 Free Software Foundation, Inc. + Written by Robert Hoehne. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file handles now also stubbed coff images. The stub is a small + DOS executable program before the coff image to load it in memory + and execute it. This is needed, because DOS cannot run coff files. + + All the functions below are called by the corresponding functions + from coffswap.h. + The only thing what they do is to adjust the information stored in + the COFF file which are offset into the file. + This is needed, because DJGPP uses a very special way to load and run + the coff image. It loads the image in memory and assumes then, that the + image had no stub by using the filepointers as pointers in the coff + image and NOT in the file. + + To be compatible with any existing executables I have fixed this + here and NOT in the DJGPP startup code. + */ + +#define TARGET_SYM go32stubbedcoff_vec +#define TARGET_NAME "coff-go32-exe" +#define TARGET_UNDERSCORE '_' +#define COFF_GO32_EXE + +#include "bfd.h" + +/* At first the prototypes */ + +static void +adjust_filehdr_in_post PARAMS ((bfd * abfd, PTR src, PTR dst)); +static void +adjust_filehdr_out_pre PARAMS ((bfd * abfd, PTR in, PTR out)); +static void +adjust_filehdr_out_post PARAMS ((bfd * abfd, PTR in, PTR out)); + +static void +adjust_scnhdr_in_post PARAMS ((bfd * abfd, PTR ext, PTR in)); +static void +adjust_scnhdr_out_pre PARAMS ((bfd * abfd, PTR in, PTR out)); +static void +adjust_scnhdr_out_post PARAMS ((bfd * abfd, PTR in, PTR out)); + +static void +adjust_aux_in_post PARAMS ((bfd * abfd, PTR ext1, int type, int class, int indx, + int numaux, PTR in1)); +static void +adjust_aux_out_pre PARAMS ((bfd * abfd, PTR inp, int type, int class, int indx, + int numaux, PTR extp)); +static void +adjust_aux_out_post PARAMS ((bfd * abfd, PTR inp, int type, int class, int indx, + int numaux, PTR extp)); + +static void +create_go32_stub PARAMS ((bfd * abfd)); + +/* + All that ..._PRE and ...POST functions are called from the corresponding + coff_swap... functions. The ...PRE functions are called at the beginning + of the function and the ...POST functions at the end of the swap routines. + */ + +#define COFF_ADJUST_FILEHDR_IN_POST adjust_filehdr_in_post +#define COFF_ADJUST_FILEHDR_OUT_PRE adjust_filehdr_out_pre +#define COFF_ADJUST_FILEHDR_OUT_POST adjust_filehdr_out_post + +#define COFF_ADJUST_SCNHDR_IN_POST adjust_scnhdr_in_post +#define COFF_ADJUST_SCNHDR_OUT_PRE adjust_scnhdr_out_pre +#define COFF_ADJUST_SCNHDR_OUT_POST adjust_scnhdr_out_post + +#define COFF_ADJUST_AUX_IN_POST adjust_aux_in_post +#define COFF_ADJUST_AUX_OUT_PRE adjust_aux_out_pre +#define COFF_ADJUST_AUX_OUT_POST adjust_aux_out_post + +static boolean + go32_stubbed_coff_bfd_copy_private_bfd_data PARAMS ((bfd * ibfd, bfd * obfd)); + +#define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data + +#include "coff-i386.c" + +/* I hold in the usrdata the stub */ +#define bfd_coff_go32stub bfd_usrdata + +/* This macro is used, because I cannot assume the endianess of the + host system */ +#define _H(index) (bfd_h_get_16(abfd, (bfd_byte *)(header+index*2))) + +/* This function checks if the bfd is a stubbed coff image */ +static const bfd_target * +go32_stubbed_coff_object_p (abfd) + bfd *abfd; +{ + unsigned char header[10]; + char magic[8]; + unsigned long coff_start, exe_start; + + if (bfd_read (&header, 1, sizeof (header), abfd) != sizeof (header)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + if (_H (0) != 0x5a4d) /* it is not an exe file. maybe a coff-image */ + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + coff_start = (long) _H (2) * 512L; + if (_H (1)) + coff_start += (long) _H (1) - 512L; + + /* We can handle only a stub with a length of STUBSIZE */ + if (coff_start != STUBSIZE) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + exe_start = _H (4) * 16; + if (bfd_seek (abfd, exe_start, SEEK_SET) != 0) + return 0; + if (bfd_read (&magic, 1, 8, abfd) != 8) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return 0; + } + if (memcmp (magic, "go32stub", 8) != 0) + { + bfd_set_error (bfd_error_wrong_format); + return 0; + } + if (bfd_seek (abfd, 0, SEEK_SET) != 0) + return 0; + + /* Call the normal COFF detection routine */ + return coff_object_p (abfd); +} + +/* These bytes are a 2048-byte DOS executable, which loads the COFF + image into memory and then runs it. It is called 'stub' */ + +static unsigned char stub_bytes[STUBSIZE] = +{ +#include "go32stub.h" +}; + +/* + I have not commented each swap function below, because the + technique is in any function the same. For the ...in function, + all the pointers are adjusted by adding STUBSIZE and for the + ...out function, it is subtracted first and after calling the + standard swap function it is reset to the old value */ + +/* This macro is used for adjusting the filepointers, which + is done only, if the pointer is nonzero */ + +#define ADJUST_VAL(val,diff) \ + if (val != 0) val += diff + +static void +adjust_filehdr_in_post (abfd, src, dst) + bfd *abfd; + PTR src; + PTR dst; +{ + FILHDR *filehdr_src = (FILHDR *) src; + struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst; + + ADJUST_VAL (filehdr_dst->f_symptr, STUBSIZE); + + /* Save now the stub to be used later */ + bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, STUBSIZE); + + /* Since this function returns no status, I do not set here + any bfd_error_... + That means, before the use of bfd_coff_go32stub (), this value + should be checked if it is != NULL */ + if (bfd_coff_go32stub (abfd) == NULL) + return; + memcpy (bfd_coff_go32stub (abfd), filehdr_src->stub, STUBSIZE); +} + +static void +adjust_filehdr_out_pre (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; + FILHDR *filehdr_out = (FILHDR *) out; + + /* Generate the stub */ + create_go32_stub (abfd); + + /* Copy the stub to the file header */ + if (bfd_coff_go32stub (abfd) != NULL) + memcpy (filehdr_out->stub, bfd_coff_go32stub (abfd), STUBSIZE); + else + /* use the default */ + memcpy (filehdr_out->stub, stub_bytes, STUBSIZE); + + ADJUST_VAL (filehdr_in->f_symptr, -STUBSIZE); +} + +static void +adjust_filehdr_out_post (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in; + /* undo the above change */ + ADJUST_VAL (filehdr_in->f_symptr, STUBSIZE); +} + +static void +adjust_scnhdr_in_post (abfd, ext, in) + bfd *abfd; + PTR ext; + PTR in; +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE); + ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE); + ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE); +} + +static void +adjust_scnhdr_out_pre (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + ADJUST_VAL (scnhdr_int->s_scnptr, -STUBSIZE); + ADJUST_VAL (scnhdr_int->s_relptr, -STUBSIZE); + ADJUST_VAL (scnhdr_int->s_lnnoptr, -STUBSIZE); +} + +static void +adjust_scnhdr_out_post (abfd, in, out) + bfd *abfd; + PTR in; + PTR out; +{ + struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in; + + ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE); + ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE); + ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE); +} + +static void +adjust_aux_in_post (abfd, ext1, type, class, indx, numaux, in1) + bfd *abfd; + PTR ext1; + int type; + int class; + int indx; + int numaux; + PTR in1; +{ + union internal_auxent *in = (union internal_auxent *) in1; + + if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class)) + { + ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE); + } +} + +static void +adjust_aux_out_pre (abfd, inp, type, class, indx, numaux, extp) + bfd *abfd; + PTR inp; + int type; + int class; + int indx; + int numaux; + PTR extp; +{ + union internal_auxent *in = (union internal_auxent *) inp; + + if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class)) + { + ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -STUBSIZE); + } +} + +static void +adjust_aux_out_post (abfd, inp, type, class, indx, numaux, extp) + bfd *abfd; + PTR inp; + int type; + int class; + int indx; + int numaux; + PTR extp; +{ + union internal_auxent *in = (union internal_auxent *) inp; + + if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class)) + { + ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE); + } +} + +/* + That's the function, which creates the stub. There are + different cases from where the stub is taken. + At first the environment variable $(GO32STUB) is checked and then + $(STUB) if it was not set. + If it exists and points to a valid stub the stub is taken from + that file. This file can be also a whole executable file, because + the stub is computed from the exe information at the start of that + file. + + If there was any error, the standard stub (compiled in this file) + is taken. + */ + +static void +create_go32_stub (abfd) + bfd *abfd; +{ + /* Do it only once */ + if (bfd_coff_go32stub (abfd) == NULL) + { + char *stub; + struct stat st; + int f; + unsigned char header[10]; + char magic[8]; + unsigned long coff_start, exe_start; + + /* Check at first the environment variable $(GO32STUB) */ + stub = getenv ("GO32STUB"); + /* Now check the environment variable $(STUB) */ + if (stub == NULL) + stub = getenv ("STUB"); + if (stub == NULL) + goto stub_end; + if (stat (stub, &st) != 0) + goto stub_end; +#ifdef O_BINARY + f = open (stub, O_RDONLY | O_BINARY); +#else + f = open (stub, O_RDONLY); +#endif + if (f < 0) + goto stub_end; + if (read (f, &header, sizeof (header)) < 0) + { + close (f); + goto stub_end; + } + if (_H (0) != 0x5a4d) /* it is not an exe file */ + { + close (f); + goto stub_end; + } + /* Compute the size of the stub (it is every thing up + to the beginning of the coff image) */ + coff_start = (long) _H (2) * 512L; + if (_H (1)) + coff_start += (long) _H (1) - 512L; + + /* Currently there is only a fixed stub size of 2048 bytes + supported */ + if (coff_start != 2048) + { + close (f); + goto stub_end; + } + exe_start = _H (4) * 16; + if ((unsigned long) lseek (f, exe_start, SEEK_SET) != exe_start) + { + close (f); + goto stub_end; + } + if (read (f, &magic, 8) != 8) + { + close (f); + goto stub_end; + } + if (memcmp (magic, "go32stub", 8) != 0) + { + close (f); + goto stub_end; + } + /* Now we found a correct stub (hopefully) */ + bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, coff_start); + if (bfd_coff_go32stub (abfd) == NULL) + { + close (f); + return; + } + lseek (f, 0L, SEEK_SET); + if ((unsigned long) read (f, bfd_coff_go32stub (abfd), coff_start) + != coff_start) + { + bfd_release (abfd, bfd_coff_go32stub (abfd)); + bfd_coff_go32stub (abfd) = NULL; + } + close (f); + } +stub_end: + /* There was something wrong above, so use now the standard builtin + stub */ + if (bfd_coff_go32stub (abfd) == NULL) + { + bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, STUBSIZE); + if (bfd_coff_go32stub (abfd) == NULL) + { + return; + } + + memcpy (bfd_coff_go32stub (abfd), stub_bytes, STUBSIZE); + } +} + +/* If ibfd was a stubbed coff image, copy the stub from that bfd + to the new obfd. + */ + +static boolean +go32_stubbed_coff_bfd_copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + /* check if both are the same targets */ + if (ibfd->xvec != obfd->xvec) + return true; + + /* check if both have a valid stub */ + if (bfd_coff_go32stub (ibfd) == NULL + || bfd_coff_go32stub (obfd) == NULL) + return true; + + /* Now copy the stub */ + memcpy (bfd_coff_go32stub (obfd), bfd_coff_go32stub (ibfd), STUBSIZE); + + return true; +} -- cgit v1.1