// output.cc -- manage the output file for gold
-// Copyright 2006, 2007, 2008 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
# define MAP_ANONYMOUS MAP_ANON
#endif
+#ifndef HAVE_POSIX_FALLOCATE
+// A dummy, non general, version of posix_fallocate. Here we just set
+// the file size and hope that there is enough disk space. FIXME: We
+// could allocate disk space by walking block by block and writing a
+// zero byte into each block.
+static int
+posix_fallocate(int o, off_t offset, off_t len)
+{
+ return ftruncate(o, offset + len);
+}
+#endif // !defined(HAVE_POSIX_FALLOCATE)
+
namespace gold
{
? elfcpp::ELFDATA2MSB
: elfcpp::ELFDATA2LSB);
e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT;
- // FIXME: Some targets may need to set EI_OSABI and EI_ABIVERSION.
oehdr.put_e_ident(e_ident);
elfcpp::ET e_type;
else
oehdr.put_e_shstrndx(elfcpp::SHN_XINDEX);
+ // Let the target adjust the ELF header, e.g., to set EI_OSABI in
+ // the e_ident field.
+ parameters->target().adjust_elf_header(view, ehdr_size);
+
of->write_output_view(0, ehdr_size, view);
}
gold_unreachable();
}
-// Return the output address of the start of the merged section for
+// Find the output address of the start of the merged section for
// input section SHNDX in object OBJECT.
-uint64_t
-Output_section::starting_output_address(const Relobj* object,
- unsigned int shndx) const
+bool
+Output_section::find_starting_output_address(const Relobj* object,
+ unsigned int shndx,
+ uint64_t* paddr) const
{
uint64_t addr = this->address() + this->first_input_offset_;
for (Input_section_list::const_iterator p = this->input_sections_.begin();
// Unfortunately we don't know for sure that input offset 0 is
// mapped at all.
if (p->is_merge_section_for(object, shndx))
- return addr;
+ {
+ *paddr = addr;
+ return true;
+ }
addr += p->data_size();
}
- gold_unreachable();
+
+ // We couldn't find a merge output section for this input section.
+ return false;
}
// Set the data size of an Output_section. This is where we handle
}
}
+// Map a block of memory which will later be written to the file.
+// Return a pointer to the memory.
+
+void*
+Output_file::map_anonymous()
+{
+ this->map_is_anonymous_ = true;
+ return ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+}
+
// Map the file into memory.
void
|| ::fstat(o, &statbuf) != 0
|| !S_ISREG(statbuf.st_mode)
|| this->is_temporary_)
- {
- this->map_is_anonymous_ = true;
- base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- }
+ base = this->map_anonymous();
else
{
- // Write out one byte to make the file the right size.
- if (::lseek(o, this->file_size_ - 1, SEEK_SET) < 0)
- gold_fatal(_("%s: lseek: %s"), this->name_, strerror(errno));
- char b = 0;
- if (::write(o, &b, 1) != 1)
- gold_fatal(_("%s: write: %s"), this->name_, strerror(errno));
+ // Ensure that we have disk space available for the file. If we
+ // don't do this, it is possible that we will call munmap,
+ // close, and exit with dirty buffers still in the cache with no
+ // assigned disk blocks. If the disk is out of space at that
+ // point, the output file will wind up incomplete, but we will
+ // have already exited. The alternative to fallocate would be
+ // to use fdatasync, but that would be a more significant
+ // performance hit.
+ if (::posix_fallocate(o, 0, this->file_size_) < 0)
+ gold_fatal(_("%s: %s"), this->name_, strerror(errno));
// Map the file into memory.
this->map_is_anonymous_ = false;
base = ::mmap(NULL, this->file_size_, PROT_READ | PROT_WRITE,
MAP_SHARED, o, 0);
+
+ // The mmap call might fail because of file system issues: the
+ // file system might not support mmap at all, or it might not
+ // support mmap with PROT_WRITE. I'm not sure which errno
+ // values we will see in all cases, so if the mmap fails for any
+ // reason try for an anonymous map.
+ if (base == MAP_FAILED)
+ base = this->map_anonymous();
}
if (base == MAP_FAILED)
- gold_fatal(_("%s: mmap: %s"), this->name_, strerror(errno));
+ gold_fatal(_("%s: mmap: failed to allocate %lu bytes for output file: %s"),
+ this->name_, static_cast<unsigned long>(this->file_size_),
+ strerror(errno));
this->base_ = static_cast<unsigned char*>(base);
}
if (this->map_is_anonymous_ && !this->is_temporary_)
{
size_t bytes_to_write = this->file_size_;
+ size_t offset = 0;
while (bytes_to_write > 0)
{
- ssize_t bytes_written = ::write(this->o_, this->base_, bytes_to_write);
+ ssize_t bytes_written = ::write(this->o_, this->base_ + offset,
+ bytes_to_write);
if (bytes_written == 0)
gold_error(_("%s: write: unexpected 0 return-value"), this->name_);
else if (bytes_written < 0)
gold_error(_("%s: write: %s"), this->name_, strerror(errno));
else
- bytes_to_write -= bytes_written;
+ {
+ bytes_to_write -= bytes_written;
+ offset += bytes_written;
+ }
}
}
this->unmap();
bool have_sections_script);
#endif
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, false, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, false, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, false, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, false, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_REL, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_REL, true, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, false, 64, true>;
+#endif
+
+#ifdef HAVE_TARGET_32_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 32, false>;
+#endif
+
+#ifdef HAVE_TARGET_32_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 32, true>;
+#endif
+
+#ifdef HAVE_TARGET_64_LITTLE
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 64, false>;
+#endif
+
+#ifdef HAVE_TARGET_64_BIG
+template
+class Output_reloc<elfcpp::SHT_RELA, true, 64, true>;
+#endif
+
#ifdef HAVE_TARGET_32_LITTLE
template
class Output_data_reloc<elfcpp::SHT_REL, false, 32, false>;