diff options
Diffstat (limited to 'contrib/binutils/bfd/peXXigen.c')
-rw-r--r-- | contrib/binutils/bfd/peXXigen.c | 249 |
1 files changed, 167 insertions, 82 deletions
diff --git a/contrib/binutils/bfd/peXXigen.c b/contrib/binutils/bfd/peXXigen.c index b643f3c..598aa7c 100644 --- a/contrib/binutils/bfd/peXXigen.c +++ b/contrib/binutils/bfd/peXXigen.c @@ -1,5 +1,5 @@ /* Support for the generic parts of PE/PEI; the common executable parts. - Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Written by Cygnus Solutions. @@ -91,10 +91,10 @@ static void add_data_entry PARAMS ((bfd *, struct internal_extra_pe_aouthdr *, int, char *, bfd_vma)); -static boolean pe_print_pdata PARAMS ((bfd *, PTR)); -static boolean pe_print_reloc PARAMS ((bfd *, PTR)); -static boolean pe_print_idata PARAMS ((bfd *, PTR)); -static boolean pe_print_edata PARAMS ((bfd *, PTR)); +static bfd_boolean pe_print_pdata PARAMS ((bfd *, PTR)); +static bfd_boolean pe_print_reloc PARAMS ((bfd *, PTR)); +static bfd_boolean pe_print_idata PARAMS ((bfd *, PTR)); +static bfd_boolean pe_print_edata PARAMS ((bfd *, PTR)); void @@ -570,7 +570,8 @@ _bfd_XXi_swap_aouthdr_out (abfd, in, out) struct internal_extra_pe_aouthdr *extra = &pe->pe_opthdr; PEAOUTHDR *aouthdr_out = (PEAOUTHDR *) out; bfd_vma sa, fa, ib; - + IMAGE_DATA_DIRECTORY idata2, idata5, tls; + if (pe->force_minimum_alignment) { if (!extra->FileAlignment) @@ -586,6 +587,10 @@ _bfd_XXi_swap_aouthdr_out (abfd, in, out) fa = extra->FileAlignment; ib = extra->ImageBase; + idata2 = pe->pe_opthdr.DataDirectory[1]; + idata5 = pe->pe_opthdr.DataDirectory[12]; + tls = pe->pe_opthdr.DataDirectory[9]; + if (aouthdr_in->tsize) { aouthdr_in->text_start -= ib; @@ -614,28 +619,35 @@ _bfd_XXi_swap_aouthdr_out (abfd, in, out) #define SA(x) (((x) + sa -1 ) & (- sa)) /* We like to have the sizes aligned. */ - aouthdr_in->bsize = FA (aouthdr_in->bsize); extra->NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; - /* first null out all data directory entries .. */ + /* First null out all data directory entries. */ memset (extra->DataDirectory, 0, sizeof (extra->DataDirectory)); add_data_entry (abfd, extra, 0, ".edata", ib); - - /* Don't call add_data_entry for .idata$2 or .idata$5. It's done in - bfd_coff_final_link where all the required information is - available. */ - - /* However, until other .idata fixes are made (pending patch), the - entry for .idata is needed for backwards compatability. FIXME. */ - add_data_entry (abfd, extra, 1, ".idata", ib); - add_data_entry (abfd, extra, 2, ".rsrc", ib); - add_data_entry (abfd, extra, 3, ".pdata", ib); + /* In theory we do not need to call add_data_entry for .idata$2 or + .idata$5. It will be done in bfd_coff_final_link where all the + required information is available. If however, we are not going + to perform a final link, eg because we have been invoked by objcopy + or strip, then we need to make sure that these Data Directory + entries are initialised properly. + + So - we copy the input values into the output values, and then, if + a final link is going to be performed, it can overwrite them. */ + extra->DataDirectory[1] = idata2; + extra->DataDirectory[12] = idata5; + extra->DataDirectory[9] = tls; + + if (extra->DataDirectory[1].VirtualAddress == 0) + /* Until other .idata fixes are made (pending patch), the entry for + .idata is needed for backwards compatibility. FIXME. */ + add_data_entry (abfd, extra, 1, ".idata", ib); + /* For some reason, the virtual size (which is what's set by add_data_entry) for .reloc is not the same as the size recorded in this slot by MSVC; it doesn't seem to cause problems (so far), @@ -663,7 +675,9 @@ _bfd_XXi_swap_aouthdr_out (abfd, in, out) 5.0 link.exe) where the file size of the .data segment is quite small compared to the virtual size. Without this fix, strip munges the file. */ - isize += SA (FA (pei_section_data (abfd, sec)->virt_size)); + if (coff_section_data (abfd, sec) != NULL + && pei_section_data (abfd, sec) != NULL) + isize += SA (FA (pei_section_data (abfd, sec)->virt_size)); } aouthdr_in->dsize = dsize; @@ -689,7 +703,7 @@ _bfd_XXi_swap_aouthdr_out (abfd, in, out) aouthdr_out->standard.text_start); #ifndef COFF_WITH_pep - /* PE32+ does not have data_start member! */ + /* PE32+ does not have data_start member! */ PUT_AOUTHDR_DATA_START (abfd, aouthdr_in->data_start, aouthdr_out->standard.data_start); #endif @@ -895,12 +909,24 @@ _bfd_XXi_swap_scnhdr_out (abfd, in, out) sometimes). */ if ((scnhdr_int->s_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != 0) { - ps = scnhdr_int->s_size; - ss = 0; + if (bfd_pe_executable_p (abfd)) + { + ps = scnhdr_int->s_size; + ss = 0; + } + else + { + ps = 0; + ss = scnhdr_int->s_size; + } } else { - ps = scnhdr_int->s_paddr; + if (bfd_pe_executable_p (abfd)) + ps = scnhdr_int->s_paddr; + else + ps = 0; + ss = scnhdr_int->s_size; } @@ -917,33 +943,76 @@ _bfd_XXi_swap_scnhdr_out (abfd, in, out) PUT_SCNHDR_LNNOPTR (abfd, scnhdr_int->s_lnnoptr, scnhdr_ext->s_lnnoptr); - /* Extra flags must be set when dealing with NT. All sections should also - have the IMAGE_SCN_MEM_READ (0x40000000) flag set. In addition, the - .text section must have IMAGE_SCN_MEM_EXECUTE (0x20000000) and the data - sections (.idata, .data, .bss, .CRT) must have IMAGE_SCN_MEM_WRITE set - (this is especially important when dealing with the .idata section since - the addresses for routines from .dlls must be overwritten). If .reloc - section data is ever generated, we must add IMAGE_SCN_MEM_DISCARDABLE - (0x02000000). Also, the resource data should also be read and - writable. */ - - /* FIXME: alignment is also encoded in this field, at least on ppc (krk) */ - /* FIXME: even worse, I don't see how to get the original alignment field*/ - /* back... */ - { + /* Extra flags must be set when dealing with PE. All sections should also + have the IMAGE_SCN_MEM_READ (0x40000000) flag set. In addition, the + .text section must have IMAGE_SCN_MEM_EXECUTE (0x20000000) and the data + sections (.idata, .data, .bss, .CRT) must have IMAGE_SCN_MEM_WRITE set + (this is especially important when dealing with the .idata section since + the addresses for routines from .dlls must be overwritten). If .reloc + section data is ever generated, we must add IMAGE_SCN_MEM_DISCARDABLE + (0x02000000). Also, the resource data should also be read and + writable. */ + + /* FIXME: Alignment is also encoded in this field, at least on PPC and + ARM-WINCE. Although - how do we get the original alignment field + back ? */ + + typedef struct + { + const char * section_name; + unsigned long must_have; + } + pe_required_section_flags; + + pe_required_section_flags known_sections [] = + { + { ".arch", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_8BYTES }, + { ".bss", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".data", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".edata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, + { ".idata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".pdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, + { ".rdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, + { ".reloc", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE }, + { ".rsrc", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".text" , IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE }, + { ".tls", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE }, + { ".xdata", IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA }, + { NULL, 0} + }; + + pe_required_section_flags * p; int flags = scnhdr_int->s_flags; + /* We have defaulted to adding the IMAGE_SCN_MEM_WRITE flag, but now + we know exactly what this specific section wants so we remove it + and then allow the must_have field to add it back in if necessary. + However, we don't remove IMAGE_SCN_MEM_WRITE flag from .text if the + default WP_TEXT file flag has been cleared. WP_TEXT may be cleared + by ld --enable-auto-import (if auto-import is actually needed), + by ld --omagic, or by obcopy --writable-text. */ + + for (p = known_sections; p->section_name; p++) + if (strcmp (scnhdr_int->s_name, p->section_name) == 0) + { + if (strcmp (scnhdr_int->s_name, ".text") + || (bfd_get_file_flags (abfd) & WP_TEXT)) + flags &= ~IMAGE_SCN_MEM_WRITE; + flags |= p->must_have; + break; + } + H_PUT_32 (abfd, flags, scnhdr_ext->s_flags); } if (coff_data (abfd)->link_info - && ! coff_data (abfd)->link_info->relocateable + && ! coff_data (abfd)->link_info->relocatable && ! coff_data (abfd)->link_info->shared && strcmp (scnhdr_int->s_name, ".text") == 0) { /* By inference from looking at MS output, the 32 bit field - which is the combintion of the number_of_relocs and + which is the combination of the number_of_relocs and number_of_linenos is used for the line number count in executables. A 16-bit field won't do for cc1. The MS document says that the number of relocs is zero for @@ -967,7 +1036,11 @@ _bfd_XXi_swap_scnhdr_out (abfd, in, out) ret = 0; } - if (scnhdr_int->s_nreloc <= 0xffff) + /* Although we could encode 0xffff relocs here, we do not, to be + consistent with other parts of bfd. Also it lets us warn, as + we should never see 0xffff here w/o having the overflow flag + set. */ + if (scnhdr_int->s_nreloc < 0xffff) H_PUT_16 (abfd, scnhdr_int->s_nreloc, scnhdr_ext->s_nreloc); else { @@ -1016,7 +1089,7 @@ static char * dir_names[IMAGE_NUMBEROF_DIRECTORY_ENTRIES] = PPC- specific code. */ #endif -static boolean +static bfd_boolean pe_print_idata (abfd, vfile) bfd *abfd; PTR vfile; @@ -1048,12 +1121,12 @@ pe_print_idata (abfd, vfile) /* Maybe the extra header isn't there. Look for the section. */ section = bfd_get_section_by_name (abfd, ".idata"); if (section == NULL) - return true; + return TRUE; addr = section->vma; datasize = bfd_section_size (abfd, section); if (datasize == 0) - return true; + return TRUE; } else { @@ -1069,7 +1142,7 @@ pe_print_idata (abfd, vfile) { fprintf (file, _("\nThere is an import table, but the section containing it could not be found\n")); - return true; + return TRUE; } } @@ -1098,7 +1171,7 @@ pe_print_idata (abfd, vfile) amt = bfd_section_size (abfd, rel_section); data = (bfd_byte *) bfd_malloc (amt); if (data == NULL && amt != 0) - return false; + return FALSE; bfd_get_section_contents (abfd, rel_section, (PTR) data, (bfd_vma) 0, amt); @@ -1134,11 +1207,11 @@ pe_print_idata (abfd, vfile) amt = dataoff + datasize; data = (bfd_byte *) bfd_malloc (amt); if (data == NULL) - return false; + return FALSE; /* Read the whole section. Some of the fields might be before dataoff. */ if (! bfd_get_section_contents (abfd, section, (PTR) data, (bfd_vma) 0, amt)) - return false; + return FALSE; adj = section->vma - extra->ImageBase; @@ -1290,10 +1363,10 @@ pe_print_idata (abfd, vfile) free (data); - return true; + return TRUE; } -static boolean +static bfd_boolean pe_print_edata (abfd, vfile) bfd *abfd; PTR vfile; @@ -1332,12 +1405,12 @@ pe_print_edata (abfd, vfile) /* Maybe the extra header isn't there. Look for the section. */ section = bfd_get_section_by_name (abfd, ".edata"); if (section == NULL) - return true; + return TRUE; addr = section->vma; datasize = bfd_section_size (abfd, section); if (datasize == 0) - return true; + return TRUE; } else { @@ -1355,7 +1428,7 @@ pe_print_edata (abfd, vfile) { fprintf (file, _("\nThere is an export table, but the section containing it could not be found\n")); - return true; + return TRUE; } } @@ -1367,11 +1440,11 @@ pe_print_edata (abfd, vfile) data = (bfd_byte *) bfd_malloc (datasize); if (data == NULL) - return false; + return FALSE; if (! bfd_get_section_contents (abfd, section, (PTR) data, (file_ptr) dataoff, datasize)) - return false; + return FALSE; /* Go get Export Directory Table. */ edt.export_flags = bfd_get_32 (abfd, data + 0); @@ -1508,7 +1581,7 @@ pe_print_edata (abfd, vfile) free (data); - return true; + return TRUE; } /* This really is architecture dependent. On IA-64, a .pdata entry @@ -1516,7 +1589,7 @@ pe_print_edata (abfd, vfile) specify the start and end address of the code range the entry covers and the address of the corresponding unwind info data. */ -static boolean +static bfd_boolean pe_print_pdata (abfd, vfile) bfd *abfd; PTR vfile; @@ -1537,7 +1610,7 @@ pe_print_pdata (abfd, vfile) if (section == NULL || coff_section_data (abfd, section) == NULL || pei_section_data (abfd, section) == NULL) - return true; + return TRUE; stop = pei_section_data (abfd, section)->virt_size; if ((stop % onaline) != 0) @@ -1558,11 +1631,11 @@ pe_print_pdata (abfd, vfile) datasize = bfd_section_size (abfd, section); if (datasize == 0) - return true; + return TRUE; data = (bfd_byte *) bfd_malloc (datasize); if (data == NULL && datasize != 0) - return false; + return FALSE; bfd_get_section_contents (abfd, section, (PTR) data, (bfd_vma) 0, datasize); @@ -1639,7 +1712,7 @@ pe_print_pdata (abfd, vfile) free (data); - return true; + return TRUE; } #define IMAGE_REL_BASED_HIGHADJ 4 @@ -1660,7 +1733,7 @@ static const char * const tbl[] = "UNKNOWN", /* MUST be last */ }; -static boolean +static bfd_boolean pe_print_reloc (abfd, vfile) bfd *abfd; PTR vfile; @@ -1673,10 +1746,10 @@ pe_print_reloc (abfd, vfile) bfd_size_type start, stop; if (section == NULL) - return true; + return TRUE; if (bfd_section_size (abfd, section) == 0) - return true; + return TRUE; fprintf (file, _("\n\nPE File Base Relocations (interpreted .reloc section contents)\n")); @@ -1684,7 +1757,7 @@ pe_print_reloc (abfd, vfile) datasize = bfd_section_size (abfd, section); data = (bfd_byte *) bfd_malloc (datasize); if (data == NULL && datasize != 0) - return false; + return FALSE; bfd_get_section_contents (abfd, section, (PTR) data, (bfd_vma) 0, datasize); @@ -1743,12 +1816,12 @@ pe_print_reloc (abfd, vfile) free (data); - return true; + return TRUE; } /* Print out the program headers. */ -boolean +bfd_boolean _bfd_XX_print_private_bfd_data_common (abfd, vfile) bfd *abfd; PTR vfile; @@ -1859,20 +1932,20 @@ _bfd_XX_print_private_bfd_data_common (abfd, vfile) pe_print_pdata (abfd, vfile); pe_print_reloc (abfd, vfile); - return true; + return TRUE; } /* Copy any private info we understand from the input bfd to the output bfd. */ -boolean +bfd_boolean _bfd_XX_bfd_copy_private_bfd_data_common (ibfd, obfd) bfd *ibfd, *obfd; { /* One day we may try to grok other private data. */ if (ibfd->xvec->flavour != bfd_target_coff_flavour || obfd->xvec->flavour != bfd_target_coff_flavour) - return true; + return TRUE; pe_data (obfd)->pe_opthdr = pe_data (ibfd)->pe_opthdr; pe_data (obfd)->dll = pe_data (ibfd)->dll; @@ -1884,12 +1957,12 @@ _bfd_XX_bfd_copy_private_bfd_data_common (ibfd, obfd) pe_data (obfd)->pe_opthdr.DataDirectory[5].VirtualAddress = 0; pe_data (obfd)->pe_opthdr.DataDirectory[5].Size = 0; } - return true; + return TRUE; } /* Copy private section data. */ -boolean +bfd_boolean _bfd_XX_bfd_copy_private_section_data (ibfd, isec, obfd, osec) bfd *ibfd; asection *isec; @@ -1898,7 +1971,7 @@ _bfd_XX_bfd_copy_private_section_data (ibfd, isec, obfd, osec) { if (bfd_get_flavour (ibfd) != bfd_target_coff_flavour || bfd_get_flavour (obfd) != bfd_target_coff_flavour) - return true; + return TRUE; if (coff_section_data (ibfd, isec) != NULL && pei_section_data (ibfd, isec) != NULL) @@ -1908,7 +1981,7 @@ _bfd_XX_bfd_copy_private_section_data (ibfd, isec, obfd, osec) bfd_size_type amt = sizeof (struct coff_section_tdata); osec->used_by_bfd = (PTR) bfd_zalloc (obfd, amt); if (osec->used_by_bfd == NULL) - return false; + return FALSE; } if (pei_section_data (obfd, osec) == NULL) @@ -1916,7 +1989,7 @@ _bfd_XX_bfd_copy_private_section_data (ibfd, isec, obfd, osec) bfd_size_type amt = sizeof (struct pei_section_tdata); coff_section_data (obfd, osec)->tdata = (PTR) bfd_zalloc (obfd, amt); if (coff_section_data (obfd, osec)->tdata == NULL) - return false; + return FALSE; } pei_section_data (obfd, osec)->virt_size = @@ -1925,7 +1998,7 @@ _bfd_XX_bfd_copy_private_section_data (ibfd, isec, obfd, osec) pei_section_data (ibfd, isec)->pe_flags; } - return true; + return TRUE; } void @@ -1948,7 +2021,7 @@ _bfd_XX_get_symbol_info (abfd, symbol, ret) /* Handle the .idata section and other things that need symbol table access. */ -boolean +bfd_boolean _bfd_XXi_final_link_postscript (abfd, pfinfo) bfd *abfd; struct coff_final_link_info *pfinfo; @@ -1965,7 +2038,7 @@ _bfd_XXi_final_link_postscript (abfd, pfinfo) /* The import directory. This is the address of .idata$2, with size of .idata$2 + .idata$3. */ h1 = coff_link_hash_lookup (coff_hash_table (info), - ".idata$2", false, false, true); + ".idata$2", FALSE, FALSE, TRUE); if (h1 != NULL) { pe_data (abfd)->pe_opthdr.DataDirectory[1].VirtualAddress = @@ -1973,7 +2046,7 @@ _bfd_XXi_final_link_postscript (abfd, pfinfo) + h1->root.u.def.section->output_section->vma + h1->root.u.def.section->output_offset); h1 = coff_link_hash_lookup (coff_hash_table (info), - ".idata$4", false, false, true); + ".idata$4", FALSE, FALSE, TRUE); pe_data (abfd)->pe_opthdr.DataDirectory[1].Size = ((h1->root.u.def.value + h1->root.u.def.section->output_section->vma @@ -1983,22 +2056,34 @@ _bfd_XXi_final_link_postscript (abfd, pfinfo) /* The import address table. This is the size/address of .idata$5. */ h1 = coff_link_hash_lookup (coff_hash_table (info), - ".idata$5", false, false, true); + ".idata$5", FALSE, FALSE, TRUE); pe_data (abfd)->pe_opthdr.DataDirectory[12].VirtualAddress = (h1->root.u.def.value + h1->root.u.def.section->output_section->vma + h1->root.u.def.section->output_offset); h1 = coff_link_hash_lookup (coff_hash_table (info), - ".idata$6", false, false, true); + ".idata$6", FALSE, FALSE, TRUE); pe_data (abfd)->pe_opthdr.DataDirectory[12].Size = ((h1->root.u.def.value + h1->root.u.def.section->output_section->vma + h1->root.u.def.section->output_offset) - - pe_data (abfd)->pe_opthdr.DataDirectory[12].VirtualAddress); + - pe_data (abfd)->pe_opthdr.DataDirectory[12].VirtualAddress); + } + + h1 = coff_link_hash_lookup (coff_hash_table (info), + "__tls_used", FALSE, FALSE, TRUE); + if (h1 != NULL) + { + pe_data (abfd)->pe_opthdr.DataDirectory[9].VirtualAddress = + (h1->root.u.def.value + + h1->root.u.def.section->output_section->vma + + h1->root.u.def.section->output_offset + - pe_data (abfd)->pe_opthdr.ImageBase); + pe_data (abfd)->pe_opthdr.DataDirectory[9].Size = 0x18; } /* If we couldn't find idata$2, we either have an excessively trivial program or are in DEEP trouble; we have to assume trivial program.... */ - return true; + return TRUE; } |