* PATCH: PR 797: Alignment in empty section changes the output layout @ 2005-03-24 11:45 H. J. Lu 2005-03-25 2:22 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-03-24 11:45 UTC (permalink / raw) To: binutils This patch tries to undo the damange caused by the unused output sections in linker script by removing them and resizing the remaining sections. H.J. ---- 2005-03-23 H.J. Lu <hongjiu.lu@intel.com> PR 797 * emultempl/elf32.em (gld${EMULATION_NAME}_finish): Remove the unused output sections without input sections and the empty unused output sections created by linker, if they don't have any contents. Resize sections. * ldlang.c (lang_output_section_statement_lookup_1): Set the ignored field to FALSE. (lang_size_sections_1): Skip an output section if it should be ignored. * ldlang.h (lang_output_section_statement_type): Add ignored. --- ld/emultempl/elf32.em.empty 2005-03-23 11:05:04.000000000 -0800 +++ ld/emultempl/elf32.em 2005-03-23 16:27:44.511115226 -0800 @@ -1472,20 +1472,76 @@ gld${EMULATION_NAME}_finish (void) if (!link_info.relocatable) { lang_output_section_statement_type *os; + asection *s, **p; + bfd_boolean resize = FALSE; + + /* We want to remove unused output sections and resize the + remaining sections so that any alignment changes caused by + those removed output sections are reverted. Possible unused + output sections are those without input sections or empty. + We can't remove all unused output sections without input + sections since they may be created by linker scripts. We can't + remove all empty unused output sections since they may have + empty input sections whose alignments may affect the memory + layout of output sections which we don't want to change. + + So we remove the unused output sections without input sections + and the empty unused output sections created by linker, if + they don't have any contents. */ for (os = &lang_output_section_statement.head->output_section_statement; os != NULL; os = os->next) { - asection *s; + if (os == abs_output_section || os->constraint == -1) + continue; + s = os->bfd_section; + if (s != NULL + && (s->linker_has_input == 0 + || (s->size == 0 + && (s->flags & SEC_LINKER_CREATED) != 0)) + && (s->flags & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0) + { + os->ignored = TRUE; + resize = TRUE; + + for (p = &output_bfd->sections; *p; p = &(*p)->next) + if (*p == s) + { + bfd_section_list_remove (output_bfd, p); + output_bfd->section_count--; + break; + } + } + } + + /* Resize to revert the changes from those removed sections. */ + if (resize) + { + lang_reset_memory_regions (); + + /* Resize the sections. */ + lang_size_sections (stat_ptr->head, abs_output_section, + &stat_ptr->head, 0, (bfd_vma) 0, + NULL, TRUE); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (stat_ptr->head, abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + } + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { if (os == abs_output_section || os->constraint == -1) continue; s = os->bfd_section; if (s != NULL && s->size == 0 && (s->flags & SEC_KEEP) == 0) { - asection **p; - for (p = &output_bfd->sections; *p; p = &(*p)->next) if (*p == s) { --- ld/ldlang.c.empty 2005-03-18 06:23:45.000000000 -0800 +++ ld/ldlang.c 2005-03-23 16:03:11.799216976 -0800 @@ -637,6 +637,7 @@ lang_output_section_statement_lookup_1 ( lookup->bfd_section = NULL; lookup->processed = 0; lookup->constraint = constraint; + lookup->ignored = FALSE; lookup->sectype = normal_section; lookup->addr_tree = NULL; lang_list_init (&lookup->children); @@ -3418,8 +3419,8 @@ lang_size_sections_1 lang_output_section_statement_type *os; os = &s->output_section_statement; - if (os->bfd_section == NULL) - /* This section was never actually created. */ + if (os->bfd_section == NULL || os->ignored) + /* This section was removed or never actually created. */ break; /* If this is a COFF shared library section, use the size and --- ld/ldlang.h.empty 2005-03-03 08:56:33.000000000 -0800 +++ ld/ldlang.h 2005-03-23 14:11:11.000000000 -0800 @@ -148,6 +148,7 @@ typedef struct lang_output_section_state int section_alignment; /* Alignment of start of section. */ int constraint; bfd_boolean all_input_readonly; + bfd_boolean ignored; union etree_union *load_base; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-03-24 11:45 PATCH: PR 797: Alignment in empty section changes the output layout H. J. Lu @ 2005-03-25 2:22 ` H. J. Lu 2005-03-29 4:21 ` Alan Modra 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-03-25 2:22 UTC (permalink / raw) To: binutils On Wed, Mar 23, 2005 at 04:36:53PM -0800, H. J. Lu wrote: > This patch tries to undo the damange caused by the unused output > sections in linker script by removing them and resizing the remaining > sections. > > > H.J. > ---- > 2005-03-23 H.J. Lu <hongjiu.lu@intel.com> > > PR 797 > * emultempl/elf32.em (gld${EMULATION_NAME}_finish): Remove > the unused output sections without input sections and the empty > unused output sections created by linker, if they don't have > any contents. Resize sections. > > * ldlang.c (lang_output_section_statement_lookup_1): Set the > ignored field to FALSE. > (lang_size_sections_1): Skip an output section if it should > be ignored. > > * ldlang.h (lang_output_section_statement_type): Add ignored. > I missed one place in lang_do_assignments_1. We need to skip the ignored output section when we assign values to symbols. Otherwise, their values will be incorrect. H.J. ---- 2005-03-24 H.J. Lu <hongjiu.lu@intel.com> PR 797 * emultempl/elf32.em (gld${EMULATION_NAME}_finish): Remove the unused output sections without input sections and the empty unused output sections created by linker, if they don't have any contents. Resize sections. * ldlang.c (lang_output_section_statement_lookup_1): Set the ignored field to FALSE. (lang_size_sections_1): Skip an output section if it should be ignored. (lang_do_assignments_1): Likewise. * ldlang.h (lang_output_section_statement_type): Add ignored. --- ld/emultempl/elf32.em.empty 2005-03-23 11:05:04.000000000 -0800 +++ ld/emultempl/elf32.em 2005-03-24 08:58:05.000000000 -0800 @@ -1472,20 +1472,76 @@ gld${EMULATION_NAME}_finish (void) if (!link_info.relocatable) { lang_output_section_statement_type *os; + asection *s, **p; + bfd_boolean resize = FALSE; + + /* We want to remove unused output sections and resize the + remaining sections so that any alignment changes caused by + those removed output sections are reverted. Possible unused + output sections are those without input sections or empty. + We can't remove all unused output sections without input + sections since they may be created by linker scripts. We can't + remove all empty unused output sections since they may have + empty input sections whose alignments may affect the memory + layout of output sections which we don't want to change. + + So we remove the unused output sections without input sections + and the empty unused output sections created by linker, if + they don't have any contents. */ for (os = &lang_output_section_statement.head->output_section_statement; os != NULL; os = os->next) { - asection *s; + if (os == abs_output_section || os->constraint == -1) + continue; + s = os->bfd_section; + if (s != NULL + && (s->linker_has_input == 0 + || (s->size == 0 + && (s->flags & SEC_LINKER_CREATED) != 0)) + && (s->flags & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0) + { + os->ignored = TRUE; + resize = TRUE; + + for (p = &output_bfd->sections; *p; p = &(*p)->next) + if (*p == s) + { + bfd_section_list_remove (output_bfd, p); + output_bfd->section_count--; + break; + } + } + } + + /* Resize to revert the changes from those removed sections. */ + if (resize) + { + lang_reset_memory_regions (); + + /* Resize the sections. */ + lang_size_sections (stat_ptr->head, abs_output_section, + &stat_ptr->head, 0, (bfd_vma) 0, + NULL, TRUE); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (stat_ptr->head, abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + } + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { if (os == abs_output_section || os->constraint == -1) continue; s = os->bfd_section; if (s != NULL && s->size == 0 && (s->flags & SEC_KEEP) == 0) { - asection **p; - for (p = &output_bfd->sections; *p; p = &(*p)->next) if (*p == s) { --- ld/ldlang.c.empty 2005-03-24 11:13:06.000000000 -0800 +++ ld/ldlang.c 2005-03-24 12:37:30.431168331 -0800 @@ -637,6 +637,7 @@ lang_output_section_statement_lookup_1 ( lookup->bfd_section = NULL; lookup->processed = 0; lookup->constraint = constraint; + lookup->ignored = FALSE; lookup->sectype = normal_section; lookup->addr_tree = NULL; lang_list_init (&lookup->children); @@ -3418,8 +3419,8 @@ lang_size_sections_1 lang_output_section_statement_type *os; os = &s->output_section_statement; - if (os->bfd_section == NULL) - /* This section was never actually created. */ + if (os->bfd_section == NULL || os->ignored) + /* This section was removed or never actually created. */ break; /* If this is a COFF shared library section, use the size and @@ -3914,7 +3915,7 @@ lang_do_assignments_1 lang_output_section_statement_type *os; os = &(s->output_section_statement); - if (os->bfd_section != NULL) + if (os->bfd_section != NULL && !os->ignored) { dot = os->bfd_section->vma; lang_do_assignments_1 (os->children.head, os, os->fill, dot); @@ -3928,7 +3929,7 @@ lang_do_assignments_1 { /* If nothing has been placed into the output section then it won't have a bfd_section. */ - if (os->bfd_section) + if (os->bfd_section && !os->ignored) { os->bfd_section->lma = exp_get_abs_int (os->load_base, 0, "load base", --- ld/ldlang.h.empty 2005-03-03 08:56:33.000000000 -0800 +++ ld/ldlang.h 2005-03-24 08:58:05.000000000 -0800 @@ -148,6 +148,7 @@ typedef struct lang_output_section_state int section_alignment; /* Alignment of start of section. */ int constraint; bfd_boolean all_input_readonly; + bfd_boolean ignored; union etree_union *load_base; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-03-25 2:22 ` H. J. Lu @ 2005-03-29 4:21 ` Alan Modra 2005-03-29 7:13 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: Alan Modra @ 2005-03-29 4:21 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils On Thu, Mar 24, 2005 at 02:05:56PM -0800, H. J. Lu wrote: > + So we remove the unused output sections without input sections > + and the empty unused output sections created by linker, if > + they don't have any contents. */ Is it possible to do this in strip_excluded_output_sections? You won't have sizes set at that stage, but linker_has_input will be set, as will SEC_HAS_CONTENTS from link script data statements. So I think most of what you're trying to achieve can be done there. SEC_LINKER_CREATED sections ought to be handled by the backend size_dynamic_sections function calling _bfd_strip_section_from_output. -- Alan Modra IBM OzLabs - Linux Technology Centre ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-03-29 4:21 ` Alan Modra @ 2005-03-29 7:13 ` H. J. Lu 2005-03-29 8:12 ` Alan Modra 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-03-29 7:13 UTC (permalink / raw) To: binutils On Tue, Mar 29, 2005 at 08:12:31AM +0930, Alan Modra wrote: > On Thu, Mar 24, 2005 at 02:05:56PM -0800, H. J. Lu wrote: > > + So we remove the unused output sections without input sections > > + and the empty unused output sections created by linker, if > > + they don't have any contents. */ > > Is it possible to do this in strip_excluded_output_sections? You won't > have sizes set at that stage, but linker_has_input will be set, as will > SEC_HAS_CONTENTS from link script data statements. So I think most of But SEC_KEEP may not be set before lang_mark_used_section. > what you're trying to achieve can be done there. SEC_LINKER_CREATED > sections ought to be handled by the backend size_dynamic_sections > function calling _bfd_strip_section_from_output. Or I can check every output section and call _bfd_strip_section_from_output at the end of bfd_elf_size_dynamic_sections so that I don't have to change every backend. But _bfd_strip_section_from_output will check every input section. It may be expensive. If I have to do it in gld${EMULATION_NAME}_finish for other sections anyway, why not to remove empty unused linker created sections in a same place. H.J. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-03-29 7:13 ` H. J. Lu @ 2005-03-29 8:12 ` Alan Modra 2005-03-30 16:30 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: Alan Modra @ 2005-03-29 8:12 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils On Mon, Mar 28, 2005 at 06:06:31PM -0800, H. J. Lu wrote: > On Tue, Mar 29, 2005 at 08:12:31AM +0930, Alan Modra wrote: > > On Thu, Mar 24, 2005 at 02:05:56PM -0800, H. J. Lu wrote: > > > + So we remove the unused output sections without input sections > > > + and the empty unused output sections created by linker, if > > > + they don't have any contents. */ > > > > Is it possible to do this in strip_excluded_output_sections? You won't > > have sizes set at that stage, but linker_has_input will be set, as will > > SEC_HAS_CONTENTS from link script data statements. So I think most of > > But SEC_KEEP may not be set before lang_mark_used_section. > > > what you're trying to achieve can be done there. SEC_LINKER_CREATED > > sections ought to be handled by the backend size_dynamic_sections > > function calling _bfd_strip_section_from_output. > > Or I can check every output section and call _bfd_strip_section_from_output > at the end of bfd_elf_size_dynamic_sections so that I don't have to > change every backend. No, I think that would be a bad idea. Most SEC_LINKER_CREATED sections are created by the backend code, so the backend code should manage them. Otherwise you run the risk of removing sections that some backend wants to keep. > But _bfd_strip_section_from_output will check > every input section. It may be expensive. Sure. Let's fix it. Perhaps by creating bfd_link_order lists earlier, after placing orphans. > If I have to do it in > gld${EMULATION_NAME}_finish for other sections anyway, why not > to remove empty unused linker created sections in a same place. I don't really like the idea of removing sections so late in the link process. It's a hack that I allowed because removing excess symbols and output sections was desirable, but now you're adding hacks upon hacks. As evidenced by the need for yet another section flag. The proper place to remove sections is after the backend size_dynamic_sections has run and before space for dynamic symbols is allocated. If you do it that way you'll avoid some unnecessary dynamic syms too. -- Alan Modra IBM OzLabs - Linux Technology Centre ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-03-29 8:12 ` Alan Modra @ 2005-03-30 16:30 ` H. J. Lu 0 siblings, 0 replies; 17+ messages in thread From: H. J. Lu @ 2005-03-30 16:30 UTC (permalink / raw) To: binutils On Tue, Mar 29, 2005 at 12:29:59PM +0930, Alan Modra wrote: > On Mon, Mar 28, 2005 at 06:06:31PM -0800, H. J. Lu wrote: > > On Tue, Mar 29, 2005 at 08:12:31AM +0930, Alan Modra wrote: > > > On Thu, Mar 24, 2005 at 02:05:56PM -0800, H. J. Lu wrote: > > > > + So we remove the unused output sections without input sections > > > > + and the empty unused output sections created by linker, if > > > > + they don't have any contents. */ > > > > > > Is it possible to do this in strip_excluded_output_sections? You won't > > > have sizes set at that stage, but linker_has_input will be set, as will > > > SEC_HAS_CONTENTS from link script data statements. So I think most of > > > > But SEC_KEEP may not be set before lang_mark_used_section. > > > > > what you're trying to achieve can be done there. SEC_LINKER_CREATED > > > sections ought to be handled by the backend size_dynamic_sections > > > function calling _bfd_strip_section_from_output. > > > > Or I can check every output section and call _bfd_strip_section_from_output > > at the end of bfd_elf_size_dynamic_sections so that I don't have to > > change every backend. > > No, I think that would be a bad idea. Most SEC_LINKER_CREATED sections > are created by the backend code, so the backend code should manage them. > Otherwise you run the risk of removing sections that some backend wants > to keep. > > > But _bfd_strip_section_from_output will check > > every input section. It may be expensive. > > Sure. Let's fix it. Perhaps by creating bfd_link_order lists earlier, > after placing orphans. > > > If I have to do it in > > gld${EMULATION_NAME}_finish for other sections anyway, why not > > to remove empty unused linker created sections in a same place. > > I don't really like the idea of removing sections so late in the link > process. It's a hack that I allowed because removing excess symbols and > output sections was desirable, but now you're adding hacks upon hacks. > As evidenced by the need for yet another section flag. > > The proper place to remove sections is after the backend > size_dynamic_sections has run and before space for dynamic symbols is > allocated. If you do it that way you'll avoid some unnecessary dynamic > syms too. > This is an updated patch. The new section flag is needed since I can't set bfd_section to NULL if it is ever created. H.J. --- bfd/ 2005-03-29 H.J. Lu <hongjiu.lu@intel.com> PR 797 * elf32-i386.c (elf_i386_size_dynamic_sections): Also remove empty sdynbss section. * elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise. ld/ 2005-03-29 H.J. Lu <hongjiu.lu@intel.com> PR 797 * ldlang.c (lang_output_section_statement_lookup_1): Set the ignored field to FALSE. (strip_excluded_output_sections): Renamed to ... (strip_excluded_or_unused_output_sections): This. Accept an argument to check for unused sections. (lang_size_sections_1): Skip an output section if it should be ignored. (lang_do_assignments_1): Likewise. (lang_process): Call strip_excluded_or_unused_output_sections to remove unused output sections after lang_mark_used_section. * ldlang.h (lang_output_section_statement_type): Change all_input_readonly to bitfield. Add ignored. --- binutils/bfd/elf32-i386.c.empty 2005-02-11 09:28:10.000000000 -0800 +++ binutils/bfd/elf32-i386.c 2005-03-29 12:13:09.000000000 -0800 @@ -1830,7 +1830,8 @@ elf_i386_size_dynamic_sections (bfd *out if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/bfd/elf64-x86-64.c.empty 2005-03-21 13:13:36.000000000 -0800 +++ binutils/bfd/elf64-x86-64.c 2005-03-29 12:13:09.000000000 -0800 @@ -1622,7 +1622,8 @@ elf64_x86_64_size_dynamic_sections (bfd if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/ld/ldlang.c.empty 2005-03-24 11:13:06.000000000 -0800 +++ binutils/ld/ldlang.c 2005-03-29 13:50:42.351403473 -0800 @@ -637,6 +637,7 @@ lang_output_section_statement_lookup_1 ( lookup->bfd_section = NULL; lookup->processed = 0; lookup->constraint = constraint; + lookup->ignored = FALSE; lookup->sectype = normal_section; lookup->addr_tree = NULL; lang_list_init (&lookup->children); @@ -2643,7 +2644,7 @@ map_input_to_output_sections sections if they turn out to be not needed. Clean them up here. */ static void -strip_excluded_output_sections (void) +strip_excluded_or_unused_output_sections (bfd_boolean unused) { lang_output_section_statement_type *os; @@ -2656,11 +2657,20 @@ strip_excluded_output_sections (void) if (os->constraint == -1) continue; s = os->bfd_section; - if (s != NULL && (s->flags & SEC_EXCLUDE) != 0) + if (s != NULL + && ((!unused && (s->flags & SEC_EXCLUDE) != 0) + || (unused + && s->linker_has_input == 0 + && (s->flags & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0))) { asection **p; - os->bfd_section = NULL; + /* We don't set bfd_section to NULL since bfd_section of + the used output section may still be used. */ + if (unused) + os->ignored = TRUE; + else + os->bfd_section = NULL; for (p = &output_bfd->sections; *p; p = &(*p)->next) if (*p == s) @@ -3418,8 +3428,8 @@ lang_size_sections_1 lang_output_section_statement_type *os; os = &s->output_section_statement; - if (os->bfd_section == NULL) - /* This section was never actually created. */ + if (os->bfd_section == NULL || os->ignored) + /* This section was removed or never actually created. */ break; /* If this is a COFF shared library section, use the size and @@ -3914,7 +3924,7 @@ lang_do_assignments_1 lang_output_section_statement_type *os; os = &(s->output_section_statement); - if (os->bfd_section != NULL) + if (os->bfd_section != NULL && !os->ignored) { dot = os->bfd_section->vma; lang_do_assignments_1 (os->children.head, os, os->fill, dot); @@ -3928,7 +3938,7 @@ lang_do_assignments_1 { /* If nothing has been placed into the output section then it won't have a bfd_section. */ - if (os->bfd_section) + if (os->bfd_section && !os->ignored) { os->bfd_section->lma = exp_get_abs_int (os->load_base, 0, "load base", @@ -4819,7 +4829,7 @@ lang_process (void) ldemul_before_allocation (); if (!link_info.relocatable) - strip_excluded_output_sections (); + strip_excluded_or_unused_output_sections (FALSE); /* We must record the program headers before we try to fix the section positions, since they will affect SIZEOF_HEADERS. */ @@ -4867,9 +4877,19 @@ lang_process (void) } } while (relax_again); + } + if (command_line.relax || !link_info.relocatable) + { /* Final extra sizing to report errors. */ lang_do_assignments (statement_list.head, abs_output_section, NULL, 0); + if (!link_info.relocatable) + { + lang_mark_used_section (); + /* Do it here so that the unused output_sections won't affect + memory layout. */ + strip_excluded_or_unused_output_sections (TRUE); + } lang_reset_memory_regions (); lang_size_sections (statement_list.head, abs_output_section, &statement_list.head, 0, 0, NULL, TRUE); @@ -4893,7 +4913,7 @@ lang_process (void) lang_check_section_addresses (); /* Final stuffs. */ - lang_mark_used_section (); + ldemul_finish (); lang_finish (); } --- binutils/ld/ldlang.h.empty 2005-03-03 08:56:33.000000000 -0800 +++ binutils/ld/ldlang.h 2005-03-29 12:13:09.000000000 -0800 @@ -147,7 +147,8 @@ typedef struct lang_output_section_state int subsection_alignment; /* Alignment of components. */ int section_alignment; /* Alignment of start of section. */ int constraint; - bfd_boolean all_input_readonly; + unsigned int all_input_readonly : 1; + unsigned int ignored : 1; union etree_union *load_base; ^ permalink raw reply [flat|nested] 17+ messages in thread
* PATCH: PR 797: Alignment in empty section changes the output layout @ 2005-05-04 19:53 H. J. Lu 2005-05-05 3:48 ` Alan Modra 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-05-04 19:53 UTC (permalink / raw) To: binutils The recent linker change makes this bug easier to fix. Here is an updated patch. H.J. --- bfd/ 2005-05-04 H.J. Lu <hongjiu.lu@intel.com> PR 797 * elf32-i386.c (elf_i386_size_dynamic_sections): Also remove empty sdynbss section. * elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise. ld/ 2005-05-04 H.J. Lu <hongjiu.lu@intel.com> PR 797 * ldlang.c (lang_output_section_statement_lookup_1): Set the ignored field to FALSE. (strip_unused_output_sections): New. (strip_excluded_or_unused_output_sections): This. Accept an argument to check for unused sections. (lang_size_sections_1): Skip an output section if it should be ignored. (lang_do_assignments_1): Likewise. (lang_process): Call strip_unused_output_sections to remove unused output sections after lang_mark_used_section. * ldlang.h (lang_output_section_statement_type): Change all_input_readonly to bitfield. Add ignored. --- binutils/bfd/elf32-i386.c.empty 2005-05-04 08:52:10.000000000 -0700 +++ binutils/bfd/elf32-i386.c 2005-05-04 10:08:02.000000000 -0700 @@ -1830,7 +1830,8 @@ elf_i386_size_dynamic_sections (bfd *out if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/bfd/elf64-x86-64.c.empty 2005-05-04 08:52:16.000000000 -0700 +++ binutils/bfd/elf64-x86-64.c 2005-05-04 10:08:02.000000000 -0700 @@ -1622,7 +1622,8 @@ elf64_x86_64_size_dynamic_sections (bfd if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/ld/ldlang.c.empty 2005-05-04 08:52:34.000000000 -0700 +++ binutils/ld/ldlang.c 2005-05-04 11:03:09.000000000 -0700 @@ -1022,6 +1022,7 @@ lang_output_section_statement_lookup_1 ( lookup->bfd_section = NULL; lookup->processed = 0; lookup->constraint = constraint; + lookup->ignored = FALSE; lookup->sectype = normal_section; lookup->addr_tree = NULL; lang_list_init (&lookup->children); @@ -3084,6 +3085,41 @@ strip_excluded_output_sections (void) stripped_excluded_sections = TRUE; } +/* An output section might have been removed after its statement was + added if it isn't used at all. Clean them up here. */ + +static void +strip_unused_output_sections (void) +{ + lang_output_section_statement_type *os; + + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { + asection *s; + + if (os->constraint == -1) + continue; + + s = os->bfd_section; + + if (s != NULL + && s->linker_has_input == 0 + && (s->flags & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0) + { + /* We don't set bfd_section to NULL since bfd_section of the + removed output section statement may still be used. */ + os->ignored = TRUE; + if (!bfd_section_removed_from_list (output_bfd, s)) + { + bfd_section_list_remove (output_bfd, s); + output_bfd->section_count--; + } + } + } +} + static void print_output_section_statement (lang_output_section_statement_type *output_section_statement) @@ -3855,8 +3891,8 @@ lang_size_sections_1 lang_output_section_statement_type *os; os = &s->output_section_statement; - if (os->bfd_section == NULL) - /* This section was never actually created. */ + if (os->bfd_section == NULL || os->ignored) + /* This section was removed or never actually created. */ break; /* If this is a COFF shared library section, use the size and @@ -4351,7 +4387,7 @@ lang_do_assignments_1 lang_output_section_statement_type *os; os = &(s->output_section_statement); - if (os->bfd_section != NULL) + if (os->bfd_section != NULL && !os->ignored) { dot = os->bfd_section->vma; lang_do_assignments_1 (os->children.head, os, os->fill, dot); @@ -4365,7 +4401,7 @@ lang_do_assignments_1 { /* If nothing has been placed into the output section then it won't have a bfd_section. */ - if (os->bfd_section) + if (os->bfd_section && !os->ignored) { os->bfd_section->lma = exp_get_abs_int (os->load_base, 0, "load base", @@ -5301,9 +5337,19 @@ lang_process (void) } } while (relax_again); + } + if (command_line.relax || !link_info.relocatable) + { /* Final extra sizing to report errors. */ lang_do_assignments (statement_list.head, abs_output_section, NULL, 0); + if (!link_info.relocatable) + { + lang_mark_used_section (); + /* Do it here so that the unused output_sections won't affect + memory layout. */ + strip_unused_output_sections (); + } lang_reset_memory_regions (); lang_size_sections (statement_list.head, abs_output_section, &statement_list.head, 0, 0, NULL, TRUE); @@ -5327,7 +5373,7 @@ lang_process (void) lang_check_section_addresses (); /* Final stuffs. */ - lang_mark_used_section (); + ldemul_finish (); lang_finish (); } --- binutils/ld/ldlang.h.empty 2005-05-04 08:52:34.000000000 -0700 +++ binutils/ld/ldlang.h 2005-05-04 10:36:53.000000000 -0700 @@ -147,7 +147,8 @@ typedef struct lang_output_section_state int subsection_alignment; /* Alignment of components. */ int section_alignment; /* Alignment of start of section. */ int constraint; - bfd_boolean all_input_readonly; + unsigned int all_input_readonly : 1; + unsigned int ignored : 1; union etree_union *load_base; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-04 19:53 H. J. Lu @ 2005-05-05 3:48 ` Alan Modra 2005-05-05 4:52 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: Alan Modra @ 2005-05-05 3:48 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils On Wed, May 04, 2005 at 11:09:41AM -0700, H. J. Lu wrote: > + if (command_line.relax || !link_info.relocatable) > + { > /* Final extra sizing to report errors. */ > lang_do_assignments (statement_list.head, abs_output_section, NULL, 0); > + if (!link_info.relocatable) > + { > + lang_mark_used_section (); > + /* Do it here so that the unused output_sections won't affect > + memory layout. */ > + strip_unused_output_sections (); > + } Can you please look at merging lang_mark_used_section and strip_unused_output_sections into strip_excluded_output_sections? I think it should be possible if you call lang_do_assignments before bfd_gc_sections to ensure that linker script symbols defined inside output sections are in the hash table. -- Alan Modra IBM OzLabs - Linux Technology Centre ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-05 3:48 ` Alan Modra @ 2005-05-05 4:52 ` H. J. Lu 2005-05-05 5:35 ` Alan Modra 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-05-05 4:52 UTC (permalink / raw) To: binutils On Thu, May 05, 2005 at 12:07:17PM +0930, Alan Modra wrote: > On Wed, May 04, 2005 at 11:09:41AM -0700, H. J. Lu wrote: > > + if (command_line.relax || !link_info.relocatable) > > + { > > /* Final extra sizing to report errors. */ > > lang_do_assignments (statement_list.head, abs_output_section, NULL, 0); > > + if (!link_info.relocatable) > > + { > > + lang_mark_used_section (); > > + /* Do it here so that the unused output_sections won't affect > > + memory layout. */ > > + strip_unused_output_sections (); > > + } > > Can you please look at merging lang_mark_used_section and > strip_unused_output_sections into strip_excluded_output_sections? > > I think it should be possible if you call lang_do_assignments before > bfd_gc_sections to ensure that linker script symbols defined inside > output sections are in the hash table. I am not sure it will work since the order is quite important. I got many /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: tmpdir/ld1: Not enough room for program headers (allocated 2, need 4) /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link failed: Bad value H.J. H.J. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-05 4:52 ` H. J. Lu @ 2005-05-05 5:35 ` Alan Modra 2005-05-05 5:56 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: Alan Modra @ 2005-05-05 5:35 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils On Wed, May 04, 2005 at 09:48:17PM -0700, H. J. Lu wrote: > On Thu, May 05, 2005 at 12:07:17PM +0930, Alan Modra wrote: > > Can you please look at merging lang_mark_used_section and > > strip_unused_output_sections into strip_excluded_output_sections? > > > > I think it should be possible if you call lang_do_assignments before > > bfd_gc_sections to ensure that linker script symbols defined inside > > output sections are in the hash table. > > I am not sure it will work since the order is quite important. I > got many > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: > tmpdir/ld1: Not enough room for program headers (allocated 2, need 4) > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link > failed: Bad value Did you find that you needed to run lang_size_sections early as well? If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to be undone. -- Alan Modra IBM OzLabs - Linux Technology Centre ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-05 5:35 ` Alan Modra @ 2005-05-05 5:56 ` H. J. Lu 2005-05-05 6:33 ` Alan Modra 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-05-05 5:56 UTC (permalink / raw) To: binutils On Thu, May 05, 2005 at 02:44:56PM +0930, Alan Modra wrote: > On Wed, May 04, 2005 at 09:48:17PM -0700, H. J. Lu wrote: > > On Thu, May 05, 2005 at 12:07:17PM +0930, Alan Modra wrote: > > > Can you please look at merging lang_mark_used_section and > > > strip_unused_output_sections into strip_excluded_output_sections? > > > > > > I think it should be possible if you call lang_do_assignments before > > > bfd_gc_sections to ensure that linker script symbols defined inside > > > output sections are in the hash table. > > > > I am not sure it will work since the order is quite important. I > > got many > > > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: > > tmpdir/ld1: Not enough room for program headers (allocated 2, need 4) > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link > > failed: Bad value > > Did you find that you needed to run lang_size_sections early as well? > If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to > be undone. Same problem. ldemul_before_allocation is called after map_input_to_output_sections. I guess it is hard to call lang_do_assignments before it. Besides, it makes lang_process even more complicated. H.J. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-05 5:56 ` H. J. Lu @ 2005-05-05 6:33 ` Alan Modra 2005-05-05 16:12 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: Alan Modra @ 2005-05-05 6:33 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils On Wed, May 04, 2005 at 10:35:44PM -0700, H. J. Lu wrote: > On Thu, May 05, 2005 at 02:44:56PM +0930, Alan Modra wrote: > > On Wed, May 04, 2005 at 09:48:17PM -0700, H. J. Lu wrote: > > > On Thu, May 05, 2005 at 12:07:17PM +0930, Alan Modra wrote: > > > > Can you please look at merging lang_mark_used_section and > > > > strip_unused_output_sections into strip_excluded_output_sections? > > > > > > > > I think it should be possible if you call lang_do_assignments before > > > > bfd_gc_sections to ensure that linker script symbols defined inside > > > > output sections are in the hash table. > > > > > > I am not sure it will work since the order is quite important. I > > > got many > > > > > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: > > > tmpdir/ld1: Not enough room for program headers (allocated 2, need 4) > > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link > > > failed: Bad value > > > > Did you find that you needed to run lang_size_sections early as well? > > If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to > > be undone. > > Same problem. ldemul_before_allocation is called after > map_input_to_output_sections. I guess it is hard to call > lang_do_assignments before it. Besides, it makes lang_process even > more complicated. I meant for you to call lang_do_assignments, bfd_gc_sections and strip_unused_output_sections from strip_excluded_output_sections. Is that what you're doing? -- Alan Modra IBM OzLabs - Linux Technology Centre ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-05 6:33 ` Alan Modra @ 2005-05-05 16:12 ` H. J. Lu 2005-05-06 6:20 ` Alan Modra 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-05-05 16:12 UTC (permalink / raw) To: binutils On Thu, May 05, 2005 at 03:26:16PM +0930, Alan Modra wrote: > On Wed, May 04, 2005 at 10:35:44PM -0700, H. J. Lu wrote: > > On Thu, May 05, 2005 at 02:44:56PM +0930, Alan Modra wrote: > > > On Wed, May 04, 2005 at 09:48:17PM -0700, H. J. Lu wrote: > > > > On Thu, May 05, 2005 at 12:07:17PM +0930, Alan Modra wrote: > > > > > Can you please look at merging lang_mark_used_section and > > > > > strip_unused_output_sections into strip_excluded_output_sections? > > > > > > > > > > I think it should be possible if you call lang_do_assignments before > > > > > bfd_gc_sections to ensure that linker script symbols defined inside > > > > > output sections are in the hash table. > > > > > > > > I am not sure it will work since the order is quite important. I > > > > got many > > > > > > > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: > > > > tmpdir/ld1: Not enough room for program headers (allocated 2, need 4) > > > > /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link > > > > failed: Bad value > > > > > > Did you find that you needed to run lang_size_sections early as well? > > > If so, see emultempl/ppc64elf.em:ppc_before_allocation for what needs to > > > be undone. > > > > Same problem. ldemul_before_allocation is called after > > map_input_to_output_sections. I guess it is hard to call > > lang_do_assignments before it. Besides, it makes lang_process even > > more complicated. > > I meant for you to call lang_do_assignments, bfd_gc_sections and > strip_unused_output_sections from strip_excluded_output_sections. Is > that what you're doing? > With lang_size_sections (statement_list.head, abs_output_section, &statement_list.head, 0, 0, NULL, command_line.relax ? FALSE : TRUE); lang_do_assignments (statement_list.head, abs_output_section, NULL, 0); lang_reset_memory_regions (); lang_mark_used_section (); strip_unused_output_sections (); at the end of strip_excluded_output_sections, I got Running /export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs.exp ... /export/build/gnu/binutils-debug/build-i686-linux/ld/../gas/as-new -o tmpdir/phdrs.o /export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs.s /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new -o tmpdir/phdrs -T /export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs.t tmpdir/phdrs.o/export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: tmpdir/phdrs: Not enough room for program headers (allocated 2, need 3) /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new: final link failed: Bad value FAIL: PHDRS and Running /export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs2.exp .../export/build/gnu/binutils-debug/build-i686-linux/ld/../gas/as-new -o tmpdir/phdrs2.o /export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs2.s /export/build/gnu/binutils-debug/build-i686-linux/ld/ld-new -o tmpdir/phdrs2 -T /export/gnu/src/binutils/binutils/ld/testsuite/ld-scripts/phdrs2.t tmpdir/phdrs2.o /export/build/gnu/binutils-debug/build-i686-linux/ld/../binutils/objdump --private tmpdir/phdrs2 tmpdir/phdrs2: file format elf32-i386 Program Header: LOAD off 0x00001000 vaddr 0x00800000 paddr 0x00800000 align 2**12 filesz 0x00000004 memsz 0x00000004 flags r-x LOAD off 0x00001000 vaddr 0x00000000 paddr 0x00000000 align 2**12 filesz 0x0080000c memsz 0x0080000c flags rw- FAIL: PHDRS2 H.J. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-05 16:12 ` H. J. Lu @ 2005-05-06 6:20 ` Alan Modra 2005-05-07 19:16 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: Alan Modra @ 2005-05-06 6:20 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils On Thu, May 05, 2005 at 09:02:23AM -0700, H. J. Lu wrote: > With > > lang_size_sections (statement_list.head, abs_output_section, > &statement_list.head, 0, 0, NULL, > command_line.relax ? FALSE : TRUE); > lang_do_assignments (statement_list.head, abs_output_section, NULL, > 0); > lang_reset_memory_regions (); > lang_mark_used_section (); > strip_unused_output_sections (); > > at the end of strip_excluded_output_sections, I got > failed: Bad value FAIL: PHDRS > FAIL: PHDRS2 You need this from ppc64elf.em. /* We must not cache anything from the preliminary sizing. */ elf_tdata (output_bfd)->program_header_size = 0; Perhaps a better approach would be to run a cut-down lang_do_assignments that just keeps track of output section and symbol assignments other than "." within output sections. If it finds such an assignment, mark the section as needed. -- Alan Modra IBM OzLabs - Linux Technology Centre ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-06 6:20 ` Alan Modra @ 2005-05-07 19:16 ` H. J. Lu 2005-05-07 20:08 ` H. J. Lu 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-05-07 19:16 UTC (permalink / raw) To: binutils On Fri, May 06, 2005 at 03:47:17PM +0930, Alan Modra wrote: > On Thu, May 05, 2005 at 09:02:23AM -0700, H. J. Lu wrote: > > With > > > > lang_size_sections (statement_list.head, abs_output_section, > > &statement_list.head, 0, 0, NULL, > > command_line.relax ? FALSE : TRUE); > > lang_do_assignments (statement_list.head, abs_output_section, NULL, > > 0); > > lang_reset_memory_regions (); > > lang_mark_used_section (); > > strip_unused_output_sections (); > > > > at the end of strip_excluded_output_sections, I got > > failed: Bad value FAIL: PHDRS > > FAIL: PHDRS2 > > You need this from ppc64elf.em. > > /* We must not cache anything from the preliminary sizing. */ > elf_tdata (output_bfd)->program_header_size = 0; > > Perhaps a better approach would be to run a cut-down lang_do_assignments > that just keeps track of output section and symbol assignments other > than "." within output sections. If it finds such an assignment, mark > the section as needed. > This patch implements it. H.J. ----- bfd/ 2005-05-07 H.J. Lu <hongjiu.lu@intel.com> PR 797 * elf32-i386.c (elf_i386_size_dynamic_sections): Also remove empty sdynbss section. * elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise. ld/ 2005-05-07 H.J. Lu <hongjiu.lu@intel.com> PR 797 * ldexp.c (exp_fold_tree_1): Renamed from exp_fold_tree and take take a bfd_boolean, mark_used. Skip etree_assert if mark_used is TRUE. (exp_fold_tree) Call exp_fold_tree_1 with mark_used == FALSE. (exp_fold_tree_no_dot): Updated to take a bfd_boolean, mark_used and pass down. (fold_unary): Likewise. (fold_binary): Likewise. (fold_trinary): Likewise. (exp_binop): Add FALSE to call to exp_fold_tree_no_dot. (exp_trinop): Likewise. (exp_unop): Likewise. (exp_nameop): Likewise. (exp_get_vma): Likewise. (exp_get_fill): Likewise. (exp_get_abs_int): Likewise. (fold_name): Likewise. Set SEC_KEEP in output section flags. (exp_mark_used_section): New. * ldexp.h (exp_mark_used_section): New. * ldlang.c (lang_output_section_statement_lookup_1): Set the ignored field to FALSE. (lang_mark_used_section_1): New. (lang_mark_used_section): Call lang_mark_used_section_1. (strip_excluded_output_sections): Call lang_mark_used_section and check for unused sections. (lang_size_sections_1): Skip an output section if it should be ignored. (lang_do_assignments_1): Likewise. (lang_process): Don't call lang_mark_used_section here. * ldlang.h (lang_output_section_statement_type): Change all_input_readonly to bitfield. Add ignored. --- binutils/bfd/elf32-i386.c.empty 2005-05-05 07:44:37.000000000 -0700 +++ binutils/bfd/elf32-i386.c 2005-05-07 06:58:49.000000000 -0700 @@ -1914,7 +1914,8 @@ elf_i386_size_dynamic_sections (bfd *out if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/bfd/elf64-x86-64.c.empty 2005-05-05 07:44:41.000000000 -0700 +++ binutils/bfd/elf64-x86-64.c 2005-05-07 06:58:49.000000000 -0700 @@ -1624,7 +1624,8 @@ elf64_x86_64_size_dynamic_sections (bfd if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/ld/ldexp.c.empty 2005-03-15 09:35:19.000000000 -0800 +++ binutils/ld/ldexp.c 2005-05-07 09:54:41.000000000 -0700 @@ -41,8 +41,12 @@ #include "libiberty.h" #include "safe-ctype.h" +static etree_value_type exp_fold_tree_1 + (etree_type *, lang_output_section_statement_type *, + lang_phase_type, bfd_vma, bfd_vma *, bfd_boolean); static etree_value_type exp_fold_tree_no_dot - (etree_type *, lang_output_section_statement_type *, lang_phase_type); + (etree_type *, lang_output_section_statement_type *, lang_phase_type, + bfd_boolean); static bfd_vma align_n (bfd_vma, bfd_vma); @@ -219,13 +223,14 @@ fold_unary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->unary.child, - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->unary.child, + current_section, + allocation_done, dot, dotp, mark_used); if (result.valid_p) { switch (tree->type.node_code) @@ -308,12 +313,13 @@ fold_binary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->binary.lhs, current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->binary.lhs, current_section, + allocation_done, dot, dotp, mark_used); /* The SEGMENT_START operator is special because its first operand is a string, not the name of a symbol. */ @@ -338,9 +344,10 @@ fold_binary (etree_type *tree, { etree_value_type other; - other = exp_fold_tree (tree->binary.rhs, - current_section, - allocation_done, dot, dotp); + other = exp_fold_tree_1 (tree->binary.rhs, + current_section, + allocation_done, + dot, dotp, mark_used); if (other.valid_p) { /* If the values are from different sections, or this is an @@ -498,18 +505,20 @@ fold_trinary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->trinary.cond, current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->trinary.cond, current_section, + allocation_done, dot, dotp, mark_used); if (result.valid_p) - result = exp_fold_tree ((result.value - ? tree->trinary.lhs - : tree->trinary.rhs), - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 ((result.value + ? tree->trinary.lhs + : tree->trinary.rhs), + current_section, + allocation_done, + dot, dotp, mark_used); return result; } @@ -518,7 +527,8 @@ static etree_value_type fold_name (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, - bfd_vma dot) + bfd_vma dot, + bfd_boolean mark_used) { etree_value_type result; @@ -596,6 +606,7 @@ fold_name (etree_type *tree, + h->u.def.section->output_offset), NULL, os); + os->bfd_section->flags |= SEC_KEEP; } } } @@ -619,8 +630,12 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed > 0) - result = new_rel (0, NULL, os); + if (os) + { + os->bfd_section->flags |= SEC_KEEP; + if (os->processed > 0) + result = new_rel (0, NULL, os); + } } break; @@ -630,14 +645,19 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed != 0) + if (os) { - if (os->load_base == NULL) - result = new_rel (0, NULL, os); - else - result = exp_fold_tree_no_dot (os->load_base, - abs_output_section, - allocation_done); + os->bfd_section->flags |= SEC_KEEP; + if (os->processed != 0) + { + if (os->load_base == NULL) + result = new_rel (0, NULL, os); + else + result = exp_fold_tree_no_dot (os->load_base, + abs_output_section, + allocation_done, + mark_used); + } } } break; @@ -649,8 +669,12 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed > 0) - result = new_abs (os->bfd_section->size / opb); + if (os) + { + os->bfd_section->flags |= SEC_KEEP; + if (os->processed > 0) + result = new_abs (os->bfd_section->size / opb); + } } break; @@ -688,12 +712,13 @@ fold_name (etree_type *tree, return result; } -etree_value_type -exp_fold_tree (etree_type *tree, - lang_output_section_statement_type *current_section, - lang_phase_type allocation_done, - bfd_vma dot, - bfd_vma *dotp) +static etree_value_type +exp_fold_tree_1 (etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; @@ -721,26 +746,32 @@ exp_fold_tree (etree_type *tree, break; case etree_assert: - result = exp_fold_tree (tree->assert_s.child, - current_section, - allocation_done, dot, dotp); - if (result.valid_p && !result.value) - einfo ("%X%P: %s\n", tree->assert_s.message); + if (!mark_used) + { + result = exp_fold_tree_1 (tree->assert_s.child, + current_section, + allocation_done, dot, dotp, + mark_used); + if (result.valid_p && !result.value) + einfo ("%X%P: %s\n", tree->assert_s.message); + } + else + memset (&result, 0, sizeof (result)); break; case etree_unary: result = fold_unary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_binary: result = fold_binary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_trinary: result = fold_trinary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_assign: @@ -757,9 +788,10 @@ exp_fold_tree (etree_type *tree, { /* Notify the folder that this is an assignment to dot. */ assigning_to_dot = TRUE; - result = exp_fold_tree (tree->assign.src, - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->assign.src, + current_section, + allocation_done, + dot, dotp, mark_used); assigning_to_dot = FALSE; if (! result.valid_p) @@ -788,9 +820,9 @@ exp_fold_tree (etree_type *tree, } else { - result = exp_fold_tree (tree->assign.src, - current_section, allocation_done, - dot, dotp); + result = exp_fold_tree_1 (tree->assign.src, + current_section, allocation_done, + dot, dotp, mark_used); if (result.valid_p) { bfd_boolean create; @@ -832,7 +864,8 @@ exp_fold_tree (etree_type *tree, break; case etree_name: - result = fold_name (tree, current_section, allocation_done, dot); + result = fold_name (tree, current_section, allocation_done, dot, + mark_used); break; default: @@ -844,12 +877,25 @@ exp_fold_tree (etree_type *tree, return result; } +etree_value_type +exp_fold_tree (etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, + bfd_vma *dotp) +{ + return exp_fold_tree_1 (tree, current_section, allocation_done, + dot, dotp, FALSE); +} + static etree_value_type exp_fold_tree_no_dot (etree_type *tree, lang_output_section_statement_type *current_section, - lang_phase_type allocation_done) + lang_phase_type allocation_done, + bfd_boolean mark_used) { - return exp_fold_tree (tree, current_section, allocation_done, 0, NULL); + return exp_fold_tree_1 (tree, current_section, allocation_done, 0, + NULL, mark_used); } etree_type * @@ -864,7 +910,7 @@ exp_binop (int code, etree_type *lhs, et value.type.node_class = etree_binary; r = exp_fold_tree_no_dot (&value, abs_output_section, - lang_first_phase_enum); + lang_first_phase_enum, FALSE); if (r.valid_p) { return exp_intop (r.value); @@ -884,7 +930,7 @@ exp_trinop (int code, etree_type *cond, value.trinary.cond = cond; value.trinary.rhs = rhs; value.type.node_class = etree_trinary; - r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum); + r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -903,7 +949,7 @@ exp_unop (int code, etree_type *child) value.unary.child = child; value.unary.type.node_class = etree_unary; r = exp_fold_tree_no_dot (&value, abs_output_section, - lang_first_phase_enum); + lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -921,7 +967,7 @@ exp_nameop (int code, const char *name) value.name.name = name; value.name.type.node_class = etree_name; - r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum); + r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -1071,7 +1117,8 @@ exp_get_vma (etree_type *tree, if (tree != NULL) { - r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + r = exp_fold_tree_no_dot (tree, abs_output_section, + allocation_done, FALSE); if (! r.valid_p && name != NULL) einfo (_("%F%S nonconstant expression for %s\n"), name); return r.value; @@ -1103,7 +1150,8 @@ exp_get_fill (etree_type *tree, if (tree == NULL) return def; - r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done, + FALSE); if (! r.valid_p && name != NULL) einfo (_("%F%S nonconstant expression for %s\n"), name); @@ -1154,7 +1202,8 @@ exp_get_abs_int (etree_type *tree, lang_phase_type allocation_done) { etree_value_type res; - res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done, + FALSE); if (res.valid_p) res.value += res.section->bfd_section->vma; @@ -1173,3 +1222,91 @@ align_n (bfd_vma value, bfd_vma align) value = (value + align - 1) / align; return value * align; } + +void +exp_mark_used_section + (etree_type *tree, + lang_output_section_statement_type *current_section) +{ + switch (tree->type.node_class) + { + case etree_value: + break; + + case etree_rel: + break; + + case etree_assert: + break; + + case etree_unary: + break; + + case etree_binary: + break; + + case etree_trinary: + break; + + case etree_assign: + case etree_provide: + case etree_provided: + if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0) + { + etree_value_type result; + bfd_vma dot = 0; + + result = exp_fold_tree_1 (tree->assign.src, + current_section, + lang_allocating_phase_enum, + dot, &dot, TRUE); + if (result.valid_p) + { + bfd_boolean create; + struct bfd_link_hash_entry *h; + + if (tree->type.node_class == etree_assign) + create = TRUE; + else + create = FALSE; + h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, + create, FALSE, TRUE); + if (h == NULL) + { + if (create) + einfo (_("%P%F:%s: hash creation failed\n"), + tree->assign.dst); + } + else if (tree->type.node_class == etree_provide + && h->type != bfd_link_hash_new + && h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Do nothing. The symbol was defined by some + object. */ + } + else + { + /* FIXME: Should we worry if the symbol is already + defined? */ + lang_update_definedness (tree->assign.dst, h); + h->type = bfd_link_hash_defined; + h->u.def.value = result.value; + h->u.def.section = result.section->bfd_section; + if (tree->type.node_class == etree_provide) + tree->type.node_class = etree_provided; + } + } + } + break; + + case etree_name: + fold_name (tree, current_section, lang_allocating_phase_enum, 0, + TRUE); + break; + + default: + abort (); + break; + } +} --- binutils/ld/ldexp.h.empty 2004-12-22 09:30:57.000000000 -0800 +++ binutils/ld/ldexp.h 2005-05-07 09:34:05.000000000 -0700 @@ -156,5 +156,7 @@ fill_type *exp_get_fill (etree_type *, fill_type *, char *, lang_phase_type); bfd_vma exp_get_abs_int (etree_type *, int, char *, lang_phase_type); +void exp_mark_used_section + (etree_type *, struct lang_output_section_statement_struct *); #endif --- binutils/ld/ldlang.c.empty 2005-05-07 06:58:49.000000000 -0700 +++ binutils/ld/ldlang.c 2005-05-07 10:13:04.000000000 -0700 @@ -1083,6 +1083,7 @@ lang_output_section_statement_lookup_1 ( lookup->bfd_section = NULL; lookup->processed = 0; lookup->constraint = constraint; + lookup->ignored = FALSE; lookup->sectype = normal_section; lookup->addr_tree = NULL; lang_list_init (&lookup->children); @@ -3109,6 +3110,90 @@ map_input_to_output_sections } } +/* Worker function for lang_mark_used_section. Recursiveness goes + here. */ + +static void +lang_mark_used_section_1 + (lang_statement_union_type *s, + lang_output_section_statement_type *output_section_statement) +{ + for (; s != NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_constructors_statement_enum: + break; + + case lang_output_section_statement_enum: + { + lang_output_section_statement_type *os; + + os = &(s->output_section_statement); + if (os->bfd_section != NULL) + lang_mark_used_section_1 (os->children.head, os); + } + break; + case lang_wild_statement_enum: + lang_mark_used_section_1 (s->wild_statement.children.head, + output_section_statement); + + break; + + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + break; + case lang_data_statement_enum: + exp_mark_used_section (s->data_statement.exp, + abs_output_section); + break; + + case lang_reloc_statement_enum: + break; + + case lang_input_section_enum: + break; + + case lang_input_statement_enum: + break; + case lang_fill_statement_enum: + break; + case lang_assignment_statement_enum: + exp_mark_used_section (s->assignment_statement.exp, + output_section_statement); + break; + case lang_padding_statement_enum: + break; + + case lang_group_statement_enum: + lang_mark_used_section_1 (s->group_statement.children.head, + output_section_statement); + break; + + default: + FAIL (); + break; + case lang_address_statement_enum: + break; + } + } +} + +static void +lang_mark_used_section (void) +{ + unsigned int gc_sections = link_info.gc_sections; + + /* Callers of exp_fold_tree need to increment this. */ + lang_statement_iteration++; + lang_mark_used_section_1 (statement_list.head, abs_output_section); + + link_info.gc_sections = 0; + bfd_gc_sections (output_bfd, &link_info); + link_info.gc_sections = gc_sections; +} + /* An output section might have been removed after its statement was added. For example, ldemul_before_allocation can remove dynamic sections if they turn out to be not needed. Clean them up here. */ @@ -3118,32 +3203,54 @@ strip_excluded_output_sections (void) { lang_output_section_statement_type *os; + lang_mark_used_section (); + for (os = &lang_output_section_statement.head->output_section_statement; os != NULL; os = os->next) { - asection *s; + asection *output_section; + bfd_boolean exclude; if (os->constraint == -1) continue; - if (os->bfd_section == NULL || os->bfd_section->map_head.s == NULL) + output_section = os->bfd_section; + if (output_section == NULL) continue; - for (s = os->bfd_section->map_head.s; s != NULL; s = s->map_head.s) - if ((s->flags & SEC_EXCLUDE) == 0) - break; + exclude = FALSE; + if (output_section->map_head.s != NULL) + { + asection *s; - os->bfd_section->map_head.link_order = NULL; - os->bfd_section->map_tail.link_order = NULL; + for (s = output_section->map_head.s; s != NULL; + s = s->map_head.s) + if ((s->flags & SEC_EXCLUDE) == 0) + break; + + output_section->map_head.link_order = NULL; + output_section->map_tail.link_order = NULL; + + if (s == NULL) + exclude = TRUE; + } - if (s == NULL) + if (exclude + || (output_section->linker_has_input == 0 + && ((output_section->flags + & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0))) { - s = os->bfd_section; - os->bfd_section = NULL; - if (!bfd_section_removed_from_list (output_bfd, s)) + if (exclude) + os->bfd_section = NULL; + else + /* We don't set bfd_section to NULL since bfd_section of the + * removed output section statement may still be used. */ + os->ignored = TRUE; + if (!bfd_section_removed_from_list (output_bfd, + output_section)) { - bfd_section_list_remove (output_bfd, s); + bfd_section_list_remove (output_bfd, output_section); output_bfd->section_count--; } } @@ -3925,8 +4032,8 @@ lang_size_sections_1 lang_output_section_statement_type *os; os = &s->output_section_statement; - if (os->bfd_section == NULL) - /* This section was never actually created. */ + if (os->bfd_section == NULL || os->ignored) + /* This section was removed or never actually created. */ break; /* If this is a COFF shared library section, use the size and @@ -4421,7 +4528,7 @@ lang_do_assignments_1 lang_output_section_statement_type *os; os = &(s->output_section_statement); - if (os->bfd_section != NULL) + if (os->bfd_section != NULL && !os->ignored) { dot = os->bfd_section->vma; lang_do_assignments_1 (os->children.head, os, os->fill, dot); @@ -4435,7 +4542,7 @@ lang_do_assignments_1 { /* If nothing has been placed into the output section then it won't have a bfd_section. */ - if (os->bfd_section) + if (os->bfd_section && !os->ignored) { os->bfd_section->lma = exp_get_abs_int (os->load_base, 0, "load base", @@ -5240,16 +5347,6 @@ lang_gc_sections (void) bfd_gc_sections (output_bfd, &link_info); } -static void -lang_mark_used_section (void) -{ - unsigned int gc_sections = link_info.gc_sections; - - link_info.gc_sections = 0; - bfd_gc_sections (output_bfd, &link_info); - link_info.gc_sections = gc_sections; -} - void lang_process (void) { @@ -5408,7 +5505,6 @@ lang_process (void) lang_check_section_addresses (); /* Final stuffs. */ - lang_mark_used_section (); ldemul_finish (); lang_end (); } --- binutils/ld/ldlang.h.empty 2005-05-07 06:58:49.000000000 -0700 +++ binutils/ld/ldlang.h 2005-05-07 08:59:05.000000000 -0700 @@ -147,7 +147,8 @@ typedef struct lang_output_section_state int subsection_alignment; /* Alignment of components. */ int section_alignment; /* Alignment of start of section. */ int constraint; - bfd_boolean all_input_readonly; + unsigned int all_input_readonly : 1; + unsigned int ignored : 1; union etree_union *load_base; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-07 19:16 ` H. J. Lu @ 2005-05-07 20:08 ` H. J. Lu 2005-05-17 15:13 ` Nick Clifton 0 siblings, 1 reply; 17+ messages in thread From: H. J. Lu @ 2005-05-07 20:08 UTC (permalink / raw) To: binutils On Sat, May 07, 2005 at 10:34:32AM -0700, H. J. Lu wrote: > On Fri, May 06, 2005 at 03:47:17PM +0930, Alan Modra wrote: > > On Thu, May 05, 2005 at 09:02:23AM -0700, H. J. Lu wrote: > > > With > > > > > > lang_size_sections (statement_list.head, abs_output_section, > > > &statement_list.head, 0, 0, NULL, > > > command_line.relax ? FALSE : TRUE); > > > lang_do_assignments (statement_list.head, abs_output_section, NULL, > > > 0); > > > lang_reset_memory_regions (); > > > lang_mark_used_section (); > > > strip_unused_output_sections (); > > > > > > at the end of strip_excluded_output_sections, I got > > > failed: Bad value FAIL: PHDRS > > > FAIL: PHDRS2 > > > > You need this from ppc64elf.em. > > > > /* We must not cache anything from the preliminary sizing. */ > > elf_tdata (output_bfd)->program_header_size = 0; > > > > Perhaps a better approach would be to run a cut-down lang_do_assignments > > that just keeps track of output section and symbol assignments other > > than "." within output sections. If it finds such an assignment, mark > > the section as needed. > > > > This patch implements it. > > We should ignore assert failure if mark_used is TRUE, not skip it. H.J. --- bfd/ 2005-05-07 H.J. Lu <hongjiu.lu@intel.com> PR 797 * elf32-i386.c (elf_i386_size_dynamic_sections): Also remove empty sdynbss section. * elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise. ld/ 2005-05-07 H.J. Lu <hongjiu.lu@intel.com> PR 797 * ldexp.c (exp_fold_tree_1): Renamed from exp_fold_tree and take take a bfd_boolean, mark_used. Ignore assert failure if mark_used is TRUE. (exp_fold_tree) Call exp_fold_tree_1 with mark_used == FALSE. (exp_fold_tree_no_dot): Updated to take a bfd_boolean, mark_used and pass down. (fold_unary): Likewise. (fold_binary): Likewise. (fold_trinary): Likewise. (exp_binop): Add FALSE to call to exp_fold_tree_no_dot. (exp_trinop): Likewise. (exp_unop): Likewise. (exp_nameop): Likewise. (exp_get_vma): Likewise. (exp_get_fill): Likewise. (exp_get_abs_int): Likewise. (fold_name): Likewise. Set SEC_KEEP in output section flags. (exp_mark_used_section): New. * ldexp.h (exp_mark_used_section): New. * ldlang.c (lang_output_section_statement_lookup_1): Set the ignored field to FALSE. (lang_mark_used_section_1): New. (lang_mark_used_section): Call lang_mark_used_section_1. (strip_excluded_output_sections): Call lang_mark_used_section and check for unused sections. (lang_size_sections_1): Skip an output section if it should be ignored. (lang_do_assignments_1): Likewise. (lang_process): Don't call lang_mark_used_section here. * ldlang.h (lang_output_section_statement_type): Change all_input_readonly to bitfield. Add ignored. --- binutils/bfd/elf32-i386.c.empty 2005-05-05 07:44:37.000000000 -0700 +++ binutils/bfd/elf32-i386.c 2005-05-07 06:58:49.000000000 -0700 @@ -1914,7 +1914,8 @@ elf_i386_size_dynamic_sections (bfd *out if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/bfd/elf64-x86-64.c.empty 2005-05-05 07:44:41.000000000 -0700 +++ binutils/bfd/elf64-x86-64.c 2005-05-07 06:58:49.000000000 -0700 @@ -1624,7 +1624,8 @@ elf64_x86_64_size_dynamic_sections (bfd if (s == htab->splt || s == htab->sgot - || s == htab->sgotplt) + || s == htab->sgotplt + || s == htab->sdynbss) { /* Strip this section if we don't need it; see the comment below. */ --- binutils/ld/ldexp.c.empty 2005-03-15 09:35:19.000000000 -0800 +++ binutils/ld/ldexp.c 2005-05-07 12:11:09.000000000 -0700 @@ -41,8 +41,12 @@ #include "libiberty.h" #include "safe-ctype.h" +static etree_value_type exp_fold_tree_1 + (etree_type *, lang_output_section_statement_type *, + lang_phase_type, bfd_vma, bfd_vma *, bfd_boolean); static etree_value_type exp_fold_tree_no_dot - (etree_type *, lang_output_section_statement_type *, lang_phase_type); + (etree_type *, lang_output_section_statement_type *, lang_phase_type, + bfd_boolean); static bfd_vma align_n (bfd_vma, bfd_vma); @@ -219,13 +223,14 @@ fold_unary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->unary.child, - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->unary.child, + current_section, + allocation_done, dot, dotp, mark_used); if (result.valid_p) { switch (tree->type.node_code) @@ -308,12 +313,13 @@ fold_binary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->binary.lhs, current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->binary.lhs, current_section, + allocation_done, dot, dotp, mark_used); /* The SEGMENT_START operator is special because its first operand is a string, not the name of a symbol. */ @@ -338,9 +344,10 @@ fold_binary (etree_type *tree, { etree_value_type other; - other = exp_fold_tree (tree->binary.rhs, - current_section, - allocation_done, dot, dotp); + other = exp_fold_tree_1 (tree->binary.rhs, + current_section, + allocation_done, + dot, dotp, mark_used); if (other.valid_p) { /* If the values are from different sections, or this is an @@ -498,18 +505,20 @@ fold_trinary (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, bfd_vma dot, - bfd_vma *dotp) + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; - result = exp_fold_tree (tree->trinary.cond, current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->trinary.cond, current_section, + allocation_done, dot, dotp, mark_used); if (result.valid_p) - result = exp_fold_tree ((result.value - ? tree->trinary.lhs - : tree->trinary.rhs), - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 ((result.value + ? tree->trinary.lhs + : tree->trinary.rhs), + current_section, + allocation_done, + dot, dotp, mark_used); return result; } @@ -518,7 +527,8 @@ static etree_value_type fold_name (etree_type *tree, lang_output_section_statement_type *current_section, lang_phase_type allocation_done, - bfd_vma dot) + bfd_vma dot, + bfd_boolean mark_used) { etree_value_type result; @@ -596,6 +606,7 @@ fold_name (etree_type *tree, + h->u.def.section->output_offset), NULL, os); + os->bfd_section->flags |= SEC_KEEP; } } } @@ -619,8 +630,12 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed > 0) - result = new_rel (0, NULL, os); + if (os) + { + os->bfd_section->flags |= SEC_KEEP; + if (os->processed > 0) + result = new_rel (0, NULL, os); + } } break; @@ -630,14 +645,19 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed != 0) + if (os) { - if (os->load_base == NULL) - result = new_rel (0, NULL, os); - else - result = exp_fold_tree_no_dot (os->load_base, - abs_output_section, - allocation_done); + os->bfd_section->flags |= SEC_KEEP; + if (os->processed != 0) + { + if (os->load_base == NULL) + result = new_rel (0, NULL, os); + else + result = exp_fold_tree_no_dot (os->load_base, + abs_output_section, + allocation_done, + mark_used); + } } } break; @@ -649,8 +669,12 @@ fold_name (etree_type *tree, lang_output_section_statement_type *os; os = lang_output_section_find (tree->name.name); - if (os && os->processed > 0) - result = new_abs (os->bfd_section->size / opb); + if (os) + { + os->bfd_section->flags |= SEC_KEEP; + if (os->processed > 0) + result = new_abs (os->bfd_section->size / opb); + } } break; @@ -688,12 +712,13 @@ fold_name (etree_type *tree, return result; } -etree_value_type -exp_fold_tree (etree_type *tree, - lang_output_section_statement_type *current_section, - lang_phase_type allocation_done, - bfd_vma dot, - bfd_vma *dotp) +static etree_value_type +exp_fold_tree_1 (etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, + bfd_vma *dotp, + bfd_boolean mark_used) { etree_value_type result; @@ -721,26 +746,34 @@ exp_fold_tree (etree_type *tree, break; case etree_assert: - result = exp_fold_tree (tree->assert_s.child, - current_section, - allocation_done, dot, dotp); - if (result.valid_p && !result.value) - einfo ("%X%P: %s\n", tree->assert_s.message); + result = exp_fold_tree_1 (tree->assert_s.child, + current_section, + allocation_done, dot, dotp, + mark_used); + if (result.valid_p) + { + if (mark_used) + /* We don't care if assert fails or not when we are just + marking if a section is used or not. */ + result.value = 1; + else if (!result.value) + einfo ("%X%P: %s\n", tree->assert_s.message); + } break; case etree_unary: result = fold_unary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_binary: result = fold_binary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_trinary: result = fold_trinary (tree, current_section, allocation_done, - dot, dotp); + dot, dotp, mark_used); break; case etree_assign: @@ -757,9 +790,10 @@ exp_fold_tree (etree_type *tree, { /* Notify the folder that this is an assignment to dot. */ assigning_to_dot = TRUE; - result = exp_fold_tree (tree->assign.src, - current_section, - allocation_done, dot, dotp); + result = exp_fold_tree_1 (tree->assign.src, + current_section, + allocation_done, + dot, dotp, mark_used); assigning_to_dot = FALSE; if (! result.valid_p) @@ -788,9 +822,9 @@ exp_fold_tree (etree_type *tree, } else { - result = exp_fold_tree (tree->assign.src, - current_section, allocation_done, - dot, dotp); + result = exp_fold_tree_1 (tree->assign.src, + current_section, allocation_done, + dot, dotp, mark_used); if (result.valid_p) { bfd_boolean create; @@ -832,7 +866,8 @@ exp_fold_tree (etree_type *tree, break; case etree_name: - result = fold_name (tree, current_section, allocation_done, dot); + result = fold_name (tree, current_section, allocation_done, dot, + mark_used); break; default: @@ -844,12 +879,25 @@ exp_fold_tree (etree_type *tree, return result; } +etree_value_type +exp_fold_tree (etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, + bfd_vma *dotp) +{ + return exp_fold_tree_1 (tree, current_section, allocation_done, + dot, dotp, FALSE); +} + static etree_value_type exp_fold_tree_no_dot (etree_type *tree, lang_output_section_statement_type *current_section, - lang_phase_type allocation_done) + lang_phase_type allocation_done, + bfd_boolean mark_used) { - return exp_fold_tree (tree, current_section, allocation_done, 0, NULL); + return exp_fold_tree_1 (tree, current_section, allocation_done, 0, + NULL, mark_used); } etree_type * @@ -864,7 +912,7 @@ exp_binop (int code, etree_type *lhs, et value.type.node_class = etree_binary; r = exp_fold_tree_no_dot (&value, abs_output_section, - lang_first_phase_enum); + lang_first_phase_enum, FALSE); if (r.valid_p) { return exp_intop (r.value); @@ -884,7 +932,7 @@ exp_trinop (int code, etree_type *cond, value.trinary.cond = cond; value.trinary.rhs = rhs; value.type.node_class = etree_trinary; - r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum); + r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -903,7 +951,7 @@ exp_unop (int code, etree_type *child) value.unary.child = child; value.unary.type.node_class = etree_unary; r = exp_fold_tree_no_dot (&value, abs_output_section, - lang_first_phase_enum); + lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -921,7 +969,7 @@ exp_nameop (int code, const char *name) value.name.name = name; value.name.type.node_class = etree_name; - r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum); + r = exp_fold_tree_no_dot (&value, NULL, lang_first_phase_enum, FALSE); if (r.valid_p) return exp_intop (r.value); @@ -1071,7 +1119,8 @@ exp_get_vma (etree_type *tree, if (tree != NULL) { - r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + r = exp_fold_tree_no_dot (tree, abs_output_section, + allocation_done, FALSE); if (! r.valid_p && name != NULL) einfo (_("%F%S nonconstant expression for %s\n"), name); return r.value; @@ -1103,7 +1152,8 @@ exp_get_fill (etree_type *tree, if (tree == NULL) return def; - r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done, + FALSE); if (! r.valid_p && name != NULL) einfo (_("%F%S nonconstant expression for %s\n"), name); @@ -1154,7 +1204,8 @@ exp_get_abs_int (etree_type *tree, lang_phase_type allocation_done) { etree_value_type res; - res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done, + FALSE); if (res.valid_p) res.value += res.section->bfd_section->vma; @@ -1173,3 +1224,91 @@ align_n (bfd_vma value, bfd_vma align) value = (value + align - 1) / align; return value * align; } + +void +exp_mark_used_section + (etree_type *tree, + lang_output_section_statement_type *current_section) +{ + switch (tree->type.node_class) + { + case etree_value: + break; + + case etree_rel: + break; + + case etree_assert: + break; + + case etree_unary: + break; + + case etree_binary: + break; + + case etree_trinary: + break; + + case etree_assign: + case etree_provide: + case etree_provided: + if (tree->assign.dst[0] != '.' || tree->assign.dst[1] != 0) + { + etree_value_type result; + bfd_vma dot = 0; + + result = exp_fold_tree_1 (tree->assign.src, + current_section, + lang_allocating_phase_enum, + dot, &dot, TRUE); + if (result.valid_p) + { + bfd_boolean create; + struct bfd_link_hash_entry *h; + + if (tree->type.node_class == etree_assign) + create = TRUE; + else + create = FALSE; + h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, + create, FALSE, TRUE); + if (h == NULL) + { + if (create) + einfo (_("%P%F:%s: hash creation failed\n"), + tree->assign.dst); + } + else if (tree->type.node_class == etree_provide + && h->type != bfd_link_hash_new + && h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Do nothing. The symbol was defined by some + object. */ + } + else + { + /* FIXME: Should we worry if the symbol is already + defined? */ + lang_update_definedness (tree->assign.dst, h); + h->type = bfd_link_hash_defined; + h->u.def.value = result.value; + h->u.def.section = result.section->bfd_section; + if (tree->type.node_class == etree_provide) + tree->type.node_class = etree_provided; + } + } + } + break; + + case etree_name: + fold_name (tree, current_section, lang_allocating_phase_enum, 0, + TRUE); + break; + + default: + abort (); + break; + } +} --- binutils/ld/ldexp.h.empty 2004-12-22 09:30:57.000000000 -0800 +++ binutils/ld/ldexp.h 2005-05-07 09:34:05.000000000 -0700 @@ -156,5 +156,7 @@ fill_type *exp_get_fill (etree_type *, fill_type *, char *, lang_phase_type); bfd_vma exp_get_abs_int (etree_type *, int, char *, lang_phase_type); +void exp_mark_used_section + (etree_type *, struct lang_output_section_statement_struct *); #endif --- binutils/ld/ldlang.c.empty 2005-05-07 06:58:49.000000000 -0700 +++ binutils/ld/ldlang.c 2005-05-07 10:13:04.000000000 -0700 @@ -1083,6 +1083,7 @@ lang_output_section_statement_lookup_1 ( lookup->bfd_section = NULL; lookup->processed = 0; lookup->constraint = constraint; + lookup->ignored = FALSE; lookup->sectype = normal_section; lookup->addr_tree = NULL; lang_list_init (&lookup->children); @@ -3109,6 +3110,90 @@ map_input_to_output_sections } } +/* Worker function for lang_mark_used_section. Recursiveness goes + here. */ + +static void +lang_mark_used_section_1 + (lang_statement_union_type *s, + lang_output_section_statement_type *output_section_statement) +{ + for (; s != NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_constructors_statement_enum: + break; + + case lang_output_section_statement_enum: + { + lang_output_section_statement_type *os; + + os = &(s->output_section_statement); + if (os->bfd_section != NULL) + lang_mark_used_section_1 (os->children.head, os); + } + break; + case lang_wild_statement_enum: + lang_mark_used_section_1 (s->wild_statement.children.head, + output_section_statement); + + break; + + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + break; + case lang_data_statement_enum: + exp_mark_used_section (s->data_statement.exp, + abs_output_section); + break; + + case lang_reloc_statement_enum: + break; + + case lang_input_section_enum: + break; + + case lang_input_statement_enum: + break; + case lang_fill_statement_enum: + break; + case lang_assignment_statement_enum: + exp_mark_used_section (s->assignment_statement.exp, + output_section_statement); + break; + case lang_padding_statement_enum: + break; + + case lang_group_statement_enum: + lang_mark_used_section_1 (s->group_statement.children.head, + output_section_statement); + break; + + default: + FAIL (); + break; + case lang_address_statement_enum: + break; + } + } +} + +static void +lang_mark_used_section (void) +{ + unsigned int gc_sections = link_info.gc_sections; + + /* Callers of exp_fold_tree need to increment this. */ + lang_statement_iteration++; + lang_mark_used_section_1 (statement_list.head, abs_output_section); + + link_info.gc_sections = 0; + bfd_gc_sections (output_bfd, &link_info); + link_info.gc_sections = gc_sections; +} + /* An output section might have been removed after its statement was added. For example, ldemul_before_allocation can remove dynamic sections if they turn out to be not needed. Clean them up here. */ @@ -3118,32 +3203,54 @@ strip_excluded_output_sections (void) { lang_output_section_statement_type *os; + lang_mark_used_section (); + for (os = &lang_output_section_statement.head->output_section_statement; os != NULL; os = os->next) { - asection *s; + asection *output_section; + bfd_boolean exclude; if (os->constraint == -1) continue; - if (os->bfd_section == NULL || os->bfd_section->map_head.s == NULL) + output_section = os->bfd_section; + if (output_section == NULL) continue; - for (s = os->bfd_section->map_head.s; s != NULL; s = s->map_head.s) - if ((s->flags & SEC_EXCLUDE) == 0) - break; + exclude = FALSE; + if (output_section->map_head.s != NULL) + { + asection *s; - os->bfd_section->map_head.link_order = NULL; - os->bfd_section->map_tail.link_order = NULL; + for (s = output_section->map_head.s; s != NULL; + s = s->map_head.s) + if ((s->flags & SEC_EXCLUDE) == 0) + break; + + output_section->map_head.link_order = NULL; + output_section->map_tail.link_order = NULL; + + if (s == NULL) + exclude = TRUE; + } - if (s == NULL) + if (exclude + || (output_section->linker_has_input == 0 + && ((output_section->flags + & (SEC_KEEP | SEC_HAS_CONTENTS)) == 0))) { - s = os->bfd_section; - os->bfd_section = NULL; - if (!bfd_section_removed_from_list (output_bfd, s)) + if (exclude) + os->bfd_section = NULL; + else + /* We don't set bfd_section to NULL since bfd_section of the + * removed output section statement may still be used. */ + os->ignored = TRUE; + if (!bfd_section_removed_from_list (output_bfd, + output_section)) { - bfd_section_list_remove (output_bfd, s); + bfd_section_list_remove (output_bfd, output_section); output_bfd->section_count--; } } @@ -3925,8 +4032,8 @@ lang_size_sections_1 lang_output_section_statement_type *os; os = &s->output_section_statement; - if (os->bfd_section == NULL) - /* This section was never actually created. */ + if (os->bfd_section == NULL || os->ignored) + /* This section was removed or never actually created. */ break; /* If this is a COFF shared library section, use the size and @@ -4421,7 +4528,7 @@ lang_do_assignments_1 lang_output_section_statement_type *os; os = &(s->output_section_statement); - if (os->bfd_section != NULL) + if (os->bfd_section != NULL && !os->ignored) { dot = os->bfd_section->vma; lang_do_assignments_1 (os->children.head, os, os->fill, dot); @@ -4435,7 +4542,7 @@ lang_do_assignments_1 { /* If nothing has been placed into the output section then it won't have a bfd_section. */ - if (os->bfd_section) + if (os->bfd_section && !os->ignored) { os->bfd_section->lma = exp_get_abs_int (os->load_base, 0, "load base", @@ -5240,16 +5347,6 @@ lang_gc_sections (void) bfd_gc_sections (output_bfd, &link_info); } -static void -lang_mark_used_section (void) -{ - unsigned int gc_sections = link_info.gc_sections; - - link_info.gc_sections = 0; - bfd_gc_sections (output_bfd, &link_info); - link_info.gc_sections = gc_sections; -} - void lang_process (void) { @@ -5408,7 +5505,6 @@ lang_process (void) lang_check_section_addresses (); /* Final stuffs. */ - lang_mark_used_section (); ldemul_finish (); lang_end (); } --- binutils/ld/ldlang.h.empty 2005-05-07 06:58:49.000000000 -0700 +++ binutils/ld/ldlang.h 2005-05-07 08:59:05.000000000 -0700 @@ -147,7 +147,8 @@ typedef struct lang_output_section_state int subsection_alignment; /* Alignment of components. */ int section_alignment; /* Alignment of start of section. */ int constraint; - bfd_boolean all_input_readonly; + unsigned int all_input_readonly : 1; + unsigned int ignored : 1; union etree_union *load_base; ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: PATCH: PR 797: Alignment in empty section changes the output layout 2005-05-07 20:08 ` H. J. Lu @ 2005-05-17 15:13 ` Nick Clifton 0 siblings, 0 replies; 17+ messages in thread From: Nick Clifton @ 2005-05-17 15:13 UTC (permalink / raw) To: H. J. Lu; +Cc: binutils Hi H. J. > bfd/ > 2005-05-07 H.J. Lu <hongjiu.lu@intel.com> > > PR 797 > * elf32-i386.c (elf_i386_size_dynamic_sections): Also remove > empty sdynbss section. > * elf64-x86-64.c (elf64_x86_64_size_dynamic_sections): Likewise. > > ld/ > 2005-05-07 H.J. Lu <hongjiu.lu@intel.com> > > PR 797 > * ldexp.c (exp_fold_tree_1): Renamed from exp_fold_tree and > take take a bfd_boolean, mark_used. Ignore assert failure if > mark_used is TRUE. > (exp_fold_tree) Call exp_fold_tree_1 with mark_used == FALSE. > (exp_fold_tree_no_dot): Updated to take a bfd_boolean, > mark_used and pass down. > (fold_unary): Likewise. > (fold_binary): Likewise. > (fold_trinary): Likewise. > (exp_binop): Add FALSE to call to exp_fold_tree_no_dot. > (exp_trinop): Likewise. > (exp_unop): Likewise. > (exp_nameop): Likewise. > (exp_get_vma): Likewise. > (exp_get_fill): Likewise. > (exp_get_abs_int): Likewise. > (fold_name): Likewise. Set SEC_KEEP in output section flags. > (exp_mark_used_section): New. > > * ldexp.h (exp_mark_used_section): New. > > * ldlang.c (lang_output_section_statement_lookup_1): Set the > ignored field to FALSE. > (lang_mark_used_section_1): New. > (lang_mark_used_section): Call lang_mark_used_section_1. > (strip_excluded_output_sections): Call lang_mark_used_section > and check for unused sections. > (lang_size_sections_1): Skip an output section if it should > be ignored. > (lang_do_assignments_1): Likewise. > (lang_process): Don't call lang_mark_used_section here. > > * ldlang.h (lang_output_section_statement_type): Change > all_input_readonly to bitfield. Add ignored. Approved - please apply - but could also generate a test case to make sure that this problem does not reoccur. Cheers Nick ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2005-05-17 15:10 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2005-03-24 11:45 PATCH: PR 797: Alignment in empty section changes the output layout H. J. Lu 2005-03-25 2:22 ` H. J. Lu 2005-03-29 4:21 ` Alan Modra 2005-03-29 7:13 ` H. J. Lu 2005-03-29 8:12 ` Alan Modra 2005-03-30 16:30 ` H. J. Lu 2005-05-04 19:53 H. J. Lu 2005-05-05 3:48 ` Alan Modra 2005-05-05 4:52 ` H. J. Lu 2005-05-05 5:35 ` Alan Modra 2005-05-05 5:56 ` H. J. Lu 2005-05-05 6:33 ` Alan Modra 2005-05-05 16:12 ` H. J. Lu 2005-05-06 6:20 ` Alan Modra 2005-05-07 19:16 ` H. J. Lu 2005-05-07 20:08 ` H. J. Lu 2005-05-17 15:13 ` Nick Clifton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).