From 82dcae9de0f7ca290bba97b6dfb8449e1a2e27fb Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 25 Sep 2007 06:43:17 +0000 Subject: Rework File_read interface. Get file size. Use pread when available. --- gold/Makefile.am | 4 +- gold/Makefile.in | 14 ++--- gold/archive.cc | 31 ++++++----- gold/config.in | 3 ++ gold/configure | 117 +++++++++++++++++++++++++++++++++++++++++- gold/configure.ac | 2 + gold/fileread.cc | 125 ++++++++++++++++++++------------------------- gold/fileread.h | 24 +++++---- gold/gold.h | 4 ++ gold/pread.c | 39 ++++++++++++++ gold/readsyms.cc | 35 +++++++------ gold/script.cc | 16 +++--- gold/testsuite/Makefile.in | 4 +- 13 files changed, 293 insertions(+), 125 deletions(-) create mode 100644 gold/pread.c (limited to 'gold') diff --git a/gold/Makefile.am b/gold/Makefile.am index 11476f8..1710aa6 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -86,8 +86,8 @@ deps_var = libgold.a $(LIBINTL_DEP) ldadd_var = libgold.a $(LIBINTL) ld_new_SOURCES = $(sources_var) -ld_new_DEPENDENCIES = $(deps_var) -ld_new_LDADD = $(ldadd_var) +ld_new_DEPENDENCIES = $(deps_var) $(LIBOBJS) +ld_new_LDADD = $(ldadd_var) $(LIBOBJS) # Use an explicit dependency for the bison generated header file. script.$(OBJEXT): yyscript.h diff --git a/gold/Makefile.in b/gold/Makefile.in index f2ef3a8..2780238 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -48,8 +48,8 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/../config.guess \ $(srcdir)/../install-sh $(srcdir)/../missing \ $(srcdir)/../mkinstalldirs $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.in \ - $(top_srcdir)/configure $(top_srcdir)/po/Make-in yyscript.c \ - yyscript.h + $(top_srcdir)/configure $(top_srcdir)/po/Make-in pread.c \ + yyscript.c yyscript.h subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \ @@ -90,6 +90,7 @@ am_ld_new_OBJECTS = $(am__objects_5) ld_new_OBJECTS = $(am_ld_new_OBJECTS) am__DEPENDENCIES_1 = am__DEPENDENCIES_2 = libgold.a $(am__DEPENDENCIES_1) +am__DEPENDENCIES_3 = @LIBOBJS@ am__ld1_SOURCES_DIST = main.cc i386.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld1_OBJECTS = $(am__objects_5) ld1_OBJECTS = $(am_ld1_OBJECTS) @@ -327,8 +328,8 @@ sources_var = main.cc $(TARGETFILES) deps_var = libgold.a $(LIBINTL_DEP) ldadd_var = libgold.a $(LIBINTL) ld_new_SOURCES = $(sources_var) -ld_new_DEPENDENCIES = $(deps_var) -ld_new_LDADD = $(ldadd_var) +ld_new_DEPENDENCIES = $(deps_var) $(LIBOBJS) +ld_new_LDADD = $(ldadd_var) $(LIBOBJS) POTFILES = $(CCFILES) $(HFILES) $(TARGETFILES) @GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_SOURCES = $(sources_var) @GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_DEPENDENCIES = $(deps_var) gcctestdir1/ld @@ -430,6 +431,7 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@ @@ -893,7 +895,7 @@ clean-am: clean-checkPROGRAMS clean-generic clean-noinstLIBRARIES \ distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf ./$(DEPDIR) + -rm -rf $(DEPDIR) ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags @@ -921,7 +923,7 @@ installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache - -rm -rf ./$(DEPDIR) + -rm -rf $(DEPDIR) ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic diff --git a/gold/archive.cc b/gold/archive.cc index 5ab3696..7398076 100644 --- a/gold/archive.cc +++ b/gold/archive.cc @@ -326,16 +326,12 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout, Input_objects* input_objects) { off_t off = sarmag; + off_t filesize = this->input_file_->file().filesize(); while (true) { - unsigned char hdr_buf[sizeof(Archive_header)]; - off_t bytes; - this->input_file_->file().read_up_to(off, sizeof(Archive_header), - hdr_buf, &bytes); - - if (bytes < sizeof(Archive_header)) + if (filesize - off < sizeof(Archive_header)) { - if (bytes != 0) + if (filesize != off) { fprintf(stderr, _("%s: %s: short archive header at %ld\n"), program_name, this->name().c_str(), @@ -346,6 +342,9 @@ Archive::include_all_members(Symbol_table* symtab, Layout* layout, break; } + unsigned char hdr_buf[sizeof(Archive_header)]; + this->input_file_->file().read(off, sizeof(Archive_header), hdr_buf); + const Archive_header* hdr = reinterpret_cast(hdr_buf); std::string name; @@ -380,11 +379,14 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, size_t memoff = off + sizeof(Archive_header); // Read enough of the file to pick up the entire ELF header. - int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; - unsigned char ehdr_buf[ehdr_size]; - off_t bytes; - this->input_file_->file().read_up_to(memoff, ehdr_size, ehdr_buf, &bytes); - if (bytes < 4) + unsigned char ehdr_buf[elfcpp::Elf_sizes<64>::ehdr_size]; + + off_t filesize = this->input_file_->file().filesize(); + int read_size = elfcpp::Elf_sizes<64>::ehdr_size; + if (filesize - memoff < read_size) + read_size = filesize - memoff; + + if (read_size < 4) { fprintf(stderr, _("%s: %s: member at %ld is not an ELF object"), program_name, this->name().c_str(), @@ -392,6 +394,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, gold_exit(false); } + this->input_file_->file().read(memoff, read_size, ehdr_buf); + static unsigned char elfmagic[4] = { elfcpp::ELFMAG0, elfcpp::ELFMAG1, @@ -407,7 +411,8 @@ Archive::include_member(Symbol_table* symtab, Layout* layout, Object* obj = make_elf_object((std::string(this->input_file_->filename()) + "(" + n + ")"), - this->input_file_, memoff, ehdr_buf, bytes); + this->input_file_, memoff, ehdr_buf, + read_size); input_objects->add_object(obj); diff --git a/gold/config.in b/gold/config.in index ba337b8..bbdf051 100644 --- a/gold/config.in +++ b/gold/config.in @@ -19,6 +19,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H diff --git a/gold/configure b/gold/configure index 98c06bc..e9c942a 100755 --- a/gold/configure +++ b/gold/configure @@ -309,7 +309,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE YACC RANLIB ac_ct_RANLIB LN_S USE_NLS LIBINTL LIBINTL_DEP INCINTL XGETTEXT GMSGFMT POSUB CATALOGS DATADIRNAME INSTOBJEXT GENCAT CATOBJEXT MKINSTALLDIRS MSGFMT MSGMERGE NATIVE_LINKER_TRUE NATIVE_LINKER_FALSE GCC_TRUE GCC_FALSE WARN_CFLAGS NO_WERROR WARN_CXXFLAGS LFS_CXXFLAGS LIBOBJS CXXCPP EGREP MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -4404,6 +4404,119 @@ WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmi LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" + +for ac_func in pread +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + case $LIBOBJS in + "$ac_func.$ac_objext" | \ + *" $ac_func.$ac_objext" | \ + "$ac_func.$ac_objext "* | \ + *" $ac_func.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;; +esac + +fi +done + + + ac_ext=cc ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -6030,12 +6143,12 @@ s,@WARN_CFLAGS@,$WARN_CFLAGS,;t t s,@NO_WERROR@,$NO_WERROR,;t t s,@WARN_CXXFLAGS@,$WARN_CXXFLAGS,;t t s,@LFS_CXXFLAGS@,$LFS_CXXFLAGS,;t t +s,@LIBOBJS@,$LIBOBJS,;t t s,@CXXCPP@,$CXXCPP,;t t s,@EGREP@,$EGREP,;t t s,@MAINTAINER_MODE_TRUE@,$MAINTAINER_MODE_TRUE,;t t s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t s,@MAINT@,$MAINT,;t t -s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF diff --git a/gold/configure.ac b/gold/configure.ac index 1294fa6..fcb176f 100644 --- a/gold/configure.ac +++ b/gold/configure.ac @@ -106,6 +106,8 @@ dnl host dependent. If build == host, we can check getconf LFS_CFLAGS. LFS_CXXFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" AC_SUBST(LFS_CXXFLAGS) +AC_REPLACE_FUNCS(pread) + AC_LANG_PUSH(C++) AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map) diff --git a/gold/fileread.cc b/gold/fileread.cc index ee2ae73..9b800e8 100644 --- a/gold/fileread.cc +++ b/gold/fileread.cc @@ -89,8 +89,23 @@ File_read::open(const std::string& name) && this->descriptor_ < 0 && this->name_.empty()); this->name_ = name; + this->descriptor_ = ::open(this->name_.c_str(), O_RDONLY); + + if (this->descriptor_ >= 0) + { + struct stat s; + if (::fstat(this->descriptor_, &s) < 0) + { + fprintf(stderr, _("%s: %s: fstat failed: %s"), program_name, + this->name_.c_str(), strerror(errno)); + gold_exit(false); + } + this->size_ = s.st_size; + } + ++this->lock_count_; + return this->descriptor_ >= 0; } @@ -98,14 +113,14 @@ File_read::open(const std::string& name) bool File_read::open(const std::string& name, const unsigned char* contents, - off_t contents_size) + off_t size) { gold_assert(this->lock_count_ == 0 && this->descriptor_ < 0 && this->name_.empty()); this->name_ = name; this->contents_ = contents; - this->contents_size_ = contents_size; + this->size_ = size; ++this->lock_count_; return true; } @@ -144,50 +159,45 @@ File_read::find_view(off_t start, off_t size) return p->second; } -// Read data from the file. Return the number of bytes read. If -// PBYTES is not NULL, store the number of bytes in *PBYTES, otherwise -// require that we read exactly the number of bytes requested. +// Read SIZE bytes from the file starting at offset START. Read into +// the buffer at P. Return the number of bytes read, which should +// always be at least SIZE except at the end of the file. off_t -File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes) +File_read::do_read(off_t start, off_t size, void* p) { gold_assert(this->lock_count_ > 0); - off_t bytes; - if (this->contents_ == NULL) + if (this->contents_ != NULL) { - int o = this->descriptor_; - - if (lseek(o, start, SEEK_SET) < 0) - { - fprintf(stderr, _("%s: %s: lseek to %lld failed: %s"), - program_name, this->filename().c_str(), - static_cast(start), - strerror(errno)); - gold_exit(false); - } - - bytes = ::read(o, p, size); - if (bytes < 0) - { - fprintf(stderr, _("%s: %s: read failed: %s\n"), - program_name, this->filename().c_str(), strerror(errno)); - gold_exit(false); - } - } - else - { - bytes = this->contents_size_ - start; + off_t bytes = this->size_ - start; if (bytes < 0) bytes = 0; else if (bytes > size) bytes = size; memcpy(p, this->contents_ + start, bytes); + return bytes; + } + + off_t bytes = ::pread(this->descriptor_, p, size, start); + if (bytes < 0) + { + fprintf(stderr, _("%s: %s: pread failed: %s\n"), + program_name, this->filename().c_str(), strerror(errno)); + gold_exit(false); } - if (pbytes != NULL) - *pbytes = bytes; - else if (bytes != size) + return bytes; +} + +// Read exactly SIZE bytes from the file starting at offset START. +// Read into the buffer at P. + +void +File_read::do_read_exact(off_t start, off_t size, void* p) +{ + off_t bytes = this->do_read(start, size, p); + if (bytes != size) { fprintf(stderr, _("%s: %s: file too short: read only %lld of %lld " @@ -198,8 +208,6 @@ File_read::do_read(off_t start, off_t size, void* p, off_t* pbytes) static_cast(start)); gold_exit(false); } - - return bytes; } // Read data from the file. @@ -216,24 +224,7 @@ File_read::read(off_t start, off_t size, void* p) return; } - this->do_read(start, size, p, NULL); -} - -void -File_read::read_up_to(off_t start, off_t size, void* p, off_t* pbytes) -{ - gold_assert(this->lock_count_ > 0); - - File_read::View* pv = this->find_view(start, size); - if (pv != NULL) - { - memcpy(p, pv->data() + (start - pv->start()), size); - if (pbytes != NULL) - *pbytes = size; - return; - } - - this->do_read(start, size, p, pbytes); + this->do_read_exact(start, size, p); } // Find an existing view or make a new one. @@ -260,28 +251,24 @@ File_read::find_or_make_view(off_t start, off_t size) this->saved_views_.push_back(v); } - // We need to read data from the file. + // We need to read data from the file. We read full pages for + // greater efficiency on small files. off_t psize = File_read::pages(size + (start - poff)); - unsigned char* p = new unsigned char[psize]; - off_t got_bytes; - off_t bytes = this->do_read(poff, psize, p, &got_bytes); - - File_read::View* v = new File_read::View(poff, bytes, p); + if (poff + psize >= this->size_) + { + psize = this->size_ - poff; + gold_assert(psize >= size); + } - ins.first->second = v; + unsigned char* p = new unsigned char[psize]; - if (bytes - (start - poff) >= size) - return v; + this->do_read_exact(poff, psize, p); - fprintf(stderr, - _("%s: %s: file too short: read only %lld of %lld bytes at %lld\n"), - program_name, this->filename().c_str(), - static_cast(bytes - (start - poff)), - static_cast(size), - static_cast(start)); - gold_exit(false); + File_read::View* v = new File_read::View(poff, psize, p); + ins.first->second = v; + return v; } // This implementation of get_view just reads into a memory buffer, diff --git a/gold/fileread.h b/gold/fileread.h index 781031a..ef5efc0 100644 --- a/gold/fileread.h +++ b/gold/fileread.h @@ -45,8 +45,8 @@ class File_read { public: File_read() - : name_(), descriptor_(-1), lock_count_(0), views_(), - saved_views_(), contents_(NULL), contents_size_(0) + : name_(), descriptor_(-1), size_(0), lock_count_(0), views_(), + saved_views_(), contents_(NULL) { } ~File_read(); @@ -80,6 +80,11 @@ class File_read bool is_locked(); + // Return the size of the file. + off_t + filesize() const + { return this->size_; } + // Return a view into the file starting at file offset START for // SIZE bytes. The pointer will remain valid until the File_read is // unlocked. It is an error if we can not read enough data from the @@ -92,11 +97,6 @@ class File_read void read(off_t start, off_t size, void* p); - // Read up to SIZE bytes from the file into the buffer P starting at - // file offset START. Set *PBYTES to the number of bytes read. - void - read_up_to(off_t start, off_t size, void* p, off_t* pbytes); - // Return a lasting view into the file starting at file offset START // for SIZE bytes. This is allocated with new, and the caller is // responsible for deleting it when done. The data associated with @@ -159,7 +159,11 @@ class File_read // Read data from the file into a buffer. off_t - do_read(off_t start, off_t size, void* p, off_t* pbytes); + do_read(off_t start, off_t size, void* p); + + // Read an exact number of bytes into a buffer. + void + do_read_exact(off_t start, off_t size, void* p); // Find or make a view into the file. View* @@ -192,6 +196,8 @@ class File_read std::string name_; // File descriptor. int descriptor_; + // File size. + off_t size_; // Number of locks on the file. int lock_count_; // Buffered views into the file. @@ -201,8 +207,6 @@ class File_read Saved_views saved_views_; // Specified file contents. Used only for testing purposes. const unsigned char* contents_; - // Specified file size. Used only for testing purposes. - off_t contents_size_; }; // A view of file data that persists even when the file is unlocked. diff --git a/gold/gold.h b/gold/gold.h index 3752846..14d4aee 100644 --- a/gold/gold.h +++ b/gold/gold.h @@ -98,6 +98,10 @@ struct hash #endif +#ifndef HAVE_PREAD +extern "C" ssize_t pread(int, void*, size_t, off_t); +#endif + namespace gold { // This is a hack to work around a problem with older versions of g++. diff --git a/gold/pread.c b/gold/pread.c new file mode 100644 index 0000000..1b0cf40 --- /dev/null +++ b/gold/pread.c @@ -0,0 +1,39 @@ +/* pread.c -- version of pread for gold. */ + +/* Copyright 2006, 2007 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + 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. */ + +/* This file implements pread for systems which don't have it. This + file is only compiled if pread is not present on the system. This + is not an exact version of pread, as it does not preserve the + current file offset. */ + +#include "config.h" + +#include +#include + +ssize_t +pread(int fd, void* buf, size_t count, off_t offset) +{ + if (lseek(fd, offset, SEEK_SET) != offset) + return -1; + return read(fd, buf, count); +} diff --git a/gold/readsyms.cc b/gold/readsyms.cc index 5c5594d..bbeb425 100644 --- a/gold/readsyms.cc +++ b/gold/readsyms.cc @@ -86,12 +86,24 @@ Read_symbols::run(Workqueue* workqueue) // Read enough of the file to pick up the entire ELF header. - const int ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; - unsigned char ehdr_buf[ehdr_size]; - off_t bytes; - input_file->file().read_up_to(0, ehdr_size, ehdr_buf, &bytes); + off_t filesize = input_file->file().filesize(); - if (bytes >= 4) + if (filesize == 0) + { + fprintf(stderr, _("%s: %s: file is empty\n"), + program_name, input_file->file().filename().c_str()); + gold_exit(false); + } + + unsigned char ehdr_buf[elfcpp::Elf_sizes<64>::ehdr_size]; + + int read_size = elfcpp::Elf_sizes<64>::ehdr_size; + if (filesize < read_size) + read_size = filesize; + + input_file->file().read(0, read_size, ehdr_buf); + + if (read_size >= 4) { static unsigned char elfmagic[4] = { @@ -103,7 +115,7 @@ Read_symbols::run(Workqueue* workqueue) // This is an ELF object. Object* obj = make_elf_object(input_file->filename(), - input_file, 0, ehdr_buf, bytes); + input_file, 0, ehdr_buf, read_size); // We don't have a way to record a non-archive in an input // group. If this is an ordinary object file, we can't @@ -132,7 +144,7 @@ Read_symbols::run(Workqueue* workqueue) } } - if (bytes >= Archive::sarmag) + if (read_size >= Archive::sarmag) { if (memcmp(ehdr_buf, Archive::armag, Archive::sarmag) == 0) { @@ -151,18 +163,11 @@ Read_symbols::run(Workqueue* workqueue) } } - if (bytes == 0) - { - fprintf(stderr, _("%s: %s: file is empty\n"), - program_name, input_file->file().filename().c_str()); - gold_exit(false); - } - // Try to parse this file as a script. if (read_input_script(workqueue, this->options_, this->symtab_, this->layout_, this->dirpath_, this->input_objects_, this->input_group_, this->input_argument_, input_file, - ehdr_buf, bytes, this->this_blocker_, + ehdr_buf, read_size, this->this_blocker_, this->next_blocker_)) return; diff --git a/gold/script.cc b/gold/script.cc index 53cd493..950fa15 100644 --- a/gold/script.cc +++ b/gold/script.cc @@ -299,17 +299,21 @@ class Lex void Lex::read_file(std::string* contents) { + off_t filesize = this->input_file_->file().filesize(); contents->clear(); + contents->reserve(filesize); + off_t off = 0; - off_t got; unsigned char buf[BUFSIZ]; - do + while (off < filesize) { - this->input_file_->file().read_up_to(off, sizeof buf, buf, &got); - contents->append(reinterpret_cast(&buf[0]), got); - off += got; + off_t get = BUFSIZ; + if (get > filesize - off) + get = filesize - off; + this->input_file_->file().read(off, get, buf); + contents->append(reinterpret_cast(&buf[0]), get); + off += get; } - while (got == sizeof buf); } // Return whether C can be the start of a name, if the next character diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 24eda43..edf32e8 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -464,9 +464,9 @@ $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__confi exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu testsuite/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign testsuite/Makefile'; \ cd $(top_srcdir) && \ - $(AUTOMAKE) --gnu testsuite/Makefile + $(AUTOMAKE) --foreign testsuite/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ -- cgit v1.1