ELF/LD: Avoid producing hidden and internal dynamic symbols
authorMaciej W. Rozycki <macro@imgtec.com>
Tue, 5 Apr 2016 14:10:05 +0000 (15:10 +0100)
committerMaciej W. Rozycki <macro@imgtec.com>
Tue, 5 Apr 2016 14:14:54 +0000 (15:14 +0100)
Always turn hidden and internal symbols which have a dynamic index into
local ones.  This is required by the the ELF gABI[1]:

"A hidden symbol contained in a relocatable object must be either
removed or converted to STB_LOCAL binding by the link-editor when the
relocatable object is included in an executable file or shared object."

"An internal symbol contained in a relocatable object must be either
removed or converted to STB_LOCAL binding by the link-editor when the
relocatable object is included in an executable file or shared object."

The ELF linker usually respects this requirement, however in the case
where a dynamic symbol has been preallocated due to a reference of the
default export class aka visibility from the object being linked, and
then merged with a hidden or internal symbol definition from within the
same object, then the original export class is carried over to the
output dynamic symbol table, because while merging the generic ELF
linker only converts affected dynamic symbols to local when they are
defined or referenced by the object being linked and a dynamic object
involved in the link both at a time.

The dynamic symbol produced confuses then the dynamic loader at the run
time -- the hidden or internal export class is ignored and the symbol
follows preemption rules as with the default export class.

In the MIPS target it happens when `mips_elf_record_global_got_symbol'
creates a dynamic symbol when a call relocation is encountered.
Additionally if the undefined symbol referred by such a relocation does
specify the intended export class, then a local dynamic symbol is
created instead, which is harmless and allowed, but useless.  Normally
no local dynamic symbols are created, except for a single dummy one at
the beginning.

Correct the problem by removing the extra check for a dynamic symbol
being defined or referenced by the object being linked and a dynamic
object involved in the link both at a time.  The test cases included
cover the internal and hidden symbol cases, as well as a protected
symbol for a reference, the handling of which is unchanged by this fix.
Both cases described above are covered, that is where an internal or
hidden dynamic symbol is produced and where a local one is.

NB this change affects CRIS results where some symbols in the static
table produced in a final link are now converted from STV_HIDDEN to
STB_LOCAL.  This happens whenever the `elf_backend_hide_symbol' handler
is called, so the affected symbols must have been chosen for entering
into the dynamic symbol table, except in these test cases no such symbol
table is produced.  In fully linked binaries the static symbol table is
only used for debugging though, so such a change is fine.

References:

[1] "System V Application Binary Interface - DRAFT - 24 April 2001",
    The Santa Cruz Operation, Inc., "Symbol Table",
    <http://www.sco.com/developers/gabi/2001-04-24/ch4.symtab.html>

bfd/
PR ld/19908
* elflink.c (elf_link_add_object_symbols): Always turn hidden
and internal symbols which have a dynamic index into local
ones.

ld/
PR ld/19908
* testsuite/ld-cris/tls-e-20.d: Adjust for hidden symbol
handling fix.
* testsuite/ld-cris/tls-e-20a.d: Likewise.
* testsuite/ld-cris/tls-e-21.d: Likewise.
* testsuite/ld-cris/tls-e-23.d: Likewise.
* testsuite/ld-cris/tls-e-80.d: Likewise.
* testsuite/ld-cris/tls-gd-3h.d: Likewise.
* testsuite/ld-cris/tls-leie-19.d: Likewise.
* testsuite/ld-mips-elf/export-class-ref-lib.sd: New test.
* testsuite/ld-mips-elf/export-hidden-ref.sd: New test.
* testsuite/ld-mips-elf/export-internal-ref.sd: New test.
* testsuite/ld-mips-elf/export-protected-ref.sd: New test.
* testsuite/ld-mips-elf/export-class-ref-f0.s: New test source.
* testsuite/ld-mips-elf/export-class-ref-f1.s: New test source.
* testsuite/ld-mips-elf/export-class-ref-f2.s: New test source.
* testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.

19 files changed:
bfd/ChangeLog
bfd/elflink.c
ld/ChangeLog
ld/testsuite/ld-cris/tls-e-20.d
ld/testsuite/ld-cris/tls-e-20a.d
ld/testsuite/ld-cris/tls-e-21.d
ld/testsuite/ld-cris/tls-e-23.d
ld/testsuite/ld-cris/tls-e-80.d
ld/testsuite/ld-cris/tls-gd-3h.d
ld/testsuite/ld-cris/tls-leie-19.d
ld/testsuite/ld-mips-elf/export-class-ref-f0.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-class-ref-f1.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-class-ref-f2.s [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-class-ref-lib.sd [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-hidden-ref.sd [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-internal-ref.sd [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-local-ref.sd [new file with mode: 0644]
ld/testsuite/ld-mips-elf/export-protected-ref.sd [new file with mode: 0644]
ld/testsuite/ld-mips-elf/mips-elf.exp

index 42d112f3781722e87b8ed2f3abfb14533870985f..626e68a6aeda9f86e9c7b45aff96779a182d6aea 100644 (file)
@@ -1,3 +1,9 @@
+2016-04-05  Maciej W. Rozycki  <macro@imgtec.com>
+
+       * elflink.c (elf_link_add_object_symbols): Always turn hidden
+       and internal symbols which have a dynamic index into local
+       ones.
+
 2016-04-04  Nick Clifton  <nickc@redhat.com>
 
        PR 19872
index 445fb0132588d154c8996b7d332dd05e0a82eacc..42b3689048ceebd31e65e9850c439ce465616fe6 100644 (file)
@@ -4583,7 +4583,7 @@ error_free_dyn:
                    goto error_free_vers;
                }
            }
-         else if (dynsym && h->dynindx != -1)
+         else if (h->dynindx != -1)
            /* If the symbol already has a dynamic index, but
               visibility says it should not be visible, turn it into
               a local symbol.  */
index ae7062af5e493a214a96f78c5dc234d6a7276d1a..1e1aae7afc5bb7cea71e6b66c261a3a216cc9eb4 100644 (file)
@@ -1,3 +1,23 @@
+2016-04-05  Maciej W. Rozycki  <macro@imgtec.com>
+
+       PR ld/19908
+       * testsuite/ld-cris/tls-e-20.d: Adjust for hidden symbol
+       handling fix.
+       * testsuite/ld-cris/tls-e-20a.d: Likewise.
+       * testsuite/ld-cris/tls-e-21.d: Likewise.
+       * testsuite/ld-cris/tls-e-23.d: Likewise.
+       * testsuite/ld-cris/tls-e-80.d: Likewise.
+       * testsuite/ld-cris/tls-gd-3h.d: Likewise.
+       * testsuite/ld-cris/tls-leie-19.d: Likewise.
+       * testsuite/ld-mips-elf/export-class-ref-lib.sd: New test.
+       * testsuite/ld-mips-elf/export-hidden-ref.sd: New test.
+       * testsuite/ld-mips-elf/export-internal-ref.sd: New test.
+       * testsuite/ld-mips-elf/export-protected-ref.sd: New test.
+       * testsuite/ld-mips-elf/export-class-ref-f0.s: New test source.
+       * testsuite/ld-mips-elf/export-class-ref-f1.s: New test source.
+       * testsuite/ld-mips-elf/export-class-ref-f2.s: New test source.
+       * testsuite/ld-mips-elf/mips-elf.exp: Run the new tests.
+
 2016-04-05  Cupertino Miranda  <cmiranda@synopsys.com>
 
        * testsuite/ld-discard/extern.d: Removed xfail for ARC.
index 6b4e7142cea05efccfd94b3d1f1f8314b978e4eb..eb323a59804ca81aea17bdc6b64777f845cf5db3 100644 (file)
@@ -35,8 +35,8 @@ SYMBOL TABLE:
 0+80094 l    d  \.text 0+ \.text
 0+820b0 l    d  \.tdata        0+ \.tdata
 0+820bc l    d  \.got  0+ \.got
+0+ l       \.tdata     0+4 x
 0+820bc l     O \.got  0+ _GLOBAL_OFFSET_TABLE_
-0+ g       \.tdata     0+4 \.hidden x
 0+80098 g     F \.text 0+6 tlsdsofn2
 0+8 g       \.tdata    0+4 \.hidden x2
 0+80094 g       \.text 0+ _start
index 13b3be8b82487ec7aa6a2eb5b965b4b84d80ec24..7d5a95e8b26e67ff7ea3089b80692d0c2f0564e2 100644 (file)
@@ -43,8 +43,8 @@ SYMBOL TABLE:
 0+ l    df \*ABS\*     0+ .*
 0+ l       \.tdata     0+80 tls128
 0+ l    df \*ABS\*     0+ .*
+0+80 l       \.tdata   0+4 x
 0+82168 l     O \.got  0+ _GLOBAL_OFFSET_TABLE_
-0+80 g       \.tdata   0+4 \.hidden x
 0+800c4 g     F \.text 0+6 tlsdsofn2
 0+821b4 g     O \.data 0+4 got7var5
 0+88 g       \.tdata   0+4 \.hidden x2
index fa56b9faad8dc0bb4836d8453d1b57c223de5141..80ca3e37f774c60cff744896a27dd867a2e2d100 100644 (file)
@@ -19,7 +19,7 @@ private flags = 0:
 #...
 SYMBOL TABLE:
 #...
-0+80 g       \.tdata   0+4 \.hidden x
+0+80 l       \.tdata   0+4 x
 #...
 Contents of section \.text:
 #...
index 499899edf7664b9fe6efd7ff0355685047918f61..a09d55ef901d9cc4d1f3ad6b952c138b5f86d2d5 100644 (file)
@@ -19,7 +19,7 @@ private flags = 0:
 #...
 SYMBOL TABLE:
 #...
-0+80 g       \.tdata   0+4 \.hidden x
+0+80 l       \.tdata   0+4 x
 #...
 Contents of section \.text:
 #...
index 7a6f4599e933153c9459c663b50ee08c120c3ec1..15ce3d7838bcd8e09c65b7253bfa6e1cf04addef 100644 (file)
@@ -42,8 +42,8 @@ SYMBOL TABLE:
 0+820c0 l    d  \.tdata        0+ \.tdata
 0+820d0 l    d  \.tbss 0+ \.tbss
 0+820d0 l    d  \.got  0+ \.got
+0+ l       \.tdata     0+4 x
 0+820d0 l     O \.got  0+ _GLOBAL_OFFSET_TABLE_
-0+ g       \.tdata     0+4 \.hidden x
 0+800a0 g     F \.text 0+6 tlsdsofn2
 0+800a8 g     F \.text 0+6 tlsfn12
 0+c g       \.tdata    0+4 \.hidden x2
index 78f109da8fa1e488204fbd9c902a3cc1f960d35d..898a670e16486d4ebc4349ee9fb2f66ae52757a2 100644 (file)
@@ -19,7 +19,7 @@ private flags = 0:
 #...
 SYMBOL TABLE:
 #...
-0+80 g       \.tdata   0+4 \.hidden x
+0+80 l       \.tdata   0+4 x
 #...
 Contents of section \.text:
 #...
index 6cf69b23f75b39420b1580e402acbd6a206f5e3c..859e2e64dd82cf864c0e5ce42569061b0282f5f5 100644 (file)
@@ -26,13 +26,13 @@ private flags = 0:
                   CONTENTS.*
 SYMBOL TABLE:
 #...
-0+88 g       .tdata    0+4 x
+0+84 l       \.tdata   0+4 x2
 #...
-0+84 g       \.tdata   0+4 \.hidden x2
+0+80 l       \.tdata   0+4 x1
 #...
-0+8c g       .tdata    0+4 z
+0+88 g       .tdata    0+4 x
 #...
-0+80 g       \.tdata   0+4 \.hidden x1
+0+8c g       .tdata    0+4 z
 #...
 Contents of section \.text:
 #...
diff --git a/ld/testsuite/ld-mips-elf/export-class-ref-f0.s b/ld/testsuite/ld-mips-elf/export-class-ref-f0.s
new file mode 100644 (file)
index 0000000..675996d
--- /dev/null
@@ -0,0 +1,37 @@
+       .abicalls
+       .text
+
+       .if     refv == 3
+       .protected f1
+       .elseif refv == 2
+       .hidden f1
+       .elseif refv == 1
+       .internal f1
+       .endif
+
+       .globl  f0
+       .ent    f0
+f0:
+       .frame  $sp, 32, $31
+       .mask   0x80000000, -4
+       .fmask  0x00000000, 0
+       .set    noreorder
+       .cpload $25
+       .set    reorder
+       addiu   $sp, $sp, -32
+       sw      $31, 28($sp)
+       .cprestore 16
+
+       lw      $25, %call16(f1)($28)
+       jalr    $25
+       lw      $28, 16($sp)
+
+       lw      $25, %call16(f2)($28)
+       jalr    $25
+       lw      $28, 16($sp)
+
+       move    $2, $0
+       lw      $31, 28($sp)
+       addiu   $sp, $sp, 32
+       jr      $31
+       .end    f0
diff --git a/ld/testsuite/ld-mips-elf/export-class-ref-f1.s b/ld/testsuite/ld-mips-elf/export-class-ref-f1.s
new file mode 100644 (file)
index 0000000..299278d
--- /dev/null
@@ -0,0 +1,18 @@
+       .abicalls
+       .text
+
+       .globl  f1
+       .if     defv == 3
+       .protected f1
+       .elseif defv == 2
+       .hidden f1
+       .elseif defv == 1
+       .internal f1
+       .endif
+       .ent    f1
+f1:
+       .frame  $sp, 0, $31
+       .mask   0x00000000, 0
+       .fmask  0x00000000, 0
+       jr      $31
+       .end    f1
diff --git a/ld/testsuite/ld-mips-elf/export-class-ref-f2.s b/ld/testsuite/ld-mips-elf/export-class-ref-f2.s
new file mode 100644 (file)
index 0000000..deecdd2
--- /dev/null
@@ -0,0 +1,20 @@
+       .abicalls
+       .text
+
+       .globl  f1
+       .ent    f1
+f1:
+       .frame  $sp, 0, $31
+       .mask   0x00000000, 0
+       .fmask  0x00000000, 0
+       jr      $31
+       .end    f1
+
+       .globl  f2
+       .ent    f2
+f2:
+       .frame  $sp, 0, $31
+       .mask   0x00000000, 0
+       .fmask  0x00000000, 0
+       jr      $31
+       .end    f2
diff --git a/ld/testsuite/ld-mips-elf/export-class-ref-lib.sd b/ld/testsuite/ld-mips-elf/export-class-ref-lib.sd
new file mode 100644 (file)
index 0000000..26b3e38
--- /dev/null
@@ -0,0 +1,6 @@
+# Make sure `f1' is present in the dynamic symbol table, e.g.:
+#    Num:    Value  Size Type    Bind   Vis      Ndx Name
+#      6: 000002d0     8 FUNC    GLOBAL DEFAULT    7 f1
+#...
+ *[0-9]+: +[0-9a-f]+ +[0-9]+ FUNC +GLOBAL +DEFAULT +[0-9]+ f1
+#pass
diff --git a/ld/testsuite/ld-mips-elf/export-hidden-ref.sd b/ld/testsuite/ld-mips-elf/export-hidden-ref.sd
new file mode 100644 (file)
index 0000000..b1d6246
--- /dev/null
@@ -0,0 +1,7 @@
+# Make sure no hidden symbol is present in the dynamic symbol table, e.g.:
+#    Num:    Value  Size Type    Bind   Vis      Ndx Name
+#      6: 004003f0     8 FUNC    GLOBAL HIDDEN     8 f1
+#failif
+#...
+.+ +HIDDEN +.+ +f1
+#pass
diff --git a/ld/testsuite/ld-mips-elf/export-internal-ref.sd b/ld/testsuite/ld-mips-elf/export-internal-ref.sd
new file mode 100644 (file)
index 0000000..4851543
--- /dev/null
@@ -0,0 +1,7 @@
+# Make sure no internal symbol is present in the dynamic symbol table, e.g.:
+#    Num:    Value  Size Type    Bind   Vis      Ndx Name
+#      6: 004003f0     8 FUNC    GLOBAL INTERNAL   8 f1
+#failif
+#...
+.+ +INTERNAL +.+ +f1
+#pass
diff --git a/ld/testsuite/ld-mips-elf/export-local-ref.sd b/ld/testsuite/ld-mips-elf/export-local-ref.sd
new file mode 100644 (file)
index 0000000..4ee4a42
--- /dev/null
@@ -0,0 +1,7 @@
+# Make sure no local symbol is present in the dynamic symbol table, e.g.:
+#    Num:    Value  Size Type    Bind   Vis      Ndx Name
+#      6: 004003f0     8 FUNC    LOCAL  DEFAULT    8 f1
+#failif
+#...
+.+ +LOCAL +.+ +f1
+#pass
diff --git a/ld/testsuite/ld-mips-elf/export-protected-ref.sd b/ld/testsuite/ld-mips-elf/export-protected-ref.sd
new file mode 100644 (file)
index 0000000..af2cb98
--- /dev/null
@@ -0,0 +1,6 @@
+# Make sure a protected symbol is present in the dynamic symbol table, e.g.:
+#    Num:    Value  Size Type    Bind   Vis      Ndx Name
+#      6: 004003f0     8 FUNC    GLOBAL PROTECTED    8 f1
+#...
+ *[0-9]+: +[0-9a-f]+ +[0-9]+ FUNC +GLOBAL +PROTECTED +[0-9]+ f1
+#pass
index c5ce5bc77157896bde47b958a091e686e583a6f3..4467719683969a2ce008562c36acb21e026e8229 100644 (file)
@@ -899,3 +899,31 @@ if { $linux_gnu } {
            n32 -1 1 umips
     }
 }
+
+# PR ld/19908 export class tests.
+if { $linux_gnu } {
+    run_ld_link_tests [list \
+       [list "Shared library for MIPS export class symbol reference tests" \
+             "$abi_ldflags(o32) -shared" "" \
+             "$abi_asflags(o32)" \
+             { export-class-ref-f2.s } \
+             { { readelf --dyn-syms export-class-ref-lib.sd } } \
+             "export-class-ref-lib.so"]]
+    foreach { class flag } { internal 1 hidden 2 protected 3 } {
+       run_ld_link_tests [list \
+           [list "MIPS $class symbol reference test 1" \
+                 "$abi_ldflags(o32) -e f0" "tmpdir/export-class-ref-lib.so" \
+                 "$abi_asflags(o32) --defsym defv=$flag" \
+                 { export-class-ref-f0.s export-class-ref-f1.s } \
+                 [list [list readelf --dyn-syms export-$class-ref.sd] \
+                       [list readelf --dyn-syms export-local-ref.sd]] \
+                 "export-$class-ref"] \
+           [list "MIPS $class symbol reference test 2" \
+                 "$abi_ldflags(o32) -e f0" "tmpdir/export-class-ref-lib.so" \
+                 "$abi_asflags(o32) --defsym defv=$flag --defsym refv=$flag" \
+                 { export-class-ref-f0.s export-class-ref-f1.s } \
+                 [list [list readelf --dyn-syms export-$class-ref.sd] \
+                       [list readelf --dyn-syms export-local-ref.sd]] \
+                 "export-$class-ref"]]
+    }
+}