Back to index

cell-binutils  2.17cvs20070401
coff-stgo32.c
Go to the documentation of this file.
00001 /* BFD back-end for Intel 386 COFF files (DJGPP variant with a stub).
00002    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2006 Free Software Foundation, Inc.
00003    Written by Robert Hoehne.
00004 
00005    This file is part of BFD, the Binary File Descriptor library.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 /* This file handles now also stubbed coff images. The stub is a small
00022    DOS executable program before the coff image to load it in memory
00023    and execute it. This is needed, because DOS cannot run coff files.
00024 
00025    All the functions below are called by the corresponding functions
00026    from coffswap.h.
00027    The only thing what they do is to adjust the information stored in
00028    the COFF file which are offset into the file.
00029    This is needed, because DJGPP uses a very special way to load and run
00030    the coff image. It loads the image in memory and assumes then, that the
00031    image had no stub by using the filepointers as pointers in the coff
00032    image and NOT in the file.
00033 
00034    To be compatible with any existing executables I have fixed this
00035    here and NOT in the DJGPP startup code.  */
00036 
00037 #define TARGET_SYM          go32stubbedcoff_vec
00038 #define TARGET_NAME         "coff-go32-exe"
00039 #define TARGET_UNDERSCORE   '_'
00040 #define COFF_GO32_EXE
00041 #define COFF_LONG_SECTION_NAMES
00042 #define COFF_SUPPORT_GNU_LINKONCE
00043 #define COFF_LONG_FILENAMES
00044 
00045 #define COFF_SECTION_ALIGNMENT_ENTRIES \
00046 { COFF_SECTION_NAME_EXACT_MATCH (".data"), \
00047   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
00048 { COFF_SECTION_NAME_EXACT_MATCH (".text"), \
00049   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 4 }, \
00050 { COFF_SECTION_NAME_PARTIAL_MATCH (".debug"), \
00051   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }, \
00052 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi"), \
00053   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
00054 
00055 #include "bfd.h"
00056 
00057 /* At first the prototypes.  */
00058 
00059 static void
00060 adjust_filehdr_in_post PARAMS ((bfd *, PTR, PTR));
00061 static void
00062 adjust_filehdr_out_pre PARAMS ((bfd *, PTR, PTR));
00063 static void
00064 adjust_filehdr_out_post PARAMS ((bfd *, PTR, PTR));
00065 static void
00066 adjust_scnhdr_in_post PARAMS ((bfd *, PTR, PTR));
00067 static void
00068 adjust_scnhdr_out_pre PARAMS ((bfd *, PTR, PTR));
00069 static void
00070 adjust_scnhdr_out_post PARAMS ((bfd *, PTR, PTR));
00071 static void
00072 adjust_aux_in_post PARAMS ((bfd *, PTR, int, int, int, int, PTR));
00073 static void
00074 adjust_aux_out_pre PARAMS ((bfd *, PTR, int, int, int, int, PTR));
00075 static void
00076 adjust_aux_out_post PARAMS ((bfd *, PTR, int, int, int, int, PTR));
00077 static void
00078 create_go32_stub PARAMS ((bfd *));
00079 
00080 /* All that ..._PRE and ...POST functions are called from the corresponding
00081    coff_swap... functions. The ...PRE functions are called at the beginning
00082    of the function and the ...POST functions at the end of the swap routines.  */
00083 
00084 #define COFF_ADJUST_FILEHDR_IN_POST adjust_filehdr_in_post
00085 #define COFF_ADJUST_FILEHDR_OUT_PRE adjust_filehdr_out_pre
00086 #define COFF_ADJUST_FILEHDR_OUT_POST adjust_filehdr_out_post
00087 
00088 #define COFF_ADJUST_SCNHDR_IN_POST adjust_scnhdr_in_post
00089 #define COFF_ADJUST_SCNHDR_OUT_PRE adjust_scnhdr_out_pre
00090 #define COFF_ADJUST_SCNHDR_OUT_POST adjust_scnhdr_out_post
00091 
00092 #define COFF_ADJUST_AUX_IN_POST adjust_aux_in_post
00093 #define COFF_ADJUST_AUX_OUT_PRE adjust_aux_out_pre
00094 #define COFF_ADJUST_AUX_OUT_POST adjust_aux_out_post
00095 
00096 static bfd_boolean
00097   go32_stubbed_coff_bfd_copy_private_bfd_data PARAMS ((bfd *, bfd *));
00098 
00099 #define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data
00100 
00101 #include "coff-i386.c"
00102 
00103 /* I hold in the usrdata the stub.  */
00104 #define bfd_coff_go32stub bfd_usrdata
00105 
00106 /* This macro is used, because I cannot assume the endianess of the
00107    host system.  */
00108 #define _H(index) (H_GET_16 (abfd, (header+index*2)))
00109 
00110 /* These bytes are a 2048-byte DOS executable, which loads the COFF
00111    image into memory and then runs it. It is called 'stub'.  */
00112 
00113 static const unsigned char stub_bytes[STUBSIZE] =
00114 {
00115 #include "go32stub.h"
00116 };
00117 
00118 /*
00119    I have not commented each swap function below, because the
00120    technique is in any function the same. For the ...in function,
00121    all the pointers are adjusted by adding STUBSIZE and for the
00122    ...out function, it is subtracted first and after calling the
00123    standard swap function it is reset to the old value.  */
00124 
00125 /* This macro is used for adjusting the filepointers, which
00126    is done only, if the pointer is nonzero.  */
00127 
00128 #define ADJUST_VAL(val,diff) \
00129   if (val != 0) val += diff
00130 
00131 static void
00132 adjust_filehdr_in_post  (abfd, src, dst)
00133      bfd *abfd;
00134      PTR src;
00135      PTR dst;
00136 {
00137   FILHDR *filehdr_src = (FILHDR *) src;
00138   struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
00139 
00140   ADJUST_VAL (filehdr_dst->f_symptr, STUBSIZE);
00141 
00142   /* Save now the stub to be used later.  */
00143   bfd_coff_go32stub (abfd) = (PTR) bfd_alloc (abfd, (bfd_size_type) STUBSIZE);
00144 
00145   /* Since this function returns no status, I do not set here
00146      any bfd_error_...
00147      That means, before the use of bfd_coff_go32stub (), this value
00148      should be checked if it is != NULL.  */
00149   if (bfd_coff_go32stub (abfd) == NULL)
00150     return;
00151   memcpy (bfd_coff_go32stub (abfd), filehdr_src->stub, STUBSIZE);
00152 }
00153 
00154 static void
00155 adjust_filehdr_out_pre  (abfd, in, out)
00156      bfd *abfd;
00157      PTR in;
00158      PTR out;
00159 {
00160   struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
00161   FILHDR *filehdr_out = (FILHDR *) out;
00162 
00163   /* Generate the stub.  */
00164   create_go32_stub (abfd);
00165 
00166   /* Copy the stub to the file header.  */
00167   if (bfd_coff_go32stub (abfd) != NULL)
00168     memcpy (filehdr_out->stub, bfd_coff_go32stub (abfd), STUBSIZE);
00169   else
00170     /* Use the default.  */
00171     memcpy (filehdr_out->stub, stub_bytes, STUBSIZE);
00172 
00173   ADJUST_VAL (filehdr_in->f_symptr, -STUBSIZE);
00174 }
00175 
00176 static void
00177 adjust_filehdr_out_post  (abfd, in, out)
00178      bfd *abfd ATTRIBUTE_UNUSED;
00179      PTR in;
00180      PTR out ATTRIBUTE_UNUSED;
00181 {
00182   struct internal_filehdr *filehdr_in = (struct internal_filehdr *) in;
00183   /* Undo the above change.  */
00184   ADJUST_VAL (filehdr_in->f_symptr, STUBSIZE);
00185 }
00186 
00187 static void
00188 adjust_scnhdr_in_post  (abfd, ext, in)
00189      bfd *abfd ATTRIBUTE_UNUSED;
00190      PTR ext ATTRIBUTE_UNUSED;
00191      PTR in;
00192 {
00193   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
00194 
00195   ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE);
00196   ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE);
00197   ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE);
00198 }
00199 
00200 static void
00201 adjust_scnhdr_out_pre  (abfd, in, out)
00202      bfd *abfd ATTRIBUTE_UNUSED;
00203      PTR in;
00204      PTR out ATTRIBUTE_UNUSED;
00205 {
00206   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
00207 
00208   ADJUST_VAL (scnhdr_int->s_scnptr, -STUBSIZE);
00209   ADJUST_VAL (scnhdr_int->s_relptr, -STUBSIZE);
00210   ADJUST_VAL (scnhdr_int->s_lnnoptr, -STUBSIZE);
00211 }
00212 
00213 static void
00214 adjust_scnhdr_out_post (abfd, in, out)
00215      bfd *abfd ATTRIBUTE_UNUSED;
00216      PTR in;
00217      PTR out ATTRIBUTE_UNUSED;
00218 {
00219   struct internal_scnhdr *scnhdr_int = (struct internal_scnhdr *) in;
00220 
00221   ADJUST_VAL (scnhdr_int->s_scnptr, STUBSIZE);
00222   ADJUST_VAL (scnhdr_int->s_relptr, STUBSIZE);
00223   ADJUST_VAL (scnhdr_int->s_lnnoptr, STUBSIZE);
00224 }
00225 
00226 static void
00227 adjust_aux_in_post  (abfd, ext1, type, class, indx, numaux, in1)
00228      bfd *abfd ATTRIBUTE_UNUSED;
00229      PTR ext1 ATTRIBUTE_UNUSED;
00230      int type;
00231      int class;
00232      int indx ATTRIBUTE_UNUSED;
00233      int numaux ATTRIBUTE_UNUSED;
00234      PTR in1;
00235 {
00236   union internal_auxent *in = (union internal_auxent *) in1;
00237 
00238   if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
00239     {
00240       ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE);
00241     }
00242 }
00243 
00244 static void
00245 adjust_aux_out_pre  (abfd, inp, type, class, indx, numaux, extp)
00246      bfd *abfd ATTRIBUTE_UNUSED;
00247      PTR inp;
00248      int type;
00249      int class;
00250      int indx ATTRIBUTE_UNUSED;
00251      int numaux ATTRIBUTE_UNUSED;
00252      PTR extp ATTRIBUTE_UNUSED;
00253 {
00254   union internal_auxent *in = (union internal_auxent *) inp;
00255 
00256   if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
00257     {
00258       ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, -STUBSIZE);
00259     }
00260 }
00261 
00262 static void
00263 adjust_aux_out_post (abfd, inp, type, class, indx, numaux, extp)
00264      bfd *abfd ATTRIBUTE_UNUSED;
00265      PTR inp;
00266      int type;
00267      int class;
00268      int indx ATTRIBUTE_UNUSED;
00269      int numaux ATTRIBUTE_UNUSED;
00270      PTR extp ATTRIBUTE_UNUSED;
00271 {
00272   union internal_auxent *in = (union internal_auxent *) inp;
00273 
00274   if (class == C_BLOCK || class == C_FCN || ISFCN (type) || ISTAG (class))
00275     {
00276       ADJUST_VAL (in->x_sym.x_fcnary.x_fcn.x_lnnoptr, STUBSIZE);
00277     }
00278 }
00279 
00280 /* That's the function, which creates the stub. There are
00281    different cases from where the stub is taken.
00282    At first the environment variable $(GO32STUB) is checked and then
00283    $(STUB) if it was not set.
00284    If it exists and points to a valid stub the stub is taken from
00285    that file. This file can be also a whole executable file, because
00286    the stub is computed from the exe information at the start of that
00287    file.
00288 
00289    If there was any error, the standard stub (compiled in this file)
00290    is taken.  */
00291 
00292 static void
00293 create_go32_stub (abfd)
00294      bfd *abfd;
00295 {
00296   /* Do it only once.  */
00297   if (bfd_coff_go32stub (abfd) == NULL)
00298     {
00299       char *stub;
00300       struct stat st;
00301       int f;
00302       unsigned char header[10];
00303       char magic[8];
00304       unsigned long coff_start;
00305       long exe_start;
00306 
00307       /* Check at first the environment variable $(GO32STUB).  */
00308       stub = getenv ("GO32STUB");
00309       /* Now check the environment variable $(STUB).  */
00310       if (stub == NULL)
00311        stub = getenv ("STUB");
00312       if (stub == NULL)
00313        goto stub_end;
00314       if (stat (stub, &st) != 0)
00315        goto stub_end;
00316 #ifdef O_BINARY
00317       f = open (stub, O_RDONLY | O_BINARY);
00318 #else
00319       f = open (stub, O_RDONLY);
00320 #endif
00321       if (f < 0)
00322        goto stub_end;
00323       if (read (f, &header, sizeof (header)) < 0)
00324        {
00325          close (f);
00326          goto stub_end;
00327        }
00328       if (_H (0) != 0x5a4d) /* It is not an exe file.  */
00329        {
00330          close (f);
00331          goto stub_end;
00332        }
00333       /* Compute the size of the stub (it is every thing up
00334          to the beginning of the coff image).  */
00335       coff_start = (long) _H (2) * 512L;
00336       if (_H (1))
00337        coff_start += (long) _H (1) - 512L;
00338 
00339       /* Currently there is only a fixed stub size of 2048 bytes
00340          supported.  */
00341       if (coff_start != 2048)
00342        {
00343          close (f);
00344          goto stub_end;
00345        }
00346       exe_start = _H (4) * 16;
00347       if ((long) lseek (f, exe_start, SEEK_SET) != exe_start)
00348        {
00349          close (f);
00350          goto stub_end;
00351        }
00352       if (read (f, &magic, 8) != 8)
00353        {
00354          close (f);
00355          goto stub_end;
00356        }
00357       if (! CONST_STRNEQ (magic, "go32stub"))
00358        {
00359          close (f);
00360          goto stub_end;
00361        }
00362       /* Now we found a correct stub (hopefully).  */
00363       bfd_coff_go32stub (abfd)
00364        = (PTR) bfd_alloc (abfd, (bfd_size_type) coff_start);
00365       if (bfd_coff_go32stub (abfd) == NULL)
00366        {
00367          close (f);
00368          return;
00369        }
00370       lseek (f, 0L, SEEK_SET);
00371       if ((unsigned long) read (f, bfd_coff_go32stub (abfd), coff_start)
00372          != coff_start)
00373        {
00374          bfd_release (abfd, bfd_coff_go32stub (abfd));
00375          bfd_coff_go32stub (abfd) = NULL;
00376        }
00377       close (f);
00378     }
00379 stub_end:
00380   /* There was something wrong above, so use now the standard builtin
00381      stub.  */
00382   if (bfd_coff_go32stub (abfd) == NULL)
00383     {
00384       bfd_coff_go32stub (abfd)
00385        = (PTR) bfd_alloc (abfd, (bfd_size_type) STUBSIZE);
00386       if (bfd_coff_go32stub (abfd) == NULL)
00387        return;
00388       memcpy (bfd_coff_go32stub (abfd), stub_bytes, STUBSIZE);
00389     }
00390 }
00391 
00392 /* If ibfd was a stubbed coff image, copy the stub from that bfd
00393    to the new obfd.  */
00394 
00395 static bfd_boolean
00396 go32_stubbed_coff_bfd_copy_private_bfd_data  (ibfd, obfd)
00397      bfd *ibfd;
00398      bfd *obfd;
00399 {
00400   /* Check if both are the same targets.  */
00401   if (ibfd->xvec != obfd->xvec)
00402     return TRUE;
00403 
00404   /* Check if both have a valid stub.  */
00405   if (bfd_coff_go32stub (ibfd) == NULL
00406       || bfd_coff_go32stub (obfd) == NULL)
00407     return TRUE;
00408 
00409   /* Now copy the stub.  */
00410   memcpy (bfd_coff_go32stub (obfd), bfd_coff_go32stub (ibfd), STUBSIZE);
00411 
00412   return TRUE;
00413 }