From 62f41fd5572655d6444c572d407fb604413ce11a Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Tue, 26 Jul 2016 21:23:29 +0700 Subject: [PATCH] Set LMA and file offset --- gold/output.cc | 21 ++++++++---- gold/output.h | 4 +-- gold/script-sections.cc | 28 +++++++++++---- gold/testsuite/Makefile.am | 11 ++++++ gold/testsuite/Makefile.in | 18 ++++++++-- gold/testsuite/pr20280.s | 4 +++ gold/testsuite/pr20280.sh | 85 ++++++++++++++++++++++++++++++++++++++++++++++ gold/testsuite/pr20280.t | 7 ++++ 8 files changed, 159 insertions(+), 19 deletions(-) create mode 100644 gold/testsuite/pr20280.s create mode 100755 gold/testsuite/pr20280.sh create mode 100644 gold/testsuite/pr20280.t diff --git a/gold/output.cc b/gold/output.cc index 0a9e58f..cd1858a 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -4381,6 +4381,7 @@ Output_segment::set_section_addresses(const Target* target, *poff = off; } + uint64_t paddr = addr; if (!reset && this->are_addresses_set_) { gold_assert(this->paddr_ == addr); @@ -4405,6 +4406,7 @@ Output_segment::set_section_addresses(const Target* target, { *poff += last_relro_pad; addr += last_relro_pad; + paddr += last_relro_pad; if (this->output_lists_[i].empty()) { // If there is nothing in the ORDER_RELRO_LAST list, @@ -4413,9 +4415,11 @@ Output_segment::set_section_addresses(const Target* target, *increase_relro += last_relro_pad; } } - addr = this->set_section_list_addresses(layout, reset, - &this->output_lists_[i], - addr, poff, pshndx, &in_tls); + uint64_t new_addr = this->set_section_list_addresses( + layout, reset, &this->output_lists_[i], addr, paddr, poff, pshndx, + &in_tls); + paddr += new_addr - addr; + addr = new_addr; if (i < static_cast(ORDER_SMALL_BSS)) { this->filesz_ = *poff - orig_off; @@ -4484,8 +4488,8 @@ Output_segment::set_section_addresses(const Target* target, uint64_t Output_segment::set_section_list_addresses(Layout* layout, bool reset, Output_data_list* pdl, - uint64_t addr, off_t* poff, - unsigned int* pshndx, + uint64_t addr, uint64_t paddr, + off_t* poff, unsigned int* pshndx, bool* in_tls) { off_t startoff = *poff; @@ -4578,8 +4582,11 @@ Output_segment::set_section_list_addresses(Layout* layout, bool reset, { // The script may have inserted a skip forward, but it // better not have moved backward. - if ((*p)->address() >= addr + (off - startoff)) - off += (*p)->address() - (addr + (off - startoff)); + uint64_t laddr = (*p)->has_load_address() + ? (*p)->load_address() + : (*p)->address(); + if (laddr >= paddr + (off - startoff)) + off += laddr - (paddr + (off - startoff)); else { if (!layout->script_options()->saw_sections_clause()) diff --git a/gold/output.h b/gold/output.h index d8a8aaa..09619ae 100644 --- a/gold/output.h +++ b/gold/output.h @@ -4844,8 +4844,8 @@ class Output_segment // Set the section addresses in an Output_data_list. uint64_t set_section_list_addresses(Layout*, bool reset, Output_data_list*, - uint64_t addr, off_t* poff, unsigned int* pshndx, - bool* in_tls); + uint64_t addr, uint64_t paddr, off_t* poff, + unsigned int* pshndx, bool* in_tls); // Return the number of Output_sections in an Output_data_list. unsigned int diff --git a/gold/script-sections.cc b/gold/script-sections.cc index 96c68de..e094c5c 100644 --- a/gold/script-sections.cc +++ b/gold/script-sections.cc @@ -739,9 +739,10 @@ class Sections_element_dot_assignment : public Sections_element uint64_t* dot_value, uint64_t* dot_alignment, uint64_t* load_address) { + uint64_t old_dot_value = *dot_value; *dot_value = this->val_->eval_with_dot(symtab, layout, false, *dot_value, NULL, NULL, dot_alignment, false); - *load_address = *dot_value; + *load_address += *dot_value - old_dot_value; } // Print for debugging. @@ -2528,11 +2529,22 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, } else { - // Do not set the load address of the output section, if one exists. - // This allows future sections to determine what the load address - // should be. If none is ever set, it will default to being the - // same as the vma address. - laddr = address; + // If the VMA isn't set explicitly, then the LMA should be set so + // that the difference between the VMA and LMA is the same as + // the difference between the VMA and LMA of the last section. See + // https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html#Output-Section-LMA. + if (this->address_ == NULL && old_load_address != old_dot_value) + { + laddr = old_load_address + (address - old_dot_value); + if (this->output_section_ != NULL) + this->output_section_->set_load_address(laddr); + } + else + // Do not set the load address of the output section, if one exists. + // This allows future sections to determine what the load address + // should be. If none is ever set, it will default to being the + // same as the vma address. + laddr = address; } } else @@ -2626,7 +2638,9 @@ Output_section_definition::set_section_addresses(Symbol_table* symtab, // Compute the load address for the following section. if (this->output_section_ == NULL) *load_address = *dot_value; - else if (this->load_address_ == NULL) + else if (this->load_address_ == NULL + && (lma_region != NULL + || !this->output_section_->has_load_address())) { if (lma_region == NULL) *load_address = *dot_value; diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index 39f9e9e..5060174 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -2991,6 +2991,17 @@ script_test_10: $(srcdir)/script_test_10.t script_test_10.o gcctestdir/ld script_test_10.stdout: script_test_10 $(TEST_READELF) -SW script_test_10 > $@ +# Test LMA assignment for subsequent sections. +check_SCRIPTS += pr20280.sh +check_DATA += pr20280.stdout +MOSTLYCLEANFILES += pr20280 +pr20280.o: pr20280.s + $(TEST_AS) -o $@ $< +pr20280: $(srcdir)/pr20280.t pr20280.o gcctestdir/ld + gcctestdir/ld -o $@ pr20280.o -T $(srcdir)/pr20280.t +pr20280.stdout: pr20280 + $(TEST_READELF) -lSW $< > $@ + # These tests work with cross linkers only. if DEFAULT_TARGET_I386 diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index bd58d13..f09a7ee 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -769,9 +769,13 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ # These tests work with native and cross linkers. # Test script section order. -@NATIVE_OR_CROSS_LINKER_TRUE@am__append_79 = script_test_10.sh -@NATIVE_OR_CROSS_LINKER_TRUE@am__append_80 = script_test_10.stdout -@NATIVE_OR_CROSS_LINKER_TRUE@am__append_81 = script_test_10 + +# Test LMA assignment for subsequent sections. +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_79 = script_test_10.sh \ +@NATIVE_OR_CROSS_LINKER_TRUE@ pr20280.sh +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_80 = script_test_10.stdout \ +@NATIVE_OR_CROSS_LINKER_TRUE@ pr20280.stdout +@NATIVE_OR_CROSS_LINKER_TRUE@am__append_81 = script_test_10 pr20280 # These tests work with cross linkers only. @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_82 = split_i386.sh @@ -5115,6 +5119,8 @@ 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) +pr20280.sh.log: pr20280.sh + @p='pr20280.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) split_i386.sh.log: split_i386.sh @p='split_i386.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) split_x86_64.sh.log: split_x86_64.sh @@ -7105,6 +7111,12 @@ uninstall-am: @NATIVE_OR_CROSS_LINKER_TRUE@ gcctestdir/ld -o $@ script_test_10.o -T $(srcdir)/script_test_10.t @NATIVE_OR_CROSS_LINKER_TRUE@script_test_10.stdout: script_test_10 @NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -SW script_test_10 > $@ +@NATIVE_OR_CROSS_LINKER_TRUE@pr20280.o: pr20280.s +@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $< +@NATIVE_OR_CROSS_LINKER_TRUE@pr20280: $(srcdir)/pr20280.t pr20280.o gcctestdir/ld +@NATIVE_OR_CROSS_LINKER_TRUE@ gcctestdir/ld -o $@ pr20280.o -T $(srcdir)/pr20280.t +@NATIVE_OR_CROSS_LINKER_TRUE@pr20280.stdout: pr20280 +@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_READELF) -lSW $< > $@ @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_1.o: split_i386_1.s @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@ $(TEST_AS) -o $@ $< @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_i386_2.o: split_i386_2.s diff --git a/gold/testsuite/pr20280.s b/gold/testsuite/pr20280.s new file mode 100644 index 0000000..2dc5115 --- /dev/null +++ b/gold/testsuite/pr20280.s @@ -0,0 +1,4 @@ +.text + nop +.data + .word 123 diff --git a/gold/testsuite/pr20280.sh b/gold/testsuite/pr20280.sh new file mode 100755 index 0000000..b30da44 --- /dev/null +++ b/gold/testsuite/pr20280.sh @@ -0,0 +1,85 @@ +#!/bin/sh + +# pr20280.sh -- test LMA assignment for subsequent sections + +# Copyright (C) 2016 Free Software Foundation, Inc. +# Written by Igor Kudrin . + +# 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. + +file="pr20280.stdout" + +get_section_vaddr() +{ + section=$1 + var=$2 + pattern="\s$section\s+\w+\s+\K[\d\w]+" + found=`grep -oP "$pattern" "$file"` + if test -z "$found"; then + echo "Section \"$section\" not found." + echo "Search pattern: $pattern" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 + fi + eval $var="0x$found" +} + +get_section_paddr() +{ + section=$1 + var=$2 + vaddr=$3 + segment_index=`awk '/Segment Sections.../,0' "$file" | fgrep "$section" | awk '{ print $1 }'` + if test -z "$segment_index"; then + echo "Couldn't find the segment for section \"$section\"." + echo "" + echo "Actual output below:" + cat "$file" + exit 1 + fi + segment_props="`awk '/Program Headers/{x = NR + '$(($segment_index + 2))'}NR == x' \"$file\"`" + if test -z "$segment_props"; then + echo "Couldn't find the segment for section \"$section\"." + echo "Segment index: $(($segment_index))" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 + fi + segment_vaddr="`echo "$segment_props" | awk '{ print $3 }'`" + segment_paddr="`echo "$segment_props" | awk '{ print $4 }'`" + eval $var="`printf "0x%x\n" $(($vaddr - $segment_vaddr + $segment_paddr))`" +} + +get_section_vaddr .text text_vaddr +get_section_paddr .text text_paddr $text_vaddr + +get_section_vaddr .data data_vaddr +get_section_paddr .data data_paddr $data_vaddr + +if test "$(($text_paddr - $text_vaddr))" -ne "$(($data_paddr - $data_vaddr))"; then + echo "The difference between VMA and LMA for both .text and .data should be the same." + echo ".text VMA=$text_vaddr LMA=$text_paddr" + echo ".data VMA=$data_vaddr LMA=$data_paddr" + echo "" + echo "Actual output below:" + cat "$file" + exit 1 +fi diff --git a/gold/testsuite/pr20280.t b/gold/testsuite/pr20280.t new file mode 100644 index 0000000..41420a8 --- /dev/null +++ b/gold/testsuite/pr20280.t @@ -0,0 +1,7 @@ +SECTIONS +{ + .text : AT(0x1000000) { *(.text) } + .data : { *(.data) } + + /DISCARD/ : { *(.note*) } +} -- 1.9.5.msysgit.1