@ -23,17 +23,10 @@
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 . */
The COFF image is loaded in memory without the stub attached , so
all offsets are relative to the beginning of the image , not the
actual file . We handle this in bfd by setting bfd - > origin to where
the COFF image starts . */
# define TARGET_SYM i386_coff_go32stubbed_vec
# define TARGET_NAME "coff-go32-exe"
@ -55,52 +48,17 @@
# include "sysdep.h"
# include "bfd.h"
# include "coff/msdos.h"
/* 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 . */
static bfd_cleanup go32exe_check_format ( bfd * ) ;
static bfd_boolean go32exe_write_object_contents ( bfd * ) ;
static bfd_boolean go32exe_mkobject ( bfd * ) ;
static bfd_boolean go32exe_copy_private_bfd_data ( bfd * , bfd * ) ;
static void
adjust_filehdr_in_post ( bfd * , void * , void * ) ;
static void
adjust_filehdr_out_pre ( bfd * , void * , void * ) ;
static void
adjust_filehdr_out_post ( bfd * , void * , void * ) ;
static void
adjust_scnhdr_in_post ( bfd * , void * , void * ) ;
static void
adjust_scnhdr_out_pre ( bfd * , void * , void * ) ;
static void
adjust_scnhdr_out_post ( bfd * , void * , void * ) ;
static void
adjust_aux_in_post ( bfd * , void * , int , int , int , int , void * ) ;
static void
adjust_aux_out_pre ( bfd * , void * , int , int , int , int , void * ) ;
static void
adjust_aux_out_post ( bfd * , void * , int , int , int , int , void * ) ;
static void
create_go32_stub ( bfd * ) ;
# 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 bfd_cleanup go32_check_format ( bfd * ) ;
# define COFF_CHECK_FORMAT go32_check_format
static bfd_boolean
go32_stubbed_coff_bfd_copy_private_bfd_data ( bfd * , bfd * ) ;
# define coff_bfd_copy_private_bfd_data go32_stubbed_coff_bfd_copy_private_bfd_data
# define COFF_CHECK_FORMAT go32exe_check_format
# define COFF_WRITE_CONTENTS go32exe_write_object_contents
# define coff_mkobject go32exe_mkobject
# define coff_bfd_copy_private_bfd_data go32exe_copy_private_bfd_data
# include "coff-i386.c"
@ -110,160 +68,15 @@ static bfd_boolean
/* These bytes are a 2048-byte DOS executable, which loads the COFF
image into memory and then runs it . It is called ' stub ' . */
static const unsigned char stub_bytes [ GO32_STUBSIZE ] =
# define GO32EXE_DEFAULT_STUB_SIZE 2048
static const unsigned char go32exe_default_ stub[ GO32EXE_DEFAULT _STUB_ SIZE ] =
{
# 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 GO32_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 ( bfd * abfd ATTRIBUTE_UNUSED ,
void * src ,
void * dst )
{
FILHDR * filehdr_src = ( FILHDR * ) src ;
struct internal_filehdr * filehdr_dst = ( struct internal_filehdr * ) dst ;
ADJUST_VAL ( filehdr_dst - > f_symptr , GO32_STUBSIZE ) ;
/* Save now the stub to be used later. Put the stub data to FILEHDR_DST
first as coff_data ( abfd ) still does not exist . It may not even be ever
created as we are just checking the file format of ABFD . */
memcpy ( filehdr_dst - > go32stub , filehdr_src - > stub , GO32_STUBSIZE ) ;
filehdr_dst - > f_flags | = F_GO32STUB ;
}
static void
adjust_filehdr_out_pre ( bfd * abfd , void * in , void * 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 ( coff_data ( abfd ) - > go32stub ! = NULL )
memcpy ( filehdr_out - > stub , coff_data ( abfd ) - > go32stub , GO32_STUBSIZE ) ;
else
/* Use the default. */
memcpy ( filehdr_out - > stub , stub_bytes , GO32_STUBSIZE ) ;
ADJUST_VAL ( filehdr_in - > f_symptr , - GO32_STUBSIZE ) ;
}
static void
adjust_filehdr_out_post ( bfd * abfd ATTRIBUTE_UNUSED ,
void * in ,
void * out ATTRIBUTE_UNUSED )
{
struct internal_filehdr * filehdr_in = ( struct internal_filehdr * ) in ;
/* Undo the above change. */
ADJUST_VAL ( filehdr_in - > f_symptr , GO32_STUBSIZE ) ;
}
static void
adjust_scnhdr_in_post ( bfd * abfd ATTRIBUTE_UNUSED ,
void * ext ATTRIBUTE_UNUSED ,
void * in )
{
struct internal_scnhdr * scnhdr_int = ( struct internal_scnhdr * ) in ;
ADJUST_VAL ( scnhdr_int - > s_scnptr , GO32_STUBSIZE ) ;
ADJUST_VAL ( scnhdr_int - > s_relptr , GO32_STUBSIZE ) ;
ADJUST_VAL ( scnhdr_int - > s_lnnoptr , GO32_STUBSIZE ) ;
}
static void
adjust_scnhdr_out_pre ( bfd * abfd ATTRIBUTE_UNUSED ,
void * in ,
void * out ATTRIBUTE_UNUSED )
{
struct internal_scnhdr * scnhdr_int = ( struct internal_scnhdr * ) in ;
ADJUST_VAL ( scnhdr_int - > s_scnptr , - GO32_STUBSIZE ) ;
ADJUST_VAL ( scnhdr_int - > s_relptr , - GO32_STUBSIZE ) ;
ADJUST_VAL ( scnhdr_int - > s_lnnoptr , - GO32_STUBSIZE ) ;
}
static void
adjust_scnhdr_out_post ( bfd * abfd ATTRIBUTE_UNUSED ,
void * in ,
void * out ATTRIBUTE_UNUSED )
{
struct internal_scnhdr * scnhdr_int = ( struct internal_scnhdr * ) in ;
ADJUST_VAL ( scnhdr_int - > s_scnptr , GO32_STUBSIZE ) ;
ADJUST_VAL ( scnhdr_int - > s_relptr , GO32_STUBSIZE ) ;
ADJUST_VAL ( scnhdr_int - > s_lnnoptr , GO32_STUBSIZE ) ;
}
static void
adjust_aux_in_post ( bfd * abfd ATTRIBUTE_UNUSED ,
void * ext1 ATTRIBUTE_UNUSED ,
int type ,
int in_class ,
int indx ATTRIBUTE_UNUSED ,
int numaux ATTRIBUTE_UNUSED ,
void * in1 )
{
union internal_auxent * in = ( union internal_auxent * ) in1 ;
if ( in_class = = C_BLOCK | | in_class = = C_FCN | | ISFCN ( type )
| | ISTAG ( in_class ) )
{
ADJUST_VAL ( in - > x_sym . x_fcnary . x_fcn . x_lnnoptr , GO32_STUBSIZE ) ;
}
}
static void
adjust_aux_out_pre ( bfd * abfd ATTRIBUTE_UNUSED ,
void * inp ,
int type ,
int in_class ,
int indx ATTRIBUTE_UNUSED ,
int numaux ATTRIBUTE_UNUSED ,
void * extp ATTRIBUTE_UNUSED )
{
union internal_auxent * in = ( union internal_auxent * ) inp ;
if ( in_class = = C_BLOCK | | in_class = = C_FCN | | ISFCN ( type )
| | ISTAG ( in_class ) )
{
ADJUST_VAL ( in - > x_sym . x_fcnary . x_fcn . x_lnnoptr , - GO32_STUBSIZE ) ;
}
}
static void
adjust_aux_out_post ( bfd * abfd ATTRIBUTE_UNUSED ,
void * inp ,
int type ,
int in_class ,
int indx ATTRIBUTE_UNUSED ,
int numaux ATTRIBUTE_UNUSED ,
void * extp ATTRIBUTE_UNUSED )
{
union internal_auxent * in = ( union internal_auxent * ) inp ;
if ( in_class = = C_BLOCK | | in_class = = C_FCN | | ISFCN ( type )
| | ISTAG ( in_class ) )
{
ADJUST_VAL ( in - > x_sym . x_fcnary . x_fcn . x_lnnoptr , GO32_STUBSIZE ) ;
}
}
/* Temporary location for stub read from input file. */
static char * go32exe_temp_stub = NULL ;
static bfd_size_type go32exe_temp_stub_size = 0 ;
/* That's the function, which creates the stub. There are
different cases from where the stub is taken .
@ -275,13 +88,16 @@ adjust_aux_out_post (bfd *abfd ATTRIBUTE_UNUSED,
file .
If there was any error , the standard stub ( compiled in this file )
is taken . */
is taken .
Ideally this function should exec ' $ ( TARGET ) - stubify ' to generate
a stub , like gcc does . */
static void
create_go32_stub ( bfd * abfd )
go32exe_ create_stub ( bfd * abfd )
{
/* Do it only once. */
if ( coff_data ( abfd ) - > go32 stub = = NULL )
if ( coff_data ( abfd ) - > stub = = NULL )
{
char * stub ;
struct stat st ;
@ -291,6 +107,22 @@ create_go32_stub (bfd *abfd)
unsigned long coff_start ;
long exe_start ;
/* If we read a stub from an input file, use that one. */
if ( go32exe_temp_stub ! = NULL )
{
coff_data ( abfd ) - > stub = bfd_alloc ( abfd ,
go32exe_temp_stub_size ) ;
if ( coff_data ( abfd ) - > stub = = NULL )
return ;
memcpy ( coff_data ( abfd ) - > stub , go32exe_temp_stub ,
go32exe_temp_stub_size ) ;
coff_data ( abfd ) - > stub_size = go32exe_temp_stub_size ;
free ( go32exe_temp_stub ) ;
go32exe_temp_stub = NULL ;
go32exe_temp_stub_size = 0 ;
return ;
}
/* Check at first the environment variable $(GO32STUB). */
stub = getenv ( " GO32STUB " ) ;
/* Now check the environment variable $(STUB). */
@ -323,13 +155,6 @@ create_go32_stub (bfd *abfd)
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 ( ( long ) lseek ( f , exe_start , SEEK_SET ) ! = exe_start )
{
@ -347,31 +172,35 @@ create_go32_stub (bfd *abfd)
goto stub_end ;
}
/* Now we found a correct stub (hopefully). */
coff_data ( abfd ) - > go32 stub = bfd_alloc ( abfd , ( bfd_size_type ) coff_start ) ;
if ( coff_data ( abfd ) - > go32 stub = = NULL )
coff_data ( abfd ) - > stub = bfd_alloc ( abfd , ( bfd_size_type ) coff_start ) ;
if ( coff_data ( abfd ) - > stub = = NULL )
{
close ( f ) ;
return ;
}
lseek ( f , 0L , SEEK_SET ) ;
if ( ( unsigned long ) read ( f , coff_data ( abfd ) - > go32 stub, coff_start )
if ( ( unsigned long ) read ( f , coff_data ( abfd ) - > stub , coff_start )
! = coff_start )
{
bfd_release ( abfd , coff_data ( abfd ) - > go32 stub) ;
coff_data ( abfd ) - > go32 stub = NULL ;
bfd_release ( abfd , coff_data ( abfd ) - > stub ) ;
coff_data ( abfd ) - > stub = NULL ;
}
else
coff_data ( abfd ) - > stub_size = coff_start ;
close ( f ) ;
}
stub_end :
/* There was something wrong above, so use now the standard builtin
stub . */
if ( coff_data ( abfd ) - > go32 stub = = NULL )
if ( coff_data ( abfd ) - > stub = = NULL )
{
coff_data ( abfd ) - > go32 stub
= bfd_alloc ( abfd , ( bfd_size_type ) GO32_STUBSIZE ) ;
if ( coff_data ( abfd ) - > go32 stub = = NULL )
coff_data ( abfd ) - > stub
= bfd_alloc ( abfd , ( bfd_size_type ) GO32EXE_DEFAULT _STUB_ SIZE ) ;
if ( coff_data ( abfd ) - > stub = = NULL )
return ;
memcpy ( coff_data ( abfd ) - > go32stub , stub_bytes , GO32_STUBSIZE ) ;
memcpy ( coff_data ( abfd ) - > stub , go32exe_default_stub ,
GO32EXE_DEFAULT_STUB_SIZE ) ;
coff_data ( abfd ) - > stub_size = GO32EXE_DEFAULT_STUB_SIZE ;
}
}
@ -379,46 +208,176 @@ create_go32_stub (bfd *abfd)
to the new obfd . */
static bfd_boolean
go32_stubbed_coff_bfd _copy_private_bfd_data ( bfd * ibfd , bfd * obfd )
go32exe _copy_private_bfd_data ( bfd * ibfd , bfd * obfd )
{
/* Check if both are the same targets. */
if ( ibfd - > xvec ! = obfd - > xvec )
return TRUE ;
/* Check if we have a source stub. */
if ( coff_data ( ibfd ) - > go32stub = = NULL )
return TRUE ;
/* Make sure we have a source stub. */
BFD_ASSERT ( coff_data ( ibfd ) - > stub ! = NULL ) ;
/* As adjust_filehdr_out_pre may get called only after this function,
optionally allocate the output stub . */
if ( coff_data ( obfd ) - > go32stub = = NULL )
coff_data ( obfd ) - > go32stub = bfd_alloc ( obfd ,
( bfd_size_type ) GO32_STUBSIZE ) ;
/* Reallocate the output stub if necessary. */
if ( coff_data ( ibfd ) - > stub_size > coff_data ( obfd ) - > stub_size )
coff_data ( obfd ) - > stub = bfd_alloc ( obfd , coff_data ( ibfd ) - > stub_size ) ;
if ( coff_data ( obfd ) - > stub = = NULL )
return FALSE ;
/* Now copy the stub. */
if ( coff_data ( obfd ) - > go32stub ! = NULL )
memcpy ( coff_data ( obfd ) - > go32stub , coff_data ( ibfd ) - > go32stub ,
GO32_STUBSIZE ) ;
memcpy ( coff_data ( obfd ) - > stub , coff_data ( ibfd ) - > stub ,
coff_data ( ibfd ) - > stub_size ) ;
coff_data ( obfd ) - > stub_size = coff_data ( ibfd ) - > stub_size ;
obfd - > origin = coff_data ( obfd ) - > stub_size ;
return TRUE ;
}
/* coff_object_p only checks 2 bytes F_MAGIC at GO32_STUBSIZE inside the file
which is too fragile . */
/* Cleanup function, returned from check_format hook. */
static bfd_cleanup
go32_check_format ( bfd * abfd )
static void
go32exe_cleanup ( bfd * abfd )
{
char mz [ 2 ] ;
abfd - > origin = 0 ;
if ( go32exe_temp_stub ! = NULL )
free ( go32exe_temp_stub ) ;
go32exe_temp_stub = NULL ;
go32exe_temp_stub_size = 0 ;
}
if ( bfd_bread ( mz , 2 , abfd ) ! = 2 | | mz [ 0 ] ! = ' M ' | | mz [ 1 ] ! = ' Z ' )
/* Check that there is a GO32 stub and read it to go32exe_temp_stub.
Then set abfd - > origin so that the COFF image is read at the correct
file offset . */
static bfd_cleanup
go32exe_check_format ( bfd * abfd )
{
struct external_DOS_hdr filehdr_dos ;
uint16_t num_pages ;
uint16_t last_page_size ;
uint32_t header_end ;
bfd_size_type stubsize ;
/* This format can not appear in an archive. */
if ( abfd - > origin ! = 0 )
{
bfd_set_error ( bfd_error_wrong_format ) ;
return NULL ;
}
bfd_set_error ( bfd_error_system_call ) ;
/* Read in the stub file header, which is a DOS MZ executable. */
if ( bfd_bread ( & filehdr_dos , DOS_HDR_SIZE , abfd ) ! = DOS_HDR_SIZE )
goto fail ;
/* Make sure that this is an MZ executable. */
if ( H_GET_16 ( abfd , filehdr_dos . e_magic ) ! = IMAGE_DOS_SIGNATURE )
goto fail_format ;
/* Determine the size of the stub */
num_pages = H_GET_16 ( abfd , filehdr_dos . e_cp ) ;
last_page_size = H_GET_16 ( abfd , filehdr_dos . e_cblp ) ;
stubsize = num_pages * 512 ;
if ( last_page_size ! = 0 )
stubsize + = last_page_size - 512 ;
/* Save now the stub to be used later. Put the stub data to a temporary
location first as tdata still does not exist . It may not even
be ever created if we are just checking the file format of ABFD . */
bfd_seek ( abfd , 0 , SEEK_SET ) ;
go32exe_temp_stub = bfd_malloc ( stubsize ) ;
if ( go32exe_temp_stub = = NULL )
goto fail ;
if ( bfd_bread ( go32exe_temp_stub , stubsize , abfd ) ! = stubsize )
goto fail ;
go32exe_temp_stub_size = stubsize ;
/* Confirm that this is a go32stub. */
header_end = H_GET_16 ( abfd , filehdr_dos . e_cparhdr ) * 16UL ;
if ( ! CONST_STRNEQ ( go32exe_temp_stub + header_end , " go32stub " ) )
goto fail_format ;
/* Set origin to where the COFF header starts and seek there. */
abfd - > origin = stubsize ;
if ( bfd_seek ( abfd , 0 , SEEK_SET ) ! = 0 )
return NULL ;
goto fail ;
/* Call coff_object_p to read the COFF image. If this fails then the file
must be just a stub with no COFF data attached . */
bfd_cleanup cleanup = coff_object_p ( abfd ) ;
if ( cleanup = = NULL )
goto fail ;
BFD_ASSERT ( cleanup = = _bfd_no_cleanup ) ;
return go32exe_cleanup ;
fail_format :
bfd_set_error ( bfd_error_wrong_format ) ;
fail :
go32exe_cleanup ( abfd ) ;
return NULL ;
}
/* Write the stub to the output file, then call coff_write_object_contents. */
static bfd_boolean
go32exe_write_object_contents ( bfd * abfd )
{
const bfd_size_type pos = bfd_tell ( abfd ) ;
const bfd_size_type stubsize = coff_data ( abfd ) - > stub_size ;
BFD_ASSERT ( stubsize ! = 0 ) ;
bfd_set_error ( bfd_error_system_call ) ;
return coff_object_p ( abfd ) ;
/* Write the stub. */
abfd - > origin = 0 ;
if ( bfd_seek ( abfd , 0 , SEEK_SET ) ! = 0 )
return FALSE ;
if ( bfd_bwrite ( coff_data ( abfd ) - > stub , stubsize , abfd ) ! = stubsize )
return FALSE ;
/* Seek back to where we were. */
abfd - > origin = stubsize ;
if ( bfd_seek ( abfd , pos , SEEK_SET ) ! = 0 )
return FALSE ;
return coff_write_object_contents ( abfd ) ;
}
/* mkobject hook. Called directly through bfd_set_format or via
coff_mkobject_hook etc from bfd_check_format . */
static bfd_boolean
go32exe_mkobject ( bfd * abfd )
{
coff_data_type * coff = NULL ;
const bfd_size_type amt = sizeof ( coff_data_type ) ;
/* Don't output to an archive. */
if ( abfd - > my_archive ! = NULL )
return FALSE ;
abfd - > tdata . coff_obj_data = bfd_zalloc ( abfd , amt ) ;
if ( abfd - > tdata . coff_obj_data = = NULL )
return FALSE ;
coff = coff_data ( abfd ) ;
coff - > symbols = NULL ;
coff - > conversion_table = NULL ;
coff - > raw_syments = NULL ;
coff - > relocbase = 0 ;
coff - > local_toc_sym_map = 0 ;
go32exe_create_stub ( abfd ) ;
if ( coff - > stub = = NULL )
{
bfd_release ( abfd , coff ) ;
return FALSE ;
}
abfd - > origin = coff - > stub_size ;
/* make_abs_section(abfd);*/ /* ??? */
return TRUE ;
}