// output.cc -- manage the output file for gold
-// Copyright 2006, 2007 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
const unsigned int lsi = this->local_sym_index_;
section_offset_type offset;
Output_section* os = this->u1_.relobj->output_section(lsi, &offset);
- gold_assert(os != NULL);
+ gold_assert(os != NULL && offset != -1);
return offset;
}
template<bool dynamic, int size, bool big_endian>
typename elfcpp::Elf_types<size>::Elf_Addr
-Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value() const
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::symbol_value(
+ Address addend) const
{
if (this->local_sym_index_ == GSYM_CODE)
{
const Sized_symbol<size>* sym;
sym = static_cast<const Sized_symbol<size>*>(this->u1_.gsym);
- return sym->value();
+ return sym->value() + addend;
}
gold_assert(this->local_sym_index_ != SECTION_CODE
- && this->local_sym_index_ != INVALID_CODE);
- const Sized_relobj<size, big_endian>* relobj = this->u1_.relobj;
- return relobj->local_symbol_value(this->local_sym_index_);
+ && this->local_sym_index_ != INVALID_CODE
+ && !this->is_section_symbol_);
+ const unsigned int lsi = this->local_sym_index_;
+ const Symbol_value<size>* symval = this->u1_.relobj->local_symbol(lsi);
+ return symval->value(this->u1_.relobj, addend);
}
// Write out a Rela relocation.
this->rel_.write_rel(&orel);
Addend addend = this->addend_;
if (this->rel_.is_relative())
- addend += this->rel_.symbol_value();
- if (this->rel_.is_local_section_symbol())
+ addend = this->rel_.symbol_value(addend);
+ else if (this->rel_.is_local_section_symbol())
addend += this->rel_.local_section_offset();
orel.put_r_addend(addend);
}
break;
default:
- val = this->u_.object->local_symbol_value(this->local_sym_index_);
+ {
+ const unsigned int lsi = this->local_sym_index_;
+ const Symbol_value<size>* symval = this->u_.object->local_symbol(lsi);
+ val = symval->value(this->u_.object, 0);
+ }
break;
}
void
Output_data_dynamic::Dynamic_entry::write(
unsigned char* pov,
- const Stringpool* pool
- ACCEPT_SIZE_ENDIAN) const
+ const Stringpool* pool) const
{
typename elfcpp::Elf_types<size>::Elf_WXword val;
switch (this->classification_)
p != this->entries_.end();
++p)
{
- p->write SELECT_SIZE_ENDIAN_NAME(size, big_endian)(
- pov, this->pool_ SELECT_SIZE_ENDIAN(size, big_endian));
+ p->write<size, big_endian>(pov, this->pool_);
pov += dyn_size;
}
pdl->push_back(os);
}
+// Remove an Output_section from this segment. It is an error if it
+// is not present.
+
+void
+Output_segment::remove_output_section(Output_section* os)
+{
+ // We only need this for SHT_PROGBITS.
+ gold_assert(os->type() == elfcpp::SHT_PROGBITS);
+ for (Output_data_list::iterator p = this->output_data_.begin();
+ p != this->output_data_.end();
+ ++p)
+ {
+ if (*p == os)
+ {
+ this->output_data_.erase(p);
+ return;
+ }
+ }
+ gold_unreachable();
+}
+
// Add an Output_data (which is not an Output_section) to the start of
// a segment.
// *POFF and *PSHNDX.
uint64_t
-Output_segment::set_section_addresses(bool reset, uint64_t addr, off_t* poff,
+Output_segment::set_section_addresses(const Layout* layout, bool reset,
+ uint64_t addr, off_t* poff,
unsigned int* pshndx)
{
gold_assert(this->type_ == elfcpp::PT_LOAD);
this->are_addresses_set_ = true;
}
+ bool in_tls = false;
+
off_t orig_off = *poff;
this->offset_ = orig_off;
- addr = this->set_section_list_addresses(reset, &this->output_data_,
- addr, poff, pshndx);
+ addr = this->set_section_list_addresses(layout, reset, &this->output_data_,
+ addr, poff, pshndx, &in_tls);
this->filesz_ = *poff - orig_off;
off_t off = *poff;
- uint64_t ret = this->set_section_list_addresses(reset, &this->output_bss_,
- addr, poff, pshndx);
+ uint64_t ret = this->set_section_list_addresses(layout, reset,
+ &this->output_bss_,
+ addr, poff, pshndx,
+ &in_tls);
+
+ // If the last section was a TLS section, align upward to the
+ // alignment of the TLS segment, so that the overall size of the TLS
+ // segment is aligned.
+ if (in_tls)
+ {
+ uint64_t segment_align = layout->tls_segment()->maximum_alignment();
+ *poff = align_address(*poff, segment_align);
+ }
+
this->memsz_ = *poff - orig_off;
// Ignore the file offset adjustments made by the BSS Output_data
// structures.
uint64_t
-Output_segment::set_section_list_addresses(bool reset, Output_data_list* pdl,
+Output_segment::set_section_list_addresses(const Layout* layout, bool reset,
+ Output_data_list* pdl,
uint64_t addr, off_t* poff,
- unsigned int* pshndx)
+ unsigned int* pshndx,
+ bool* in_tls)
{
off_t startoff = *poff;
// already have an address.
if (!(*p)->is_address_valid())
{
- off = align_address(off, (*p)->addralign());
+ uint64_t align = (*p)->addralign();
+
+ if ((*p)->is_section_flag_set(elfcpp::SHF_TLS))
+ {
+ // Give the first TLS section the alignment of the
+ // entire TLS segment. Otherwise the TLS segment as a
+ // whole may be misaligned.
+ if (!*in_tls)
+ {
+ Output_segment* tls_segment = layout->tls_segment();
+ gold_assert(tls_segment != NULL);
+ uint64_t segment_align = tls_segment->maximum_alignment();
+ gold_assert(segment_align >= align);
+ align = segment_align;
+
+ *in_tls = true;
+ }
+ }
+ else
+ {
+ // If this is the first section after the TLS segment,
+ // align it to at least the alignment of the TLS
+ // segment, so that the size of the overall TLS segment
+ // is aligned.
+ if (*in_tls)
+ {
+ uint64_t segment_align =
+ layout->tls_segment()->maximum_alignment();
+ if (segment_align > align)
+ align = segment_align;
+
+ *in_tls = false;
+ }
+ }
+
+ off = align_address(off, align);
(*p)->set_address_and_file_offset(addr + (off - startoff), off);
}
else
(*p)->finalize_data_size();
}
- // Unless this is a PT_TLS segment, we want to ignore the size
- // of a SHF_TLS/SHT_NOBITS section. Such a section does not
- // affect the size of a PT_LOAD segment.
- if (this->type_ == elfcpp::PT_TLS
- || !(*p)->is_section_flag_set(elfcpp::SHF_TLS)
+ // We want to ignore the size of a SHF_TLS or SHT_NOBITS
+ // section. Such a section does not affect the size of a
+ // PT_LOAD segment.
+ if (!(*p)->is_section_flag_set(elfcpp::SHF_TLS)
|| !(*p)->is_section_type(elfcpp::SHT_NOBITS))
off += (*p)->data_size();
this->memsz_ = (last->address()
+ last->data_size()
- this->vaddr_);
+
+ // If this is a TLS segment, align the memory size. The code in
+ // set_section_list ensures that the section after the TLS segment
+ // is aligned to give us room.
+ if (this->type_ == elfcpp::PT_TLS)
+ {
+ uint64_t segment_align = this->maximum_alignment();
+ gold_assert(this->vaddr_ == align_address(this->vaddr_, segment_align));
+ this->memsz_ = align_address(this->memsz_, segment_align);
+ }
}
// Set the TLS offsets of the sections in the PT_TLS segment.
Output_segment::write_section_headers(const Layout* layout,
const Stringpool* secnamepool,
unsigned char* v,
- unsigned int *pshndx
- ACCEPT_SIZE_ENDIAN) const
+ unsigned int *pshndx) const
{
// Every section that is attached to a segment must be attached to a
// PT_LOAD segment, so we only write out section headers for PT_LOAD
if (this->type_ != elfcpp::PT_LOAD)
return v;
- v = this->write_section_headers_list
- SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- layout, secnamepool, &this->output_data_, v, pshndx
- SELECT_SIZE_ENDIAN(size, big_endian));
- v = this->write_section_headers_list
- SELECT_SIZE_ENDIAN_NAME(size, big_endian) (
- layout, secnamepool, &this->output_bss_, v, pshndx
- SELECT_SIZE_ENDIAN(size, big_endian));
+ v = this->write_section_headers_list<size, big_endian>(layout, secnamepool,
+ &this->output_data_,
+ v, pshndx);
+ v = this->write_section_headers_list<size, big_endian>(layout, secnamepool,
+ &this->output_bss_,
+ v, pshndx);
return v;
}
const Stringpool* secnamepool,
const Output_data_list* pdl,
unsigned char* v,
- unsigned int* pshndx
- ACCEPT_SIZE_ENDIAN) const
+ unsigned int* pshndx) const
{
const int shdr_size = elfcpp::Elf_sizes<size>::shdr_size;
for (Output_data_list::const_iterator p = pdl->begin();