diff options
author | Nick Clifton <nickc@redhat.com> | 2001-02-27 01:38:06 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2001-02-27 01:38:06 +0000 |
commit | 1276aefac0c17c873ad778bd853aca0d4eb5b6d4 (patch) | |
tree | 6cc9a7ef0e947ffbccbc3b257a030fe930615053 /bfd/coffcode.h | |
parent | fa7cd6d20a3e995b102606abc198502a91bccec4 (diff) | |
download | gdb-1276aefac0c17c873ad778bd853aca0d4eb5b6d4.zip gdb-1276aefac0c17c873ad778bd853aca0d4eb5b6d4.tar.gz gdb-1276aefac0c17c873ad778bd853aca0d4eb5b6d4.tar.bz2 |
BFD: Catch & report unhandled PE section flags.
LD: Catch BFD errors whilst loading symbols and do not produce an executable.
Diffstat (limited to 'bfd/coffcode.h')
-rw-r--r-- | bfd/coffcode.h | 630 |
1 files changed, 343 insertions, 287 deletions
diff --git a/bfd/coffcode.h b/bfd/coffcode.h index fce0491..29b4ab3 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -339,6 +339,9 @@ static long coff_canonicalize_reloc #ifndef coff_mkobject_hook static PTR coff_mkobject_hook PARAMS ((bfd *, PTR, PTR)); #endif +#ifdef COFF_WITH_PE +static flagword handle_COMDAT PARAMS ((bfd *, flagword, PTR, const char *, asection *)); +#endif /* void warning(); */ @@ -698,329 +701,382 @@ styp_to_sec_flags (abfd, hdr, name, section) #else /* COFF_WITH_PE */ -/* The PE version; see above for the general comments. - - Since to set the SEC_LINK_ONCE and associated flags, we have to - look at the symbol table anyway, we return the symbol table index - of the symbol being used as the COMDAT symbol. This is admittedly - ugly, but there's really nowhere else that we have access to the - required information. FIXME: Is the COMDAT symbol index used for - any purpose other than objdump? */ - static flagword -styp_to_sec_flags (abfd, hdr, name, section) - bfd *abfd ATTRIBUTE_UNUSED; +handle_COMDAT (abfd, sec_flags, hdr, name, section) + bfd * abfd; + flagword sec_flags; PTR hdr; const char *name; asection *section; { struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; - long styp_flags = internal_s->s_flags; - flagword sec_flags = 0; - - if (styp_flags & STYP_DSECT) - abort (); /* Don't know what to do */ -#ifdef SEC_NEVER_LOAD - if (styp_flags & STYP_NOLOAD) - sec_flags |= SEC_NEVER_LOAD; -#endif - if (styp_flags & STYP_GROUP) - abort (); /* Don't know what to do */ - /* skip IMAGE_SCN_TYPE_NO_PAD */ - if (styp_flags & STYP_COPY) - abort (); /* Don't know what to do */ - if (styp_flags & IMAGE_SCN_CNT_CODE) - sec_flags |= SEC_CODE | SEC_ALLOC | SEC_LOAD; - if (styp_flags & IMAGE_SCN_CNT_INITIALIZED_DATA) - sec_flags |= SEC_DATA | SEC_ALLOC | SEC_LOAD; - if (styp_flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA) - sec_flags |= SEC_ALLOC; - if (styp_flags & IMAGE_SCN_LNK_OTHER) - abort (); /* Don't know what to do */ - if (styp_flags & IMAGE_SCN_LNK_INFO) - { - /* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is - defined. coff_compute_section_file_positions uses - COFF_PAGE_SIZE to ensure that the low order bits of the - section VMA and the file offset match. If we don't know - COFF_PAGE_SIZE, we can't ensure the correct correspondence, - and demand page loading of the file will fail. */ -#ifdef COFF_PAGE_SIZE - sec_flags |= SEC_DEBUGGING; -#endif - } - if (styp_flags & STYP_OVER) - abort (); /* Don't know what to do */ - if (styp_flags & IMAGE_SCN_LNK_REMOVE) - sec_flags |= SEC_EXCLUDE; - - if (styp_flags & IMAGE_SCN_MEM_SHARED) - sec_flags |= SEC_SHARED; - /* COMDAT: see below */ - if (styp_flags & IMAGE_SCN_MEM_DISCARDABLE) - sec_flags |= SEC_DEBUGGING; - if (styp_flags & IMAGE_SCN_MEM_NOT_CACHED) - abort ();/* Don't know what to do */ - if (styp_flags & IMAGE_SCN_MEM_NOT_PAGED) - abort (); /* Don't know what to do */ - - /* We infer from the distinct read/write/execute bits the settings - of some of the bfd flags; the actual values, should we need them, - are also in pei_section_data (abfd, section)->pe_flags. */ - - if (styp_flags & IMAGE_SCN_MEM_EXECUTE) - sec_flags |= SEC_CODE; /* Probably redundant */ - /* IMAGE_SCN_MEM_READ is simply ignored, assuming it always to be true. */ - if ((styp_flags & IMAGE_SCN_MEM_WRITE) == 0) - sec_flags |= SEC_READONLY; - - /* COMDAT gets very special treatment. */ - if (styp_flags & IMAGE_SCN_LNK_COMDAT) + bfd_byte *esymstart, *esym, *esymend; + int seen_state = 0; + char *target_name = NULL; + + sec_flags |= SEC_LINK_ONCE; + + /* Unfortunately, the PE format stores essential information in + the symbol table, of all places. We need to extract that + information now, so that objdump and the linker will know how + to handle the section without worrying about the symbols. We + can't call slurp_symtab, because the linker doesn't want the + swapped symbols. */ + + /* COMDAT sections are special. The first symbol is the section + symbol, which tells what kind of COMDAT section it is. The + second symbol is the "comdat symbol" - the one with the + unique name. GNU uses the section symbol for the unique + name; MS uses ".text" for every comdat section. Sigh. - DJ */ + + /* This is not mirrored in sec_to_styp_flags(), but there + doesn't seem to be a need to, either, and it would at best be + rather messy. */ + + if (! _bfd_coff_get_external_symbols (abfd)) + return sec_flags; + + esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd); + esymend = esym + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); + + while (esym < esymend) { - sec_flags |= SEC_LINK_ONCE; - - /* Unfortunately, the PE format stores essential information in - the symbol table, of all places. We need to extract that - information now, so that objdump and the linker will know how - to handle the section without worrying about the symbols. We - can't call slurp_symtab, because the linker doesn't want the - swapped symbols. */ - - /* COMDAT sections are special. The first symbol is the section - symbol, which tells what kind of COMDAT section it is. The - second symbol is the "comdat symbol" - the one with the - unique name. GNU uses the section symbol for the unique - name; MS uses ".text" for every comdat section. Sigh. - DJ */ - - /* This is not mirrored in sec_to_styp_flags(), but there - doesn't seem to be a need to, either, and it would at best be - rather messy. */ - - if (_bfd_coff_get_external_symbols (abfd)) + struct internal_syment isym; + char buf[SYMNMLEN + 1]; + const char *symname; + + bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &isym); + + if (sizeof (internal_s->s_name) > SYMNMLEN) { - bfd_byte *esymstart, *esym, *esymend; - int seen_state = 0; - char *target_name = NULL; + /* This case implies that the matching + symbol name will be in the string table. */ + abort (); + } - esymstart = esym = (bfd_byte *) obj_coff_external_syms (abfd); - esymend = esym + obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); + if (isym.n_scnum == section->target_index) + { + /* According to the MSVC documentation, the first + TWO entries with the section # are both of + interest to us. The first one is the "section + symbol" (section name). The second is the comdat + symbol name. Here, we've found the first + qualifying entry; we distinguish it from the + second with a state flag. + + In the case of gas-generated (at least until that + is fixed) .o files, it isn't necessarily the + second one. It may be some other later symbol. + + Since gas also doesn't follow MS conventions and + emits the section similar to .text$<name>, where + <something> is the name we're looking for, we + distinguish the two as follows: + + If the section name is simply a section name (no + $) we presume it's MS-generated, and look at + precisely the second symbol for the comdat name. + If the section name has a $, we assume it's + gas-generated, and look for <something> (whatever + follows the $) as the comdat symbol. */ + + /* All 3 branches use this */ + symname = _bfd_coff_internal_syment_name (abfd, &isym, buf); + + if (symname == NULL) + abort (); - while (esym < esymend) + switch (seen_state) { - struct internal_syment isym; - char buf[SYMNMLEN + 1]; - const char *symname; + case 0: + { + /* The first time we've seen the symbol. */ + union internal_auxent aux; + + seen_state = 1; + + /* If it isn't the stuff we're expecting, die; + The MS documentation is vague, but it + appears that the second entry serves BOTH + as the comdat symbol and the defining + symbol record (either C_STAT or C_EXT, + possibly with an aux entry with debug + information if it's a function.) It + appears the only way to find the second one + is to count. (On Intel, they appear to be + adjacent, but on Alpha, they have been + found separated.) + + Here, we think we've found the first one, + but there's some checking we can do to be + sure. */ + + if (! (isym.n_sclass == C_STAT + && isym.n_type == T_NULL + && isym.n_value == 0)) + abort (); - bfd_coff_swap_sym_in (abfd, (PTR) esym, (PTR) &isym); + /* FIXME LATER: MSVC generates section names + like .text for comdats. Gas generates + names like .text$foo__Fv (in the case of a + function). See comment above for more. */ - if (sizeof (internal_s->s_name) > SYMNMLEN) - { - /* This case implies that the matching symbol name - will be in the string table. */ + if (strcmp (name, symname) != 0) abort (); - } - if (isym.n_scnum == section->target_index) - { - /* According to the MSVC documentation, the first - TWO entries with the section # are both of - interest to us. The first one is the "section - symbol" (section name). The second is the comdat - symbol name. Here, we've found the first - qualifying entry; we distinguish it from the - second with a state flag. - - In the case of gas-generated (at least until that - is fixed) .o files, it isn't necessarily the - second one. It may be some other later symbol. - - Since gas also doesn't follow MS conventions and - emits the section similar to .text$<name>, where - <something> is the name we're looking for, we - distinguish the two as follows: - - If the section name is simply a section name (no - $) we presume it's MS-generated, and look at - precisely the second symbol for the comdat name. - If the section name has a $, we assume it's - gas-generated, and look for <something> (whatever - follows the $) as the comdat symbol. */ - - /* All 3 branches use this */ - symname = _bfd_coff_internal_syment_name (abfd, &isym, buf); - - if (symname == NULL) - abort (); - - switch (seen_state) - { - case 0: - { - /* The first time we've seen the symbol. */ - union internal_auxent aux; - - seen_state = 1; - - /* If it isn't the stuff we're expecting, die; - The MS documentation is vague, but it - appears that the second entry serves BOTH - as the comdat symbol and the defining - symbol record (either C_STAT or C_EXT, - possibly with an aux entry with debug - information if it's a function.) It - appears the only way to find the second one - is to count. (On Intel, they appear to be - adjacent, but on Alpha, they have been - found separated.) - - Here, we think we've found the first one, - but there's some checking we can do to be - sure. */ - - if (! (isym.n_sclass == C_STAT - && isym.n_type == T_NULL - && isym.n_value == 0)) - abort (); - - /* FIXME LATER: MSVC generates section names - like .text for comdats. Gas generates - names like .text$foo__Fv (in the case of a - function). See comment above for more. */ - - if (strcmp (name, symname) != 0) - abort (); - - /* This is the section symbol. */ - - bfd_coff_swap_aux_in (abfd, (PTR) (esym + bfd_coff_symesz (abfd)), - isym.n_type, isym.n_sclass, - 0, isym.n_numaux, (PTR) &aux); - - target_name = strchr (name, '$'); - if (target_name != NULL) - { - /* Gas mode. */ - seen_state = 2; - /* Skip the `$'. */ - target_name += 1; - } - - /* FIXME: Microsoft uses NODUPLICATES and - ASSOCIATIVE, but gnu uses ANY and - SAME_SIZE. Unfortunately, gnu doesn't do - the comdat symbols right. So, until we can - fix it to do the right thing, we are - temporarily disabling comdats for the MS - types (they're used in DLLs and C++, but we - don't support *their* C++ libraries anyway - - DJ. */ - - /* Cygwin does not follow the MS style, and - uses ANY and SAME_SIZE where NODUPLICATES - and ASSOCIATIVE should be used. For - Interix, we just do the right thing up - front. */ - - switch (aux.x_scn.x_comdat) - { - case IMAGE_COMDAT_SELECT_NODUPLICATES: + /* This is the section symbol. */ + bfd_coff_swap_aux_in (abfd, (PTR) (esym + bfd_coff_symesz (abfd)), + isym.n_type, isym.n_sclass, + 0, isym.n_numaux, (PTR) &aux); + + target_name = strchr (name, '$'); + if (target_name != NULL) + { + /* Gas mode. */ + seen_state = 2; + /* Skip the `$'. */ + target_name += 1; + } + + /* FIXME: Microsoft uses NODUPLICATES and + ASSOCIATIVE, but gnu uses ANY and + SAME_SIZE. Unfortunately, gnu doesn't do + the comdat symbols right. So, until we can + fix it to do the right thing, we are + temporarily disabling comdats for the MS + types (they're used in DLLs and C++, but we + don't support *their* C++ libraries anyway + - DJ. */ + + /* Cygwin does not follow the MS style, and + uses ANY and SAME_SIZE where NODUPLICATES + and ASSOCIATIVE should be used. For + Interix, we just do the right thing up + front. */ + + switch (aux.x_scn.x_comdat) + { + case IMAGE_COMDAT_SELECT_NODUPLICATES: #ifdef STRICT_PE_FORMAT - sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY; + sec_flags |= SEC_LINK_DUPLICATES_ONE_ONLY; #else - sec_flags &= ~SEC_LINK_ONCE; + sec_flags &= ~SEC_LINK_ONCE; #endif - break; + break; - case IMAGE_COMDAT_SELECT_ANY: - sec_flags |= SEC_LINK_DUPLICATES_DISCARD; - break; + case IMAGE_COMDAT_SELECT_ANY: + sec_flags |= SEC_LINK_DUPLICATES_DISCARD; + break; - case IMAGE_COMDAT_SELECT_SAME_SIZE: - sec_flags |= SEC_LINK_DUPLICATES_SAME_SIZE; - break; + case IMAGE_COMDAT_SELECT_SAME_SIZE: + sec_flags |= SEC_LINK_DUPLICATES_SAME_SIZE; + break; - case IMAGE_COMDAT_SELECT_EXACT_MATCH: - /* Not yet fully implemented ??? */ - sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; - break; + case IMAGE_COMDAT_SELECT_EXACT_MATCH: + /* Not yet fully implemented ??? */ + sec_flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; + break; - /* debug$S gets this case; other - implications ??? */ + /* debug$S gets this case; other + implications ??? */ - /* There may be no symbol... we'll search - the whole table... Is this the right - place to play this game? Or should we do - it when reading it in. */ - case IMAGE_COMDAT_SELECT_ASSOCIATIVE: + /* There may be no symbol... we'll search + the whole table... Is this the right + place to play this game? Or should we do + it when reading it in. */ + case IMAGE_COMDAT_SELECT_ASSOCIATIVE: #ifdef STRICT_PE_FORMAT - /* FIXME: This is not currently implemented. */ - sec_flags |= SEC_LINK_DUPLICATES_DISCARD; + /* FIXME: This is not currently implemented. */ + sec_flags |= SEC_LINK_DUPLICATES_DISCARD; #else - sec_flags &= ~SEC_LINK_ONCE; + sec_flags &= ~SEC_LINK_ONCE; #endif - break; + break; - default: /* 0 means "no symbol" */ - /* debug$F gets this case; other - implications ??? */ - sec_flags |= SEC_LINK_DUPLICATES_DISCARD; - break; - } - } - break; + default: /* 0 means "no symbol" */ + /* debug$F gets this case; other + implications ??? */ + sec_flags |= SEC_LINK_DUPLICATES_DISCARD; + break; + } + } + break; - case 2: - /* Gas mode: the first matching on partial name. */ + case 2: + /* Gas mode: the first matching on partial name. */ #ifndef TARGET_UNDERSCORE #define TARGET_UNDERSCORE 0 #endif - /* Is this the name we're looking for? */ - if (strcmp (target_name, - symname + (TARGET_UNDERSCORE ? 1 : 0)) != 0) - { - /* Not the name we're looking for */ - esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd); - continue; - } - /* Fall through. */ - case 1: - /* MSVC mode: the lexically second symbol (or - drop through from the above). */ - { - char *newname; - - /* This must the the second symbol with the - section #. It is the actual symbol name. - Intel puts the two adjacent, but Alpha (at - least) spreads them out. */ - - section->comdat = - bfd_alloc (abfd, sizeof (struct bfd_comdat_info)); - if (section->comdat == NULL) - abort (); - section->comdat->symbol = - (esym - esymstart) / bfd_coff_symesz (abfd); - - newname = bfd_alloc (abfd, strlen (symname) + 1); - if (newname == NULL) - abort (); - - strcpy (newname, symname); - section->comdat->name = newname; - - } - - goto breakloop; - } + /* Is this the name we're looking for? */ + if (strcmp (target_name, + symname + (TARGET_UNDERSCORE ? 1 : 0)) != 0) + { + /* Not the name we're looking for */ + esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd); + continue; } + /* Fall through. */ + case 1: + /* MSVC mode: the lexically second symbol (or + drop through from the above). */ + { + char *newname; - esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd); + /* This must the the second symbol with the + section #. It is the actual symbol name. + Intel puts the two adjacent, but Alpha (at + least) spreads them out. */ + + section->comdat = + bfd_alloc (abfd, sizeof (struct bfd_comdat_info)); + if (section->comdat == NULL) + abort (); + + section->comdat->symbol = + (esym - esymstart) / bfd_coff_symesz (abfd); + + newname = bfd_alloc (abfd, strlen (symname) + 1); + if (newname == NULL) + abort (); + + strcpy (newname, symname); + section->comdat->name = newname; + } + + goto breakloop; } - breakloop: - /* SunOS requires a statement after any label. */ - ; } + + esym += (isym.n_numaux + 1) * bfd_coff_symesz (abfd); + } + + breakloop: + return sec_flags; +} + + +/* The PE version; see above for the general comments. + + Since to set the SEC_LINK_ONCE and associated flags, we have to + look at the symbol table anyway, we return the symbol table index + of the symbol being used as the COMDAT symbol. This is admittedly + ugly, but there's really nowhere else that we have access to the + required information. FIXME: Is the COMDAT symbol index used for + any purpose other than objdump? */ + +static flagword +styp_to_sec_flags (abfd, hdr, name, section) + bfd *abfd; + PTR hdr; + const char *name; + asection *section; +{ + struct internal_scnhdr *internal_s = (struct internal_scnhdr *) hdr; + long styp_flags = internal_s->s_flags; + flagword sec_flags; + + /* Assume read only unless IMAGE_SCN_MEM_WRITE is specified. */ + sec_flags = SEC_READONLY; + + /* Process each flag bit in styp_flags in turn. */ + while (styp_flags) + { + long flag = styp_flags & - styp_flags; + char * unhandled = NULL; + + styp_flags &= ~ flag; + + /* We infer from the distinct read/write/execute bits the settings + of some of the bfd flags; the actual values, should we need them, + are also in pei_section_data (abfd, section)->pe_flags. */ + + switch (flag) + { + case STYP_DSECT: + unhandled = "STYP_DSECT"; + break; + case STYP_GROUP: + unhandled = "STYP_GROUP"; + break; + case STYP_COPY: + unhandled = "STYP_COPY"; + break; + case STYP_OVER: + unhandled = "STYP_OVER"; + break; +#ifdef SEC_NEVER_LOAD + case STYP_NOLOAD: + sec_flags |= SEC_NEVER_LOAD; + break; +#endif + case IMAGE_SCN_MEM_READ: + /* Ignored, assume it always to be true. */ + break; + case IMAGE_SCN_TYPE_NO_PAD: + /* Skip. */ + break; + case IMAGE_SCN_LNK_OTHER: + unhandled = "IMAGE_SCN_LNK_OTHER"; + break; + case IMAGE_SCN_MEM_NOT_CACHED: + unhandled = "IMAGE_SCN_MEM_NOT_CACHED"; + break; + case IMAGE_SCN_MEM_NOT_PAGED: + unhandled = "IMAGE_SCN_MEM_NOT_PAGED"; + break; + case IMAGE_SCN_MEM_EXECUTE: + sec_flags |= SEC_CODE; + break; + case IMAGE_SCN_MEM_WRITE: + sec_flags &= ~ SEC_READONLY; + break; + case IMAGE_SCN_MEM_DISCARDABLE: + sec_flags |= SEC_DEBUGGING; + break; + case IMAGE_SCN_MEM_SHARED: + sec_flags |= SEC_SHARED; + break; + case IMAGE_SCN_LNK_REMOVE: + sec_flags |= SEC_EXCLUDE; + break; + case IMAGE_SCN_CNT_CODE: + sec_flags |= SEC_CODE | SEC_ALLOC | SEC_LOAD; + break; + case IMAGE_SCN_CNT_INITIALIZED_DATA: + sec_flags |= SEC_DATA | SEC_ALLOC | SEC_LOAD; + break; + case IMAGE_SCN_CNT_UNINITIALIZED_DATA: + sec_flags |= SEC_ALLOC; + break; + case IMAGE_SCN_LNK_INFO: + /* We mark these as SEC_DEBUGGING, but only if COFF_PAGE_SIZE is + defined. coff_compute_section_file_positions uses + COFF_PAGE_SIZE to ensure that the low order bits of the + section VMA and the file offset match. If we don't know + COFF_PAGE_SIZE, we can't ensure the correct correspondence, + and demand page loading of the file will fail. */ +#ifdef COFF_PAGE_SIZE + sec_flags |= SEC_DEBUGGING; +#endif + break; + case IMAGE_SCN_LNK_COMDAT: + /* COMDAT gets very special treatment. */ + sec_flags = handle_COMDAT (abfd, sec_flags, hdr, name, section); + break; + default: + /* Silently ignore for now. */ + break; + } + + /* If the section flag was not handled, report it here. This will allow + users of the BFD library to report a problem but continue executing. + Tools which need to be aware of these problems (such as the linker) + can override the default bfd_error_handler to intercept these reports. */ + if (unhandled != NULL) + (*_bfd_error_handler) + (_("%s (%s): Section flag %s (0x%x) ignored"), + bfd_get_filename (abfd), name, unhandled, flag); } #if defined (COFF_LONG_SECTION_NAMES) && defined (COFF_SUPPORT_GNU_LINKONCE) |