Fix for winnt PE bfd problem
Zik Saleeba
zik@zikzak.net
Wed Apr 26 07:02:00 GMT 2000
A couple of days ago I posted about a problem in BFD with reading
some winnt PE format executables. A fix follows.
The problem was related to the fact that PEI format executable
headers are permitted to have a variable length which is indicated by
a field in the fixed-length portion. Nearly all winnt exe files to
date use an identical length for this supposedly variable-length
header, but some recent ones I've come across have differed, breaking
the existing code. There was a self-described hack in the code which
attempted to deal with this case but which didn't work.
I've replaced the hack with a more elegant approach and have tried to
clean up some of the related code in the process.
Zik
bfd/ChangeLog:
----------------------------------------------------------------------------------
Wed Apr 26 23:37:15 2000 Zik Saleeba (zik@zikzak.net)
* coffgen.c, peicode.h, peigen.c: now allows for the fact that
winnt PE exe files have variable-length headers.
----------------------------------------------------------------------------------
include/coff/ChangeLog:
----------------------------------------------------------------------------------
Wed Apr 26 23:37:17 2000 Zik Saleeba (zik@zikzak.net)
* pe.h: now allows for the fact that winnt PE exe files have
variable-length headers.
----------------------------------------------------------------------------------
diff -rup binutils/src/bfd/coffgen.c binutils-fixed/src/bfd/coffgen.c
--- binutils/src/bfd/coffgen.c Fri Apr 7 10:58:06 2000
+++ binutils-fixed/src/bfd/coffgen.c Wed Apr 26 23:24:07 2000
@@ -255,9 +255,38 @@ coff_object_p (abfd)
PTR filehdr;
struct internal_filehdr internal_f;
struct internal_aouthdr internal_a;
+ int lfa_offset = (char *)&internal_f.pe.e_lfanew - (char *)&internal_f; /* will be 0x3c */;
/* figure out how much to read */
- filhsz = bfd_coff_filhsz (abfd);
+ if (strncmp(abfd->xvec->name, "pei-", 4) == 0) /* XXX - is there a better way of identifying pei? */
+ {
+ /* NOTE - we use target-specific code here since there
+ * seems no better place to handle PEI variable-length headers */
+ bfd_byte buffer[4];
+
+ /* for PEI files the lfa longword at 0x3c tells us where the coff header starts */
+ if (bfd_seek (abfd, lfa_offset, SEEK_SET) != 0
+ || bfd_read (buffer, 1, 4, abfd) != 4)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ filhsz = bfd_h_get_32 (abfd, buffer) + ((char *)&internal_f.f_target_id - (char *)&internal_f.pe.nt_signature); /* 24 bytes from the nt signature to the end of the coff header */;
+
+ /* go back to the start */
+ if (bfd_seek (abfd, 0, SEEK_SET) != 0)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_wrong_format);
+ return NULL;
+ }
+
+ }
+ else
+ filhsz = bfd_coff_filhsz (abfd);
+
aoutsz = bfd_coff_aoutsz (abfd);
filehdr = bfd_alloc (abfd, filhsz);
diff -rup binutils/src/bfd/peicode.h binutils-fixed/src/bfd/peicode.h
--- binutils/src/bfd/peicode.h Thu Apr 13 11:08:04 2000
+++ binutils-fixed/src/bfd/peicode.h Wed Apr 26 23:24:07 2000
@@ -202,13 +202,26 @@ coff_swap_filehdr_in (abfd, src, dst)
{
FILHDR *filehdr_src = (FILHDR *) src;
struct internal_filehdr *filehdr_dst = (struct internal_filehdr *) dst;
- filehdr_dst->f_magic = bfd_h_get_16(abfd, (bfd_byte *) filehdr_src->f_magic);
- filehdr_dst->f_nscns = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_nscns);
- filehdr_dst->f_timdat = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_timdat);
-
- filehdr_dst->f_nsyms = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> f_nsyms);
- filehdr_dst->f_flags = bfd_h_get_16(abfd, (bfd_byte *)filehdr_src-> f_flags);
- filehdr_dst->f_symptr = bfd_h_get_32 (abfd, (bfd_byte *) filehdr_src->f_symptr);
+
+#if defined(FILHDRNT) && defined(COFF_IMAGE_WITH_PE)
+ unsigned short start_magic = bfd_h_get_16 (abfd, (bfd_byte *) filehdr_src->e_magic);
+ unsigned long lfa_offset = bfd_h_get_32(abfd, (bfd_byte *)filehdr_src-> e_lfanew);
+ FILHDRNT *ntfilehdr_src;
+ if (start_magic == DOSMAGIC && lfa_offset < 0x1000) /* sanity check */
+ ntfilehdr_src = (FILHDRNT *)(src + lfa_offset);
+ else
+ ntfilehdr_src = (FILHDRNT *)filehdr_src->nt_hdr.nt_signature;
+#else
+ FILHDR *ntfilehdr_src = filehdr_src;
+#endif
+
+ filehdr_dst->f_magic = bfd_h_get_16(abfd, (bfd_byte *)ntfilehdr_src->f_magic);
+ filehdr_dst->f_nscns = bfd_h_get_16(abfd, (bfd_byte *)ntfilehdr_src->f_nscns);
+ filehdr_dst->f_timdat = bfd_h_get_32(abfd, (bfd_byte *)ntfilehdr_src->f_timdat);
+
+ filehdr_dst->f_nsyms = bfd_h_get_32(abfd, (bfd_byte *)ntfilehdr_src->f_nsyms);
+ filehdr_dst->f_flags = bfd_h_get_16(abfd, (bfd_byte *)ntfilehdr_src->f_flags);
+ filehdr_dst->f_symptr = bfd_h_get_32 (abfd, (bfd_byte *)ntfilehdr_src->f_symptr);
#ifdef COFF_IMAGE_WITH_PE
/* There are really two magic numbers involved; the magic number
@@ -221,7 +234,7 @@ coff_swap_filehdr_in (abfd, src, dst)
correctly for a PEI file, check the e_magic number here, and, if
it doesn't match, clobber the f_magic number so that we don't get
a false match. */
- if (bfd_h_get_16 (abfd, (bfd_byte *) filehdr_src->e_magic) != DOSMAGIC)
+ if (start_magic != DOSMAGIC)
filehdr_dst->f_magic = -1;
#endif
@@ -234,7 +247,7 @@ coff_swap_filehdr_in (abfd, src, dst)
}
filehdr_dst->f_opthdr = bfd_h_get_16(abfd,
- (bfd_byte *)filehdr_src-> f_opthdr);
+ (bfd_byte *)ntfilehdr_src->f_opthdr);
}
#ifdef COFF_IMAGE_WITH_PE
@@ -1264,6 +1277,8 @@ pe_bfd_object_p (bfd * abfd)
bfd_byte buffer[4];
file_ptr offset;
unsigned long signature;
+ struct external_PEI_filehdr pe_hdr;
+ int lfa_offset;
/* Detect if this a Microsoft Import Library Format element. */
if (bfd_seek (abfd, 0x00, SEEK_SET) != 0
@@ -1279,7 +1294,8 @@ pe_bfd_object_p (bfd * abfd)
if (signature == 0xffff0000)
return pe_ILF_object_p (abfd);
- if (bfd_seek (abfd, 0x3c, SEEK_SET) != 0
+ lfa_offset = pe_hdr.e_lfanew - (char *)&pe_hdr; /* will be 0x3c */
+ if (bfd_seek (abfd, lfa_offset, SEEK_SET) != 0
|| bfd_read (buffer, 1, 4, abfd) != 4)
{
if (bfd_get_error () != bfd_error_system_call)
@@ -1299,21 +1315,14 @@ pe_bfd_object_p (bfd * abfd)
signature = bfd_h_get_32 (abfd, buffer);
- if (signature != 0x4550)
+ if (signature != NT_SIGNATURE) /* will be 0x00004550 */
{
bfd_set_error (bfd_error_wrong_format);
return NULL;
}
- /* Here is the hack. coff_object_p wants to read filhsz bytes to
- pick up the COFF header. We adjust so that that will work. 20
- is the size of the i386 COFF filehdr. */
- if (bfd_seek (abfd,
- (bfd_tell (abfd)
- - bfd_coff_filhsz (abfd)
- + 20),
- SEEK_SET)
- != 0)
+ /* return to the start of the file */
+ if (bfd_seek (abfd, 0x0, SEEK_SET) != 0)
{
if (bfd_get_error () != bfd_error_system_call)
bfd_set_error (bfd_error_wrong_format);
diff -rup binutils/src/bfd/peigen.c binutils-fixed/src/bfd/peigen.c
--- binutils/src/bfd/peigen.c Tue Apr 18 14:03:16 2000
+++ binutils-fixed/src/bfd/peigen.c Wed Apr 26 23:24:07 2000
@@ -787,15 +787,15 @@ _bfd_pei_only_swap_filehdr_out (abfd, in
- bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->f_magic);
- bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->f_nscns);
+ bfd_h_put_16(abfd, filehdr_in->f_magic, (bfd_byte *) filehdr_out->nt_hdr.f_magic);
+ bfd_h_put_16(abfd, filehdr_in->f_nscns, (bfd_byte *) filehdr_out->nt_hdr.f_nscns);
- bfd_h_put_32(abfd, time (0), (bfd_byte *) filehdr_out->f_timdat);
+ bfd_h_put_32(abfd, time (0), (bfd_byte *) filehdr_out->nt_hdr.f_timdat);
PUT_FILEHDR_SYMPTR (abfd, (bfd_vma) filehdr_in->f_symptr,
- (bfd_byte *) filehdr_out->f_symptr);
- bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->f_nsyms);
- bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->f_opthdr);
- bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->f_flags);
+ (bfd_byte *) filehdr_out->nt_hdr.f_symptr);
+ bfd_h_put_32(abfd, filehdr_in->f_nsyms, (bfd_byte *) filehdr_out->nt_hdr.f_nsyms);
+ bfd_h_put_16(abfd, filehdr_in->f_opthdr, (bfd_byte *) filehdr_out->nt_hdr.f_opthdr);
+ bfd_h_put_16(abfd, filehdr_in->f_flags, (bfd_byte *) filehdr_out->nt_hdr.f_flags);
/* put in extra dos header stuff. This data remains essentially
constant, it just has to be tacked on to the beginning of all exes
@@ -843,7 +843,7 @@ _bfd_pei_only_swap_filehdr_out (abfd, in
/* also put in the NT signature */
bfd_h_put_32(abfd, filehdr_in->pe.nt_signature,
- (bfd_byte *) filehdr_out->nt_signature);
+ (bfd_byte *) filehdr_out->nt_hdr.nt_signature);
diff -rup binutils/src/include/coff/pe.h binutils-fixed/src/include/coff/pe.h
--- binutils/src/include/coff/pe.h Tue Apr 18 09:45:22 2000
+++ binutils-fixed/src/include/coff/pe.h Wed Apr 26 23:27:42 2000
@@ -108,6 +108,21 @@
#undef FILNMLEN
#define FILNMLEN 18 /* # characters in a file name */
+struct external_PEI_ntfilehdr
+{
+ char nt_signature[4]; /* required NT signature, 0x4550 */
+
+ /* From standard header */
+
+ char f_magic[2]; /* magic number */
+ char f_nscns[2]; /* number of sections */
+ char f_timdat[4]; /* time & date stamp */
+ char f_symptr[4]; /* file pointer to symtab */
+ char f_nsyms[4]; /* number of symtab entries */
+ char f_opthdr[2]; /* sizeof(optional hdr) */
+ char f_flags[2]; /* flags */
+};
+
struct external_PEI_filehdr
{
/* DOS header fields */
@@ -131,17 +146,12 @@ struct external_PEI_filehdr
char e_res2[10][2]; /* Reserved words, all 0x0 */
char e_lfanew[4]; /* File address of new exe header, 0x80 */
char dos_message[16][4]; /* other stuff, always follow DOS header */
- char nt_signature[4]; /* required NT signature, 0x4550 */
-
- /* From standard header */
-
- char f_magic[2]; /* magic number */
- char f_nscns[2]; /* number of sections */
- char f_timdat[4]; /* time & date stamp */
- char f_symptr[4]; /* file pointer to symtab */
- char f_nsyms[4]; /* number of symtab entries */
- char f_opthdr[2]; /* sizeof(optional hdr) */
- char f_flags[2]; /* flags */
+
+ /* the NT COFF header (used here when writing a
+ * fixed-size header, otherwise ignored since
+ * this header can move around depending
+ * on e_lfanew) */
+ struct external_PEI_ntfilehdr nt_hdr;
};
#ifdef COFF_IMAGE_WITH_PE
@@ -150,6 +160,7 @@ struct external_PEI_filehdr
#undef FILHDR
#define FILHDR struct external_PEI_filehdr
+#define FILHDRNT struct external_PEI_ntfilehdr
#undef FILHSZ
#define FILHSZ 152
More information about the Binutils
mailing list