* descriptors.cc: New file.
* descriptors.h: New file.
* gold-threads.h (class Hold_optional_lock): New class.
* fileread.cc: Include "descriptors.h".
(File_read::~File_read): Release descriptor rather than closing
it.
(File_read::open) [file]: Call open_descriptor rather than open.
Set is_descriptor_opened_.
(File_read::open) [memory]: Assert that descriptor is not open.
(File_read::reopen_descriptor): New function.
(File_read::release): Release descriptor.
(File_read::do_read): Make non-const. Reopen descriptor.
(File_read::read): Make non-const.
(File_read::make_view): Reopen descriptor.
(File_read::do_readv): Likewise.
* fileread.h (class File_read): Add is_descriptor_opened_ field.
Update declarations.
* layout.cc: Include "descriptors.h".
(Layout::create_build_id): Use open_descriptor rather than open.
* output.cc: Include "descriptors.h".
(Output_file::open): Use open_descriptor rather than open.
* archive.cc (Archive::const_iterator): Change Archive to be
non-const.
(Archive::begin, Archive::end): Make non-const.
(Archive::count_members): Likewise.
* archive.h (class Archive): Update declarations.
* object.h (Object::read): Make non-const.
* Makefile.am (CCFILES): Add descriptors.cc.
(HFILES): Add descriptors.h.
* Makefile.in: Rebuild.
2008-07-24 Ian Lance Taylor <iant@google.com>
+ PR 5990
+ * descriptors.cc: New file.
+ * descriptors.h: New file.
+ * gold-threads.h (class Hold_optional_lock): New class.
+ * fileread.cc: Include "descriptors.h".
+ (File_read::~File_read): Release descriptor rather than closing
+ it.
+ (File_read::open) [file]: Call open_descriptor rather than open.
+ Set is_descriptor_opened_.
+ (File_read::open) [memory]: Assert that descriptor is not open.
+ (File_read::reopen_descriptor): New function.
+ (File_read::release): Release descriptor.
+ (File_read::do_read): Make non-const. Reopen descriptor.
+ (File_read::read): Make non-const.
+ (File_read::make_view): Reopen descriptor.
+ (File_read::do_readv): Likewise.
+ * fileread.h (class File_read): Add is_descriptor_opened_ field.
+ Update declarations.
+ * layout.cc: Include "descriptors.h".
+ (Layout::create_build_id): Use open_descriptor rather than open.
+ * output.cc: Include "descriptors.h".
+ (Output_file::open): Use open_descriptor rather than open.
+ * archive.cc (Archive::const_iterator): Change Archive to be
+ non-const.
+ (Archive::begin, Archive::end): Make non-const.
+ (Archive::count_members): Likewise.
+ * archive.h (class Archive): Update declarations.
+ * object.h (Object::read): Make non-const.
+ * Makefile.am (CCFILES): Add descriptors.cc.
+ (HFILES): Add descriptors.h.
+ * Makefile.in: Rebuild.
+
PR 6716
* gold.h: Always include <clocale>. Add Solaris workarounds
following code in binutils/sysdep.h.
copy-relocs.cc \
cref.cc \
defstd.cc \
+ descriptors.cc \
dirsearch.cc \
dynobj.cc \
dwarf_reader.cc \
cref.h \
defstd.h \
dirsearch.h \
+ descriptors.h \
dynobj.h \
dwarf_reader.h \
ehframe.h \
libgold_a_LIBADD =
am__objects_1 = archive.$(OBJEXT) binary.$(OBJEXT) common.$(OBJEXT) \
compressed_output.$(OBJEXT) copy-relocs.$(OBJEXT) \
- cref.$(OBJEXT) defstd.$(OBJEXT) dirsearch.$(OBJEXT) \
- dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) \
- errors.$(OBJEXT) expression.$(OBJEXT) fileread.$(OBJEXT) \
- gold.$(OBJEXT) gold-threads.$(OBJEXT) layout.$(OBJEXT) \
- mapfile.$(OBJEXT) merge.$(OBJEXT) object.$(OBJEXT) \
- options.$(OBJEXT) output.$(OBJEXT) parameters.$(OBJEXT) \
- readsyms.$(OBJEXT) reduced_debug_output.$(OBJEXT) \
- reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \
- script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
- target-select.$(OBJEXT) version.$(OBJEXT) workqueue.$(OBJEXT) \
+ cref.$(OBJEXT) defstd.$(OBJEXT) descriptors.$(OBJEXT) \
+ dirsearch.$(OBJEXT) dynobj.$(OBJEXT) dwarf_reader.$(OBJEXT) \
+ ehframe.$(OBJEXT) errors.$(OBJEXT) expression.$(OBJEXT) \
+ fileread.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
+ layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
+ object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
+ parameters.$(OBJEXT) readsyms.$(OBJEXT) \
+ reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
+ resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
+ stringpool.$(OBJEXT) symtab.$(OBJEXT) target-select.$(OBJEXT) \
+ version.$(OBJEXT) workqueue.$(OBJEXT) \
workqueue-threads.$(OBJEXT)
am__objects_2 =
am__objects_3 = yyscript.$(OBJEXT)
copy-relocs.cc \
cref.cc \
defstd.cc \
+ descriptors.cc \
dirsearch.cc \
dynobj.cc \
dwarf_reader.cc \
cref.h \
defstd.h \
dirsearch.h \
+ descriptors.h \
dynobj.h \
dwarf_reader.h \
ehframe.h \
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy-relocs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cref.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptors.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_reader.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@
off_t size;
};
- const_iterator(const Archive* archive, off_t off)
+ const_iterator(Archive* archive, off_t off)
: archive_(archive), off_(off)
{ this->read_next_header(); }
read_next_header();
// The underlying archive.
- const Archive* archive_;
+ Archive* archive_;
// The current offset in the file.
off_t off_;
// The current archive header.
// Initial iterator.
Archive::const_iterator
-Archive::begin() const
+Archive::begin()
{
return Archive::const_iterator(this, sarmag);
}
// Final iterator.
Archive::const_iterator
-Archive::end() const
+Archive::end()
{
return Archive::const_iterator(this, this->input_file_->file().filesize());
}
// reports.
size_t
-Archive::count_members() const
+Archive::count_members()
{
size_t ret = 0;
for (Archive::const_iterator p = this->begin();
// Return the number of members in the archive.
size_t
- count_members() const;
+ count_members();
private:
Archive(const Archive&);
class const_iterator;
const_iterator
- begin() const;
+ begin();
const_iterator
- end() const;
+ end();
friend class const_iterator;
--- /dev/null
+// descriptors.cc -- manage file descriptors for gold
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@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.
+
+#include "gold.h"
+
+#include <cerrno>
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "parameters.h"
+#include "gold-threads.h"
+#include "descriptors.h"
+
+namespace gold
+{
+
+// Class Descriptors.
+
+// The default for limit_ is meant to simply be large. It gets
+// adjusted downward if we run out of file descriptors.
+
+Descriptors::Descriptors()
+ : lock_(NULL), open_descriptors_(), stack_top_(-1), current_(0),
+ limit_(8192 - 16)
+{
+ this->open_descriptors_.reserve(128);
+}
+
+// Open a file.
+
+int
+Descriptors::open(int descriptor, const char* name, int flags, int mode)
+{
+ // We don't initialize this until we are called, because we can't
+ // initialize a Lock until we have parsed the options to find out
+ // whether we are running with threads. We can be called before
+ // options are valid when reading a linker script.
+ if (this->lock_ == NULL)
+ {
+ if (parameters->options_valid())
+ this->lock_ = new Lock();
+ else
+ gold_assert(descriptor < 0);
+ }
+
+ if (descriptor >= 0)
+ {
+ Hold_lock hl(*this->lock_);
+
+ gold_assert(static_cast<size_t>(descriptor)
+ < this->open_descriptors_.size());
+ Open_descriptor* pod = &this->open_descriptors_[descriptor];
+ if (pod->name == name
+ || (pod->name != NULL && strcmp(pod->name, name) == 0))
+ {
+ gold_assert(!pod->inuse);
+ pod->inuse = true;
+ return descriptor;
+ }
+ }
+
+ while (true)
+ {
+ int new_descriptor = ::open(name, flags, mode);
+ if (new_descriptor < 0
+ && errno != ENFILE
+ && errno != EMFILE)
+ {
+ if (descriptor >= 0 && errno == ENOENT)
+ {
+ {
+ Hold_lock hl(*this->lock_);
+
+ gold_error(_("file %s was removed during the link"),
+ this->open_descriptors_[descriptor].name);
+ }
+
+ errno = ENOENT;
+ }
+
+ return new_descriptor;
+ }
+
+ if (new_descriptor >= 0)
+ {
+ Hold_optional_lock hl(this->lock_);
+
+ if (static_cast<size_t>(new_descriptor)
+ >= this->open_descriptors_.size())
+ this->open_descriptors_.resize(new_descriptor + 64);
+
+ Open_descriptor* pod = &this->open_descriptors_[new_descriptor];
+ pod->name = name;
+ pod->stack_next = -1;
+ pod->inuse = true;
+ pod->is_write = (flags & O_ACCMODE) != O_RDONLY;
+
+ ++this->current_;
+ if (this->current_ >= this->limit_)
+ this->close_some_descriptor();
+
+ return new_descriptor;
+ }
+
+ // We ran out of file descriptors.
+ {
+ Hold_optional_lock hl(this->lock_);
+
+ this->limit_ = this->current_ - 16;
+ if (this->limit_ < 8)
+ this->limit_ = 8;
+ if (!this->close_some_descriptor())
+ gold_fatal(_("out of file descriptors and couldn't close any"));
+ }
+ }
+}
+
+// Release a descriptor.
+
+void
+Descriptors::release(int descriptor, bool permanent)
+{
+ Hold_optional_lock hl(this->lock_);
+
+ gold_assert(descriptor >= 0
+ && (static_cast<size_t>(descriptor)
+ < this->open_descriptors_.size()));
+ Open_descriptor* pod = &this->open_descriptors_[descriptor];
+
+ if (permanent
+ || (this->current_ > this->limit_ && !pod->is_write))
+ {
+ if (::close(descriptor) < 0)
+ gold_warning(_("while closing %s: %s"), pod->name, strerror(errno));
+ pod->name = NULL;
+ --this->current_;
+ }
+ else
+ {
+ pod->inuse = false;
+ if (!pod->is_write)
+ {
+ pod->stack_next = this->stack_top_;
+ this->stack_top_ = descriptor;
+ }
+ }
+}
+
+// Close some descriptor. The lock is held when this is called. We
+// close the descriptor on the top of the free stack. Note that this
+// is the opposite of an LRU algorithm--we close the most recently
+// used descriptor. That is because the linker tends to cycle through
+// all the files; after we release a file, we are unlikely to need it
+// again until we have looked at all the other files. Return true if
+// we closed a descriptor.
+
+bool
+Descriptors::close_some_descriptor()
+{
+ int last = -1;
+ int i = this->stack_top_;
+ while (i >= 0)
+ {
+ gold_assert(static_cast<size_t>(i) < this->open_descriptors_.size());
+ Open_descriptor* pod = &this->open_descriptors_[i];
+ if (!pod->inuse && !pod->is_write)
+ {
+ if (::close(i) < 0)
+ gold_warning(_("while closing %s: %s"), pod->name, strerror(errno));
+ --this->current_;
+ pod->name = NULL;
+ if (last < 0)
+ this->stack_top_ = pod->stack_next;
+ else
+ this->open_descriptors_[last].stack_next = pod->stack_next;
+ return true;
+ }
+ last = i;
+ i = pod->stack_next;
+ }
+
+ // We couldn't find any descriptors to close. This is weird but not
+ // necessarily an error.
+ return false;
+}
+
+// The single global variable which manages descriptors.
+
+Descriptors descriptors;
+
+} // End namespace gold.
--- /dev/null
+// descriptors.h -- manage file descriptors for gold -*- C++ -*-
+
+// Copyright 2008 Free Software Foundation, Inc.
+// Written by Ian Lance Taylor <iant@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.
+
+#ifndef GOLD_DESCRIPTORS_H
+#define GOLD_DESCRIPTORS_H
+
+#include <vector>
+
+namespace gold
+{
+
+class Lock;
+
+// This class manages file descriptors for gold.
+
+class Descriptors
+{
+ public:
+ Descriptors();
+
+ // Get a file descriptor for a file. The DESCRIPTOR parameter is
+ // the descriptor the last time the file was used; this will be -1
+ // if this is the first time the file is being opened. The NAME,
+ // FLAGS, and MODE parameters are as for ::open. NAME must be in
+ // permanent storage. This returns the descriptor to use, which may
+ // or may not be the same as DESCRIPTOR. If there is an error
+ // opening the file, this will return -1 with errno set
+ // appropriately.
+ int
+ open(int descriptor, const char* name, int flags, int mode = 0);
+
+ // Release the file descriptor DESCRIPTOR. If PERMANENT is true, it
+ // will be closed, and the caller may not reopen it. If PERMANENT
+ // is false this doesn't necessarily close the descriptor, but it
+ // makes it available to be closed; the descriptor must not be used
+ // again except as an argument to Descriptor::open.
+ void
+ release(int descriptor, bool permanent);
+
+ private:
+ // Information kept for a descriptor.
+ struct Open_descriptor
+ {
+ // File name currently associated with descriptor. This is empty
+ // if none.
+ const char* name;
+ // Index of next descriptor on stack of released descriptors.
+ int stack_next;
+ // Whether the descriptor is currently in use.
+ bool inuse;
+ // Whether this is a write descriptor.
+ bool is_write;
+ };
+
+ bool
+ close_some_descriptor();
+
+ // We need to lock before accessing any fields.
+ Lock* lock_;
+ // Information for descriptors.
+ std::vector<Open_descriptor> open_descriptors_;
+ // Top of stack.
+ int stack_top_;
+ // The current number of file descriptors open.
+ int current_;
+ // The maximum number of file descriptors we open.
+ int limit_;
+};
+
+// File descriptors are a centralized data structure, and we use a
+// global variable rather than passing the data structure into every
+// routine that does file I/O.
+
+extern Descriptors descriptors;
+
+inline int
+open_descriptor(int descriptor, const char* name, int flags, int mode = 0)
+{ return descriptors.open(descriptor, name, flags, mode); }
+
+inline void
+release_descriptor(int descriptor, bool permanent)
+{ descriptors.release(descriptor, permanent); }
+
+} // End namespace gold.
+
+#endif // !defined(GOLD_DESCRIPTORS_H)
#include "dirsearch.h"
#include "target.h"
#include "binary.h"
+#include "descriptors.h"
#include "fileread.h"
namespace gold
unsigned long long File_read::current_mapped_bytes;
unsigned long long File_read::maximum_mapped_bytes;
-// The File_read class is designed to support file descriptor caching,
-// but this is not currently implemented.
-
File_read::~File_read()
{
gold_assert(this->token_.is_writable());
- if (this->descriptor_ >= 0)
+ if (this->is_descriptor_opened_)
{
- if (close(this->descriptor_) < 0)
- gold_warning(_("close of %s failed: %s"),
- this->name_.c_str(), strerror(errno));
+ release_descriptor(this->descriptor_, true);
this->descriptor_ = -1;
+ this->is_descriptor_opened_ = false;
}
this->name_.clear();
this->clear_views(true);
{
gold_assert(this->token_.is_writable()
&& this->descriptor_ < 0
+ && !this->is_descriptor_opened_
&& this->name_.empty());
this->name_ = name;
- this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY);
+ this->descriptor_ = open_descriptor(-1, this->name_.c_str(),
+ O_RDONLY);
if (this->descriptor_ >= 0)
{
+ this->is_descriptor_opened_ = true;
struct stat s;
if (::fstat(this->descriptor_, &s) < 0)
gold_error(_("%s: fstat failed: %s"),
{
gold_assert(this->token_.is_writable()
&& this->descriptor_ < 0
+ && !this->is_descriptor_opened_
&& this->name_.empty());
this->name_ = name;
this->contents_ = contents;
return true;
}
+// Reopen a descriptor if necessary.
+
+void
+File_read::reopen_descriptor()
+{
+ if (!this->is_descriptor_opened_)
+ {
+ this->descriptor_ = open_descriptor(this->descriptor_,
+ this->name_.c_str(),
+ O_RDONLY);
+ if (this->descriptor_ < 0)
+ gold_fatal(_("could not reopen file %s"), this->name_.c_str());
+ this->is_descriptor_opened_ = true;
+ }
+}
+
// Release the file. This is called when we are done with the file in
// a Task.
File_read::maximum_mapped_bytes = File_read::current_mapped_bytes;
// Only clear views if there is only one attached object. Otherwise
- // we waste time trying to clear cached archive views.
+ // we waste time trying to clear cached archive views. Similarly
+ // for releasing the descriptor.
if (this->object_count_ <= 1)
- this->clear_views(false);
+ {
+ this->clear_views(false);
+ if (this->is_descriptor_opened_)
+ {
+ release_descriptor(this->descriptor_, false);
+ this->is_descriptor_opened_ = false;
+ }
+ }
this->released_ = true;
}
// the buffer at P.
void
-File_read::do_read(off_t start, section_size_type size, void* p) const
+File_read::do_read(off_t start, section_size_type size, void* p)
{
ssize_t bytes;
if (this->contents_ != NULL)
}
else
{
+ this->reopen_descriptor();
bytes = ::pread(this->descriptor_, p, size, start);
if (static_cast<section_size_type>(bytes) == size)
return;
// Read data from the file.
void
-File_read::read(off_t start, section_size_type size, void* p) const
+File_read::read(off_t start, section_size_type size, void* p)
{
const File_read::View* pv = this->find_view(start, size, -1U, NULL);
if (pv != NULL)
}
else
{
+ this->reopen_descriptor();
void* p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE,
this->descriptor_, poff);
if (p == MAP_FAILED)
last_offset = i_entry.file_offset + i_entry.size;
}
+ this->reopen_descriptor();
+
gold_assert(iov_index < sizeof iov / sizeof iov[0]);
if (::lseek(this->descriptor_, base + first_offset, SEEK_SET) < 0)
class Dirsearch;
class File_view;
-// File_read manages a file descriptor for a file we are reading. We
-// close file descriptors if we run out of them, so this class reopens
-// the file as needed.
+// File_read manages a file descriptor and mappings for a file we are
+// reading.
class File_read
{
public:
File_read()
- : name_(), descriptor_(-1), object_count_(0), size_(0), token_(false),
- views_(), saved_views_(), contents_(NULL), mapped_bytes_(0),
- released_(true)
+ : name_(), descriptor_(-1), is_descriptor_opened_(false), object_count_(0),
+ size_(0), token_(false), views_(), saved_views_(), contents_(NULL),
+ mapped_bytes_(0), released_(true)
{ }
~File_read();
{ --this->object_count_; }
// Lock the file for exclusive access within a particular Task::run
- // execution. This means that the descriptor can not be closed.
- // This routine may only be called when the workqueue lock is held.
+ // execution. This routine may only be called when the workqueue
+ // lock is held.
void
lock(const Task* t);
- // Unlock the descriptor, permitting it to be closed if necessary.
+ // Unlock the file.
void
unlock(const Task* t);
// Read data from the file into the buffer P starting at file offset
// START for SIZE bytes.
void
- read(off_t start, section_size_type size, void* p) const;
+ read(off_t start, section_size_type size, void* p);
// Return a lasting view into the file starting at file offset START
// for SIZE bytes. This is allocated with new, and the caller is
// A simple list of Views.
typedef std::list<View*> Saved_views;
+ // Open the descriptor if necessary.
+ void
+ reopen_descriptor();
+
// Find a view into the file.
View*
find_view(off_t start, section_size_type size, unsigned int byteshift,
// Read data from the file into a buffer.
void
- do_read(off_t start, section_size_type size, void* p) const;
+ do_read(off_t start, section_size_type size, void* p);
// Add a view.
void
std::string name_;
// File descriptor.
int descriptor_;
+ // Whether we have regained the descriptor after releasing the file.
+ bool is_descriptor_opened_;
// The number of objects associated with this file. This will be
// more than 1 in the case of an archive.
int object_count_;
Lock& lock_;
};
+class Hold_optional_lock
+{
+ public:
+ Hold_optional_lock(Lock* lock)
+ : lock_(lock)
+ {
+ if (this->lock_ != NULL)
+ this->lock_->acquire();
+ }
+
+ ~Hold_optional_lock()
+ {
+ if (this->lock_ != NULL)
+ this->lock_->release();
+ }
+
+ private:
+ Hold_optional_lock(const Hold_optional_lock&);
+ Hold_optional_lock& operator=(const Hold_optional_lock&);
+
+ Lock* lock_;
+};
+
// The interface for the implementation of a condition variable.
class Condvar_impl
#include "compressed_output.h"
#include "reduced_debug_output.h"
#include "reloc.h"
+#include "descriptors.h"
#include "layout.h"
namespace gold
char buffer[uuidsz];
memset(buffer, 0, uuidsz);
- int descriptor = ::open("/dev/urandom", O_RDONLY);
+ int descriptor = open_descriptor(-1, "/dev/urandom", O_RDONLY);
if (descriptor < 0)
gold_error(_("--build-id=uuid failed: could not open /dev/urandom: %s"),
strerror(errno));
else
{
ssize_t got = ::read(descriptor, buffer, uuidsz);
- ::close(descriptor);
+ release_descriptor(descriptor, true);
if (got < 0)
gold_error(_("/dev/urandom: read failed: %s"), strerror(errno));
else if (static_cast<size_t>(got) != uuidsz)
// Read data from the underlying file.
void
- read(off_t start, section_size_type size, void* p) const
+ read(off_t start, section_size_type size, void* p)
{ this->input_file()->file().read(start + this->offset_, size, p); }
// Read multiple data from the underlying file.
#include "symtab.h"
#include "reloc.h"
#include "merge.h"
+#include "descriptors.h"
#include "output.h"
// Some BSD systems still use MAP_ANON instead of MAP_ANONYMOUS
unlink_if_ordinary(this->name_);
int mode = parameters->options().relocatable() ? 0666 : 0777;
- int o = ::open(this->name_, O_RDWR | O_CREAT | O_TRUNC, mode);
+ int o = open_descriptor(-1, this->name_, O_RDWR | O_CREAT | O_TRUNC,
+ mode);
if (o < 0)
gold_fatal(_("%s: open: %s"), this->name_, strerror(errno));
this->o_ = o;