Linker Bug or Design Intent (Absolute symbols in zero sized sections)

Jakub Jelinek jakub@redhat.com
Wed Oct 11 07:12:00 GMT 2006


On Tue, Oct 10, 2006 at 06:34:23PM +0200, Jakub Jelinek wrote:
> This has an ugly drawback that now almost every executable has
>   [15] .preinit_array    PREINIT_ARRAY   0000000010010a94 010a94 000000 00 WA  0   0  1
>   [16] .init_array       INIT_ARRAY      0000000010010a94 010a94 000000 00 WA  0   0  1
>   [17] .fini_array       FINI_ARRAY      0000000010010a94 010a94 000000 00 WA  0   0  1
> Can't we at least come up with PROVIDES/PROVIDES_HIDDEN variants that would
> allow these symbols turned into absolute and/or to absolute 0 if the
> section is empty and not output such empty sections and use that in the
> builtin linker script?
> 
> It is nice kernel can now do its dirty hacks, but the userland shouldn't
> suffer because of that.

On x86_64, e.g. tmpdir/dl2b and most of the other test binaries are now
unnecessarily 2MB+ big:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        00000000004001c8 0001c8 00001c 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            00000000004001e4 0001e4 000020 00   A  0   0  4
  [ 3] .hash             HASH            0000000000400208 000208 000048 04   A  4   0  8
  [ 4] .dynsym           DYNSYM          0000000000400250 000250 000138 18   A  5   1  8
  [ 5] .dynstr           STRTAB          0000000000400388 000388 000093 00   A  0   0  1
  [ 6] .gnu.version      VERSYM          000000000040041c 00041c 00001a 02   A  4   0  2
  [ 7] .gnu.version_r    VERNEED         0000000000400438 000438 000020 00   A  5   1  8
  [ 8] .rela.dyn         RELA            0000000000400458 000458 000030 18   A  4   0  8
  [ 9] .rela.plt         RELA            0000000000400488 000488 000048 18   A  4  11  8
  [10] .init             PROGBITS        00000000004004d0 0004d0 000018 00  AX  0   0  4
  [11] .plt              PROGBITS        00000000004004e8 0004e8 000040 10  AX  0   0  4
  [12] .text             PROGBITS        0000000000400530 000530 000208 00  AX  0   0 16
  [13] .fini             PROGBITS        0000000000400738 000738 00000e 00  AX  0   0  4
  [14] .rodata           PROGBITS        0000000000400748 000748 00001d 00   A  0   0  8
  [15] .eh_frame         PROGBITS        0000000000400768 000768 0000a4 00   A  0   0  8
  [16] .preinit_array    PREINIT_ARRAY   000000000060080c 20080c 000000 00  WA  0   0  1
  [17] .init_array       INIT_ARRAY      000000000060080c 20080c 000000 00  WA  0   0  1
  [18] .fini_array       FINI_ARRAY      000000000060080c 20080c 000000 00  WA  0   0  1
  [19] .ctors            PROGBITS        0000000000600810 000810 000010 00  WA  0   0  8
  [20] .dtors            PROGBITS        0000000000600820 000820 000010 00  WA  0   0  8
  [21] .jcr              PROGBITS        0000000000600830 000830 000008 00  WA  0   0  8
  [22] .dynamic          DYNAMIC         0000000000600838 000838 0001a0 10  WA  5   0  8
  [23] .got              PROGBITS        00000000006009d8 0009d8 000008 08  WA  0   0  8
  [24] .got.plt          PROGBITS        00000000006009e0 0009e0 000030 08  WA  0   0  8
  [25] .data             PROGBITS        0000000000600a10 000a10 000010 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000600a20 000a20 000008 00  WA  0   0  4
  [27] .comment          PROGBITS        0000000000000000 20080c 000114 00      0   0  1
  [28] .debug_aranges    PROGBITS        0000000000000000 200920 000030 00      0   0  1
  [29] .debug_pubnames   PROGBITS        0000000000000000 200950 000023 00      0   0  1
  [30] .debug_info       PROGBITS        0000000000000000 200973 000339 00      0   0  1
  [31] .debug_abbrev     PROGBITS        0000000000000000 200cac 0000dd 00      0   0  1
  [32] .debug_line       PROGBITS        0000000000000000 200d89 0000eb 00      0   0  1
  [33] .debug_frame      PROGBITS        0000000000000000 200e78 000050 00      0   0  8
  [34] .debug_str        PROGBITS        0000000000000000 200ec8 000220 01  MS  0   0  1
  [35] .debug_loc        PROGBITS        0000000000000000 2010e8 000038 00      0   0  1
  [36] .shstrtab         STRTAB          0000000000000000 201120 000168 00      0   0  1
  [37] .symtab           SYMTAB          0000000000000000 201c48 000780 18     38  60  8
  [38] .strtab           STRTAB          0000000000000000 2023c8 000246 00      0   0  1

and prelink isn't exactly excited about such sh_offset jumps here and
there.  This patch adds a REMOVE_EMPTY output section flag which
when present in the linker script basically undoes the PR ld/3223
changes for that section, so if the section is empty and there are any
symbols defined in it, they are changed into absolute ones.
For .preinit_array/.init_array/.fini_array libc certainly won't mind
that, if the start and end symbols are equal, it won't do anything, no
matter what values those symbols have.

On ppc, I'm still getting zero size .sdata.
Here we have:
  .sdata          :
  {
    PROVIDE (_SDA_BASE_ = 32768);
    *(.sdata .sdata.* .gnu.linkonce.s.*)
  }
Either we could add here REMOVE_EMPTY flag, or, perhaps better, not consider
at least symbol = absolute value assignments as section relative,
so adding something like:
  && tree->assign.src->type.node_class != etree_value
to the tests that check if section_relative_symbol should be set.

2006-10-11  Jakub Jelinek  <jakub@redhat.com>

	* ldgram.y (REMOVE_EMPTY): New token.
	(sect_constraint): Add it.
	* ldlex.l (REMOVE_EMPTY): Add.
	* ldlang.h (lang_output_section_statement_type): Add remove_empty.
	* ldlang.c (lang_output_section_statement_lookup_1): Handle
	REMOVE_EMPTY.
	(lang_size_sections_1): If remove_empty, don't set
	section_relative_symbol.
	* scripttempl/elf.sc: Add REMOVE_EMPTY to .init_array, .fini_array
	and .preinit_array.

--- ld/ldlang.c.jj	2006-09-27 06:18:15.000000000 +0200
+++ ld/ldlang.c	2006-10-11 00:19:48.000000000 +0200
@@ -1226,6 +1226,13 @@ lang_output_section_statement_lookup_1 (
   struct out_section_hash_entry *entry;
   struct out_section_hash_entry *last_ent;
   unsigned long hash;
+  bfd_boolean remove_empty = FALSE;
+
+  if (constraint == REMOVE_EMPTY)
+    {
+      remove_empty = TRUE;
+      constraint = 0;
+    }
 
   entry = ((struct out_section_hash_entry *)
 	   bfd_hash_lookup (&output_section_statement_table, name,
@@ -1271,6 +1278,8 @@ lang_output_section_statement_lookup_1 (
 
   entry->s.output_section_statement.name = name;
   entry->s.output_section_statement.constraint = constraint;
+  if (remove_empty)
+    entry->s.output_section_statement.remove_empty = 1;
   return &entry->s.output_section_statement;
 }
 
@@ -4640,7 +4649,8 @@ lang_size_sections_1
 	    if ((tree->type.node_class == etree_provided 
 		 || tree->type.node_class == etree_assign)
 		&& (tree->assign.dst [0] != '.'
-		    || tree->assign.dst [1] != '\0'))
+		    || tree->assign.dst [1] != '\0')
+		&& !output_section_statement->remove_empty)
 	      output_section_statement->section_relative_symbol = 1;
 
 	    if (!output_section_statement->ignored)
--- ld/ldgram.y.jj	2006-09-07 19:16:34.000000000 +0200
+++ ld/ldgram.y	2006-10-11 00:10:32.000000000 +0200
@@ -150,7 +150,7 @@ static int error_index;
 %token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START
 %token <name> VERS_TAG VERS_IDENTIFIER
 %token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT
-%token KEEP ONLY_IF_RO ONLY_IF_RW SPECIAL
+%token KEEP ONLY_IF_RO ONLY_IF_RW REMOVE_EMPTY SPECIAL
 %token EXCLUDE_FILE
 %token CONSTANT
 %type <versyms> vers_defns
@@ -907,6 +907,7 @@ opt_subalign:
 sect_constraint:
 		ONLY_IF_RO { $$ = ONLY_IF_RO; }
 	|	ONLY_IF_RW { $$ = ONLY_IF_RW; }
+	|	REMOVE_EMPTY { $$ = REMOVE_EMPTY; }
 	|	SPECIAL { $$ = SPECIAL; }
 	|	{ $$ = 0; }
 	;
--- ld/scripttempl/elf.sc.jj	2006-09-24 08:23:15.000000000 +0200
+++ ld/scripttempl/elf.sc	2006-10-11 00:26:15.000000000 +0200
@@ -380,20 +380,20 @@ cat <<EOF
   .tdata	${RELOCATING-0} : { *(.tdata${RELOCATING+ .tdata.* .gnu.linkonce.td.*}) }
   .tbss		${RELOCATING-0} : { *(.tbss${RELOCATING+ .tbss.* .gnu.linkonce.tb.*})${RELOCATING+ *(.tcommon)} }
 
-  .preinit_array   ${RELOCATING-0} :
+  .preinit_array   ${RELOCATING-0} : ${RELOCATING+${CREATE_SHLIB-REMOVE_EMPTY}}
   {
     ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_start = .);}}
     KEEP (*(.preinit_array))
     ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__preinit_array_end = .);}}
   }
-  .init_array   ${RELOCATING-0} :
+  .init_array   ${RELOCATING-0} : ${RELOCATING+${CREATE_SHLIB-REMOVE_EMPTY}}
   {
      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_start = .);}}
      KEEP (*(SORT(.init_array.*)))
      KEEP (*(.init_array))
      ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__init_array_end = .);}}
   }
-  .fini_array   ${RELOCATING-0} :
+  .fini_array   ${RELOCATING-0} : ${RELOCATING+${CREATE_SHLIB-REMOVE_EMPTY}}
   {
     ${RELOCATING+${CREATE_SHLIB-PROVIDE_HIDDEN (${USER_LABEL_PREFIX}__fini_array_start = .);}}
     KEEP (*(.fini_array))
--- ld/ldlang.h.jj	2006-09-27 06:18:15.000000000 +0200
+++ ld/ldlang.h	2006-10-11 00:07:20.000000000 +0200
@@ -157,6 +157,9 @@ typedef struct lang_output_section_state
   unsigned int ignored : 1; 
   /* If there is a symbol relative to this section.  */
   unsigned int section_relative_symbol : 1; 
+  /* If this section should be removed when empty, even when it
+     contains section relative symbols.  */
+  unsigned int remove_empty : 1;
 } lang_output_section_statement_type;
 
 typedef struct
--- ld/ldlex.l.jj	2006-09-07 19:16:34.000000000 +0200
+++ ld/ldlex.l	2006-10-10 23:59:54.000000000 +0200
@@ -1,7 +1,7 @@
 %{
 
 /* Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005  Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
 
    This file is part of GLD, the Gnu Linker.
 
@@ -304,6 +304,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
 <EXPRESSION,BOTH,SCRIPT>"OVERLAY"	{ RTOKEN(OVERLAY);}
 <EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RO"	{ RTOKEN(ONLY_IF_RO); }
 <EXPRESSION,BOTH,SCRIPT>"ONLY_IF_RW"	{ RTOKEN(ONLY_IF_RW); }
+<EXPRESSION,BOTH,SCRIPT>"REMOVE_EMPTY"	{ RTOKEN(REMOVE_EMPTY); }
 <EXPRESSION,BOTH,SCRIPT>"SPECIAL"	{ RTOKEN(SPECIAL); }
 <BOTH,SCRIPT>"o"			{ RTOKEN(ORIGIN);}
 <BOTH,SCRIPT>"org"			{ RTOKEN(ORIGIN);}

	Jakub



More information about the Binutils mailing list