+2013-04-29 Alexander Ivchenko <alexander.ivchenko@intel.com>
+
+ * output.cc (Output_section::add_merge_input_section): Allow
+ to merge sections if the alignment is more than character size.
+ * merge.h (Output_merge_string::Output_merge_string): Remove
+ assert.
+ * merge.cc (Output_merge_string<Char_type>::do_add_input_section): Count
+ only not-null strings. Check the alignment of strings.
+ * stringpool.h
+ (Stringpool_template<Stringpool_char>::Stringpool_template): Add
+ alignment as the argument.
+ (Stringpool_template<Stringpool_char>::addralign_): New class member.
+ * stringpool.cc (Stringpool_template<Stringpool_char>::new_key_offset):
+ Align non-zero length strings according to the addralign_.
+ (Stringpool_template<Stringpool_char>::set_string_offsets):
+ Updating offsets according to the given alignment.
+ * testsuite/Makefile.am (text_section_grouping): Test if string
+ literals are getting merged.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/merge_string_literals_1.c: New file.
+ * testsuite/merge_string_literals_2.c: Ditto.
+ * testsuite/merge_string_literals.sh: Ditto.
+
2013-04-26 Ian Lance Taylor <iant@google.com>
* target-reloc.h (relocate_section): If the reloc offset is out of
this->merged_strings_lists_.push_back(merged_strings_list);
Merged_strings& merged_strings = merged_strings_list->merged_strings;
- // Count the number of strings in the section and size the list.
+ // Count the number of non-null strings in the section and size the list.
size_t count = 0;
- for (const Char_type* pt = p; pt < pend0; pt += string_length(pt) + 1)
- ++count;
+ for (const Char_type* pt = p, len = string_length(pt);
+ pt < pend0;
+ pt += len + 1)
+ if (len != 0)
+ ++count;
if (pend0 < pend)
++count;
merged_strings.reserve(count + 1);
// The index I is in bytes, not characters.
section_size_type i = 0;
+
+ // We assume here that the beginning of the section is correctly
+ // aligned, so each string within the section must retain the same
+ // modulo.
+ uintptr_t init_align_modulo = (reinterpret_cast<uintptr_t>(pdata)
+ & (this->addralign() - 1));
+ bool has_misaligned_strings = false;
+
while (p < pend0)
{
size_t len = string_length(p);
- Stringpool::Key key;
- this->stringpool_.add_with_length(p, len, true, &key);
+ if (len != 0)
+ {
+ // Within merge input section each string must be aligned.
+ if ((reinterpret_cast<uintptr_t>(p) & (this->addralign() - 1))
+ != init_align_modulo)
+ has_misaligned_strings = true;
- merged_strings.push_back(Merged_string(i, key));
+ Stringpool::Key key;
+ this->stringpool_.add_with_length(p, len, true, &key);
+ merged_strings.push_back(Merged_string(i, key));
+ }
p += len + 1;
i += (len + 1) * sizeof(Char_type);
}
this->input_count_ += count;
this->input_size_ += len;
+ if (has_misaligned_strings)
+ gold_warning(_("%s: section %s contains incorrectly aligned strings;"
+ " the alignment of those strings won't be preserved"),
+ object->name().c_str(),
+ object->section_name(shndx).c_str());
+
// For script processing, we keep the input sections.
if (this->keeps_input_sections())
record_input_section(object, shndx);
{
public:
Output_merge_string(uint64_t addralign)
- : Output_merge_base(sizeof(Char_type), addralign), stringpool_(),
+ : Output_merge_base(sizeof(Char_type), addralign), stringpool_(addralign),
merged_strings_lists_(), input_count_(0), input_size_(0)
{
- gold_assert(addralign <= sizeof(Char_type));
this->stringpool_.set_no_zero_null();
}
{
bool is_string = (flags & elfcpp::SHF_STRINGS) != 0;
- // We only merge strings if the alignment is not more than the
- // character size. This could be handled, but it's unusual.
- if (is_string && addralign > entsize)
- return false;
-
// We cannot restore merged input section states.
gold_assert(this->checkpoint_ == NULL);
{
template<typename Stringpool_char>
-Stringpool_template<Stringpool_char>::Stringpool_template()
+Stringpool_template<Stringpool_char>::Stringpool_template(uint64_t addralign)
: string_set_(), key_to_offset_(), strings_(), strtab_size_(0),
- zero_null_(true), optimize_(false), offset_(sizeof(Stringpool_char))
+ zero_null_(true), optimize_(false), offset_(sizeof(Stringpool_char)),
+ addralign_(addralign)
{
if (parameters->options_valid() && parameters->options().optimize() >= 2)
this->optimize_ = true;
offset = 0;
else
{
- offset = this->offset_;
- this->offset_ += (length + 1) * sizeof(Stringpool_char);
+ // Align non-zero length strings.
+ if (length != 0)
+ offset = align_address(this->offset_, this->addralign_);
+ this->offset_ = offset + (length + 1) * sizeof(Stringpool_char);
}
this->key_to_offset_.push_back(offset);
}
* charsize));
else
{
- this_offset = offset;
- offset += ((*curr)->first.length + 1) * charsize;
+ this_offset = align_address(offset, this->addralign_);
+ offset = this_offset + ((*curr)->first.length + 1) * charsize;
}
this->key_to_offset_[(*curr)->second - 1] = this_offset;
last_offset = this_offset;
typedef size_t Key;
// Create a Stringpool.
- Stringpool_template();
+ Stringpool_template(uint64_t addralign = 1);
~Stringpool_template();
bool optimize_;
// offset of the next string.
section_offset_type offset_;
+ // The alignment of strings in the stringpool.
+ uint64_t addralign_;
};
// The most common type of Stringpool.
icf_sht_rel_addend_test.stdout: icf_sht_rel_addend_test
$(TEST_NM) icf_sht_rel_addend_test > icf_sht_rel_addend_test.stdout
+check_SCRIPTS += merge_string_literals.sh
+check_DATA += merge_string_literals.stdout
+MOSTLYCLEANFILES += merge_string_literals
+merge_string_literals_1.o: merge_string_literals_1.c
+ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+merge_string_literals_2.o: merge_string_literals_2.c
+ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+merge_string_literals: merge_string_literals_1.o merge_string_literals_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ merge_string_literals_1.o merge_string_literals_2.o -O2 -shared -nostdlib
+merge_string_literals.stdout: merge_string_literals
+ $(TEST_OBJDUMP) -s -j.rodata merge_string_literals > merge_string_literals.stdout
+
check_PROGRAMS += basic_test
check_PROGRAMS += basic_pic_test
basic_test.o: basic_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test.sh \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.sh weak_plt.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.sh undef_symbol.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.sh ver_test_2.sh \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test.stdout \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals.stdout \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so debug_msg.err
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = incremental_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_sht_rel_addend_test \
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ merge_string_literals \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \
@GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/weak_undef_lib.so
@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_5 = icf_virtual_function_folding_test \
@p='icf_string_merge_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
icf_sht_rel_addend_test.sh.log: icf_sht_rel_addend_test.sh
@p='icf_sht_rel_addend_test.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+merge_string_literals.sh.log: merge_string_literals.sh
+ @p='merge_string_literals.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
two_file_shared.sh.log: two_file_shared.sh
@p='two_file_shared.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
weak_plt.sh.log: weak_plt.sh
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_sht_rel_addend_test_1.o icf_sht_rel_addend_test_2.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_sht_rel_addend_test.stdout: icf_sht_rel_addend_test
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_sht_rel_addend_test > icf_sht_rel_addend_test.stdout
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals_1.o: merge_string_literals_1.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals_2.o: merge_string_literals_2.c
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O2 -c -fPIC -g -o $@ $<
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals: merge_string_literals_1.o merge_string_literals_2.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ merge_string_literals_1.o merge_string_literals_2.o -O2 -shared -nostdlib
+@GCC_TRUE@@NATIVE_LINKER_TRUE@merge_string_literals.stdout: merge_string_literals
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_OBJDUMP) -s -j.rodata merge_string_literals > merge_string_literals.stdout
@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test: basic_test.o gcctestdir/ld
--- /dev/null
+#!/bin/sh
+
+# merge_string_literals.sh -- test
+
+# Copyright 2013 Free Software Foundation, Inc.
+# Written by Alexander Ivchenko <alexander.ivchenko@intel.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.
+
+# The goal of this program is to check whether string literals from different
+# object files are merged together
+
+set -e
+
+check()
+{
+ number_of_occurrence=`grep $2 ./$1 -o| wc -l`
+ if [ $number_of_occurrence != $3 ]
+ then
+ echo "String literals were not merged"
+ exit 1
+ fi
+}
+
+# If string literals were merged, then "abcd" appears two times
+check merge_string_literals.stdout "abcd" 2
--- /dev/null
+// merge_string_literals_1.c -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Alexander Ivchenko <alexander.ivchenko@intel.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.
+
+// The goal of this program is to check whether string literals from different
+// object files are merged together
+
+const char* bar1() {
+ return "abcdefghijklmnopqrstuvwxyz0123456789";
+}
+const char* bar1_short() {
+ return "abcdef";
+}
--- /dev/null
+// merge_string_literals_2.c -- a test case for gold
+
+// Copyright 2013 Free Software Foundation, Inc.
+// Written by Alexander Ivchenko <alexander.ivchenko@intel.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.
+
+// The goal of this program is to check whether string literals from different
+// object files are merged together
+
+const char* bar2() {
+ return "abcdefghijklmnopqrstuvwxyz0123456789";
+}
+const char* bar2_short() {
+ return "abcdef";
+}