Fix --defsym to copy symbol attributes.
authorCary Coutant <ccoutant@google.com>
Wed, 9 Jul 2014 05:34:27 +0000 (22:34 -0700)
committerCary Coutant <ccoutant@google.com>
Wed, 9 Jul 2014 05:52:37 +0000 (22:52 -0700)
Alan Modra committed a patch to Gnu ld to fix a problem encountered on
PPC where the --defsym option wasn't copying the st_other bits to the
newly-defined symbol.

    https://sourceware.org/ml/binutils/2014-07/msg00094.html

Gold has the same problem, and additionally wasn't copying the symbol type.
This patch fixes both problems, by copying the symbol type, visibility, and
the remaining st_other bits to the new symbol for --defsym=sym1=sym2
assignments.

gold/
* expression.cc (struct Expression::Expression_eval_info): Add
new fields type_pointer, vis_pointer, and nonvis_pointer.
(Expression::eval_maybe_dot): Add type_pointer, vis_pointer, and
nonvis_pointer parameters. Adjust all calls.
(Symbol_expression::value): Update type, visibility, and nonvis bits
in caller.
* script.cc (Symbol_assignment::sized_finalize): Update type,
visibility, and remaining st_other bits for new symbol.
* script.h: (Expression::eval_maybe_dot): Add type_pointer,
vis_pointer, and nonvis_pointer parameters.
* symtab.h (Symbol::set_type): New method.

* testsuite/Makefile.am (defsym_test): New test.
* testsuite/Makefile.in: Regenerate.
* testsuite/defsym_test.c: New file.
* testsuite/defsym_test.sh: New file.

gold/ChangeLog
gold/expression.cc
gold/script.cc
gold/script.h
gold/symtab.h
gold/testsuite/Makefile.am
gold/testsuite/Makefile.in
gold/testsuite/defsym_test.c [new file with mode: 0644]
gold/testsuite/defsym_test.sh [new file with mode: 0755]

index 0bd14e41805e83646c048e4fdf6797baa9b077ca..60d74719338c980389cc86aaaaaa597c7db194e2 100644 (file)
@@ -1,3 +1,22 @@
+2014-07-08  Cary Coutant  <ccoutant@google.com>
+
+       * expression.cc (struct Expression::Expression_eval_info): Add
+       new fields type_pointer, vis_pointer, and nonvis_pointer.
+       (Expression::eval_maybe_dot): Add type_pointer, vis_pointer, and
+       nonvis_pointer parameters. Adjust all calls.
+       (Symbol_expression::value): Update type, visibility, and nonvis bits
+       in caller.
+       * script.cc (Symbol_assignment::sized_finalize): Update type,
+       visibility, and remaining st_other bits for new symbol.
+       * script.h: (Expression::eval_maybe_dot): Add type_pointer,
+       vis_pointer, and nonvis_pointer parameters.
+       * symtab.h (Symbol::set_type): New method.
+
+       * testsuite/Makefile.am (defsym_test): New test.
+       * testsuite/Makefile.in: Regenerate.
+       * testsuite/defsym_test.c: New file.
+       * testsuite/defsym_test.sh: New file.
+
 2014-07-08  Cary Coutant  <ccoutant@google.com>
 
        PR gold/15639
index bdf52fade0d96ed8ff193cc397a5ac5dc689333f..61a3eaf17e4e5525b210f65c8640d3d5f8407021 100644 (file)
@@ -68,6 +68,12 @@ struct Expression::Expression_eval_info
   Output_section** result_section_pointer;
   // Pointer to where the alignment of the result should be stored.
   uint64_t* result_alignment_pointer;
+  // Pointer to where the type of the symbol on the RHS should be stored.
+  elfcpp::STT* type_pointer;
+  // Pointer to where the visibility of the symbol on the RHS should be stored.
+  elfcpp::STV* vis_pointer;
+  // Pointer to where the rest of the symbol's st_other field should be stored.
+  unsigned char* nonvis_pointer;
 };
 
 // Evaluate an expression.
@@ -76,8 +82,8 @@ uint64_t
 Expression::eval(const Symbol_table* symtab, const Layout* layout,
                 bool check_assertions)
 {
-  return this->eval_maybe_dot(symtab, layout, check_assertions,
-                             false, 0, NULL, NULL, NULL, false);
+  return this->eval_maybe_dot(symtab, layout, check_assertions, false, 0,
+                             NULL, NULL, NULL, NULL, NULL, NULL, false);
 }
 
 // Evaluate an expression which may refer to the dot symbol.
@@ -92,7 +98,7 @@ Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout,
 {
   return this->eval_maybe_dot(symtab, layout, check_assertions, true,
                              dot_value, dot_section, result_section_pointer,
-                             result_alignment_pointer,
+                             result_alignment_pointer, NULL, NULL, NULL,
                              is_section_dot_assignment);
 }
 
@@ -105,6 +111,9 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
                           uint64_t dot_value, Output_section* dot_section,
                           Output_section** result_section_pointer,
                           uint64_t* result_alignment_pointer,
+                          elfcpp::STT* type_pointer,
+                          elfcpp::STV* vis_pointer,
+                          unsigned char* nonvis_pointer,
                           bool is_section_dot_assignment)
 {
   Expression_eval_info eei;
@@ -121,6 +130,12 @@ Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout,
     *result_section_pointer = NULL;
   eei.result_section_pointer = result_section_pointer;
 
+  // For symbol=symbol assignments, we need to track the type, visibility,
+  // and remaining st_other bits.
+  eei.type_pointer = type_pointer;
+  eei.vis_pointer = vis_pointer;
+  eei.nonvis_pointer = nonvis_pointer;
+
   eei.result_alignment_pointer = result_alignment_pointer;
 
   uint64_t val = this->value(&eei);
@@ -196,6 +211,12 @@ Symbol_expression::value(const Expression_eval_info* eei)
 
   if (eei->result_section_pointer != NULL)
     *eei->result_section_pointer = sym->output_section();
+  if (eei->type_pointer != NULL)
+    *eei->type_pointer = sym->type();
+  if (eei->vis_pointer != NULL)
+    *eei->vis_pointer = sym->visibility();
+  if (eei->nonvis_pointer != NULL)
+    *eei->nonvis_pointer = sym->nonvis();
 
   if (parameters->target().get_size() == 32)
     return eei->symtab->get_sized_symbol<32>(sym)->value();
@@ -271,6 +292,9 @@ class Unary_expression : public Expression
                                      eei->dot_section,
                                      arg_section_pointer,
                                      eei->result_alignment_pointer,
+                                     NULL,
+                                     NULL,
+                                     NULL,
                                      false);
   }
 
@@ -351,6 +375,9 @@ class Binary_expression : public Expression
                                       eei->dot_section,
                                       section_pointer,
                                       alignment_pointer,
+                                      NULL,
+                                      NULL,
+                                      NULL,
                                       false);
   }
 
@@ -366,6 +393,9 @@ class Binary_expression : public Expression
                                        eei->dot_section,
                                        section_pointer,
                                        alignment_pointer,
+                                       NULL,
+                                       NULL,
+                                       NULL,
                                        false);
   }
 
@@ -517,6 +547,9 @@ class Trinary_expression : public Expression
                                       eei->dot_section,
                                       section_pointer,
                                       NULL,
+                                      NULL,
+                                      NULL,
+                                      NULL,
                                       false);
   }
 
@@ -532,6 +565,9 @@ class Trinary_expression : public Expression
                                       eei->dot_section,
                                       section_pointer,
                                       alignment_pointer,
+                                      NULL,
+                                      NULL,
+                                      NULL,
                                       false);
   }
 
@@ -547,6 +583,9 @@ class Trinary_expression : public Expression
                                       eei->dot_section,
                                       section_pointer,
                                       alignment_pointer,
+                                      NULL,
+                                      NULL,
+                                      NULL,
                                       false);
   }
 
index b4a6aff55b2196abccf7c3465fa2b5ea53a63422..eff9a81a6cefa611debeea73c30f4bedebc050c3 100644 (file)
@@ -980,12 +980,19 @@ Symbol_assignment::sized_finalize(Symbol_table* symtab, const Layout* layout,
                                  Output_section* dot_section)
 {
   Output_section* section;
+  elfcpp::STT type = elfcpp::STT_NOTYPE;
+  elfcpp::STV vis = elfcpp::STV_DEFAULT;
+  unsigned char nonvis = 0;
   uint64_t final_val = this->val_->eval_maybe_dot(symtab, layout, true,
                                                  is_dot_available,
                                                  dot_value, dot_section,
-                                                 &section, NULL, false);
+                                                 &section, NULL, &type,
+                                                 &vis, &nonvis, false);
   Sized_symbol<size>* ssym = symtab->get_sized_symbol<size>(this->sym_);
   ssym->set_value(final_val);
+  ssym->set_type(type);
+  ssym->set_visibility(vis);
+  ssym->set_nonvis(nonvis);
   if (section != NULL)
     ssym->set_output_section(section);
 }
@@ -1005,7 +1012,7 @@ Symbol_assignment::set_if_absolute(Symbol_table* symtab, const Layout* layout,
   uint64_t val = this->val_->eval_maybe_dot(symtab, layout, false,
                                            is_dot_available, dot_value,
                                            dot_section, &val_section, NULL,
-                                           false);
+                                           NULL, NULL, NULL, false);
   if (val_section != NULL && val_section != dot_section)
     return;
 
index 49b3776cf943661ea3b8fd50d2ae0c32015a9066..99bba08a1bae148ff0e70faf9adc565e8337c6ad 100644 (file)
@@ -34,6 +34,7 @@
 #include <string>
 #include <vector>
 
+#include "elfcpp.h"
 #include "script-sections.h"
 
 namespace gold
@@ -111,6 +112,7 @@ class Expression
                 bool is_dot_available, uint64_t dot_value,
                 Output_section* dot_section,
                 Output_section** result_section, uint64_t* result_alignment,
+                elfcpp::STT* type, elfcpp::STV* vis, unsigned char* nonvis,
                 bool is_section_dot_assignment);
 
   // Print the expression to the FILE.  This is for debugging.
index ab5b5f97d7fcafb0dfe49f9757baea4b18122749..7984dd6ff84af1ba30288a464cd4d01e14886d65 100644 (file)
@@ -215,6 +215,11 @@ class Symbol
   type() const
   { return this->type_; }
 
+  // Set the symbol type.
+  void
+  set_type(elfcpp::STT type)
+  { this->type_ = type; }
+
   // Return true for function symbol.
   bool
   is_func() const
index 379ac8a8f3b405e44c927cfa55010d3d6bc80d2d..5e1cd0d12d652da3de59c5b34b97174fc3900fb1 100644 (file)
@@ -2253,6 +2253,17 @@ ehdr_start_test_5_CXXFLAGS = -DEHDR_START_USER_DEF
 ehdr_start_test_5_LDFLAGS = -Bgcctestdir/
 ehdr_start_test_5_LDADD =
 
+# Test that the --defsym option copies the symbol type and visibility.
+check_SCRIPTS += defsym_test.sh
+check_DATA += defsym_test.syms
+MOSTLYCLEANFILES += defsym_test.syms
+defsym_test.syms: defsym_test
+       $(TEST_READELF) -sW $< > $@
+defsym_test: defsym_test.o gcctestdir/ld
+       $(LINK) -Bgcctestdir/ -Wl,--defsym=bar=foo defsym_test.o
+defsym_test.o: defsym_test.c
+       $(COMPILE) -c -o $@ $<
+
 # End-to-end incremental linking tests.
 # Incremental linking is currently supported only on the x86_64 target.
 
index 04a42e8dbbb3a42cbf6feb8192d2d0701a46048e..7d0f78b59590cdc834b77b9997511d3a17c92f9a 100644 (file)
@@ -568,9 +568,14 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 
 # Test that __ehdr_start is left undefined when the text segment is not
 # appropriately aligned.
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_70 = ehdr_start_test_4.sh
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_71 = ehdr_start_test_4.syms
-@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_72 = ehdr_start_test_4
+
+# Test that the --defsym option copies the symbol type and visibility.
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_70 = ehdr_start_test_4.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ defsym_test.sh
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_71 = ehdr_start_test_4.syms \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ defsym_test.syms
+@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_72 = ehdr_start_test_4 \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ defsym_test.syms
 @GCC_FALSE@ehdr_start_test_5_DEPENDENCIES =
 @NATIVE_LINKER_FALSE@ehdr_start_test_5_DEPENDENCIES =
 
@@ -4132,6 +4137,8 @@ gdb_index_test_4.sh.log: gdb_index_test_4.sh
        @p='gdb_index_test_4.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 ehdr_start_test_4.sh.log: ehdr_start_test_4.sh
        @p='ehdr_start_test_4.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+defsym_test.sh.log: defsym_test.sh
+       @p='defsym_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 script_test_10.sh.log: script_test_10.sh
        @p='script_test_10.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 split_i386.sh.log: split_i386.sh
@@ -5600,6 +5607,12 @@ uninstall-am:
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,-Ttext=0x100100 $<
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ehdr_start_test_4.o: ehdr_start_test.cc
 @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -DEHDR_START_WEAK -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@defsym_test.syms: defsym_test
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -sW $< > $@
+@GCC_TRUE@@NATIVE_LINKER_TRUE@defsym_test: defsym_test.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(LINK) -Bgcctestdir/ -Wl,--defsym=bar=foo defsym_test.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@defsym_test.o: defsym_test.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(COMPILE) -c -o $@ $<
 
 # End-to-end incremental linking tests.
 # Incremental linking is currently supported only on the x86_64 target.
diff --git a/gold/testsuite/defsym_test.c b/gold/testsuite/defsym_test.c
new file mode 100644 (file)
index 0000000..0bf68b2
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+void foo (void) __attribute__ ((noinline, visibility ("hidden")));
+
+void foo (void) {
+  printf("foo called.\n");
+}
+
+void bar(void);
+
+int main(void) {
+  foo();
+  bar();
+  return 0;
+}
diff --git a/gold/testsuite/defsym_test.sh b/gold/testsuite/defsym_test.sh
new file mode 100755 (executable)
index 0000000..e83fa9f
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+# defsym_test.sh -- test that --defsym copies type and visiblity.
+
+# Copyright (C) 2014 Free Software Foundation, Inc.
+# Written by Cary Coutant <ccoutant@google.com>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+check()
+{
+    if ! grep -q "$2" "$1"
+    then
+       echo "Did not find expected symbol in $1:"
+       echo "   $2"
+       echo ""
+       echo "Actual output below:"
+       cat "$1"
+       exit 1
+    fi
+}
+
+check defsym_test.syms "FUNC *GLOBAL *HIDDEN *[0-9]* *bar"
+
+exit 0