/* * Copyright (c) 2011, Chris Johns * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /** * @file * * @ingroup rtems-ld * * @brief RTEMS Linker file manages access the image contained in various file * formats. * * The base element is a file. It references a object file that is either * inside an archive or stand alone. You access a object file by constructing a * handle. A handle is the object file with the specific file descriptor * created when the archive or object file was opened. * * */ #if !defined (_RLD_FILES_H_) #define _RLD_FILES_H_ #include #include #include #include #include #include namespace rld { namespace files { /** * Container of files. */ typedef std::vector < file > files; /** * Container of archive files. */ typedef std::map < const std::string, archive* > archives; /** * Container of object files. */ typedef std::map < const std::string, object* > objects; /** * Container list of object files. */ typedef std::list < object* > object_list; /** * Byte order of the image. */ enum byteorder { big_endian, little_endian }; /** * A file is a single object file that is either in an @ref archive or * a separate stand alone @ref object file. */ class file { public: /** * Construct the file from the component parts when part of an archive. * * @param aname The archive name. * @param oname The object file name. * @param offset The offset in the archive the object file starts. * @param size The size of the archive the object file starts. */ file (const std::string& aname, const std::string& oname, off_t offset, size_t size); /** * Construct the name by splitting the full path into an archive, * object file name and offset. * * @param path The path to the image. * @param is_object If true (default) the name is for an object file. */ file (const std::string& path, bool is_object = true); /** * Contruct an empty file. */ file (); /** * Set a name from the path. * * @param path The path to the image. * @param is_object If true (default) the name is for an object file. */ void set (const std::string& path, bool is_object = true); /** * Is an archive returns true if the file is in an archive. * * @retval true The object file is in an archive. * @retval false The object file is stand alone. */ bool is_archive () const; /** * Is object file stand alone. * * @retval true The object file is stand alone. * @retval false The object could be part of an archive. */ bool is_object () const; /** * Valid returns true if there is a valid name. * * @retval true There is a valid name. * @retval false There is not name assigned. */ bool is_valid () const; /** * Exists returns true if the archive or object file is present on disk * and a regular file. * * @retval true The file is valid and a regular file. * @retval false The file is either not present, not accessable or not a * regular file. */ bool exists () const; /** * The path maps to the real file on disk. The file may not be valid. * * @return const std::string The real path to the file on disk. */ const std::string path () const; /** * The full path. * * @return const std::string The full path to the image. */ const std::string full () const; /** * The base path. It is the basename of the full path. * * @return const std::string The basename of the full path to the image. */ const std::string basename () const; /** * The archive name component. A length of 0 means there was not * archive component. * * @return const std::string& The archive name. */ const std::string& aname () const; /** * The object name. There is always an object name. * * @return const std::string& The object name. */ const std::string& oname () const; /** * The object's offset in the archive or on disk. * * @return off_t The offset part of the file name. */ off_t offset () const; /** * The object's size in the archive. * * @return size_t The size of the file in bytes. */ size_t size () const; private: std::string aname_; //< The archive name. std::string oname_; //< The object name. off_t offset_; //< The object's offset in the archive. size_t size_; //< The object's size in the archive or on disk. }; /** * Image is the base file type and lets us have a single container to hold * the types of images we need to support. */ class image { public: /** * Construct the image. * * @param name The name of the image. */ image (file& name); /** * Construct the image. * * @param path The file path. * @param is_object If true (default) the name is for an object file. */ image (const std::string& path, bool is_object = true); /** * Construct the image. */ image (); /** * Destruct the image. */ virtual ~image (); /** * Open the image. You can open the image more than once but you need to * close it the same number of times. * * @param name The @ref file name. */ virtual void open (file& name); /** * Open the image. You can open the image more than once but you need to * close it the same number of times. * * @param writeable If true the image is open as writable. The default is * false. */ virtual void open (bool writable = false); /** * Close the image. */ virtual void close (); /** * Read a block from the file. * * @param buffer The buffer to read the data into. * @param size The amount of data to read. * @return ssize_t The amount of data read. */ virtual ssize_t read (void* buffer, size_t size); /** * Write a block from the file. * * @param buffer The buffer of data to write. * @param size The amount of data to write. * @return ssize_t The amount of data written. */ virtual ssize_t write (const void* buffer, size_t size); /** * Seek to the offset in the image. * * @param offset The offset to seek too. */ virtual void seek (off_t offset); /** * Seek and then read. * * @param offset The offset to seek too before reading. * @param buffer The buffer to read the data into. * @param size The amount of data to read. * @retval true The data requested was read. * @retval false The request data was not read. */ virtual bool seek_read (off_t offset, uint8_t* buffer, size_t size); /** * Seek and then write. * * @param offset The offset to seek too before writing. * @param buffer The buffer of data to write. * @param size The amount of data to write. * @retval true The data requested was written. * @retval false The request data was not written. */ virtual bool seek_write (off_t offset, const void* buffer, size_t size); /** * The name of the image. * * @param const file& The @ref file name of the image. */ const file& name () const; /** * References to the image. * * @return int The number of references the image has. */ virtual int references () const; /** * The file size. * * @return size_t The size of the image. */ virtual size_t size () const; /** * The file descriptor. * * @return int The operating system file descriptor handle. */ virtual int fd () const; /** * The ELF reference. * * @return elf::file& The @ref elf::file object of the image. */ elf::file& elf (); /** * Return the image's byte order. */ byteorder get_byteorder () const; /** * A symbol in the image has been referenced. */ virtual void symbol_referenced (); /** * Return the number of symbol references. * * @return int The symbol references count. */ virtual int symbol_references () const; /** * The path maps to the real file on disk. The file may not be valid. * * @return const std::string The real path to the file on disk. */ const std::string path () const { return name ().path (); } /** * Is the image open ? * * @retval true The image is open. * @retval false The image is not open. */ bool is_open () const { return fd () != -1; } /** * Is the image writable ? * * @retval true The image is writable. * @retval false The image is not writable. */ bool is_writable () const { return writable; } /** * Remove a writable file on close. This flag can be set when an error * happens while writing a file. */ void remove_on_close () { remove = true; } private: file name_; //< The name of the file. int references_; //< The number of handles open. int fd_; //< The file descriptor of the archive. elf::file elf_; //< The libelf reference. int symbol_refs; //< The number of symbols references made. bool writable; //< The image is writable. bool remove; //< Remove the image on close if writable. }; /** * Copy the input section of the image to the output section. The file * positions in the images must be set before making the call. * * @param in The input image. * @param out The output image. * @param size The amouint of data to copy. */ void copy (image& in, image& out, size_t size); /** * The archive class proivdes access to object files that are held in a AR * format file. GNU AR extensions are supported. The archive is a kind of * @ref image and provides the container for the @ref object's that it * contains. */ class archive: public image { public: /** * Open a archive format file that contains ELF object files. * * @param name The name of the @ref archive. */ archive (const std::string& name); /** * Close the archive. */ virtual ~archive (); /** * Begin the ELF session. */ void begin (); /** * End the ELF session. */ void end (); /** * Match the archive name. * * @param name The name of the archive to check. * @retval true The name matches. * @retval false The name does not match. */ bool is (const std::string& name) const; /** * Check this is a valid archive. * * @retval true It is a valid archive. * @retval false It is not a valid archive. */ bool is_valid (); /** * Load @ref object's from the @ref archive adding each to the provided * @ref objects container. * * @param objs The container the loaded object files are added too. */ void load_objects (objects& objs); /** * Get the name. * * @return const std::string& Return a reference to the archive's name. */ const std::string& get_name () const; /** * Less than operator for the map container. It compares the name of the * the @ref archive. * * @param rhs The right hand side of the '<' operator. * @return true The right hand side is less than this archive. * @return false The right hand side is greater than or equal to this * archive. */ bool operator< (const archive& rhs) const; /** * Create a new archive containing the given set of objects. If * referening an existing archive it is overwritten. * * @param objects The list of objects to place in the archive. */ void create (object_list& objects); private: /** * Read the archive header and check the magic number is valid. * * @param offset The offset in the file to read the header. * @param header Read the header into here. There must be enough space. * @retval true The header was read successfull and the magic number * matched. * @retval false The header could not be read from the @ref image. */ bool read_header (off_t offset, uint8_t* header); /** * Add the object file from the archive to the object's container. * * @param objs The container to add the object to. * @param name The name of the object file being added. * @param offset The offset in the @ref archive of the object file. * @param size The size of the object file. */ void add_object (objects& objs, const char* name, off_t offset, size_t size); /** * Write a file header into the archive. * * @param name The name of the archive. * @param mtime The modified time of the archive. * @param uid The user id of the archive. * @param gid The group id of the archive. * @param mode The mode of the archive. * @param size The size of the archive. */ void write_header (const std::string& name, uint32_t mtime, int uid, int gid, int mode, size_t size); /** * Cannot copy via a copy constructor. */ archive (const archive& orig); /** * Cannot assign using the assignment operator. */ archive& operator= (const archive& rhs); }; /** * A relocation record. We extract what we want because the elf::section * class requires the image be left open as references are alive. We * extract and keep the data we need to create the image. */ struct relocation { const uint32_t offset; //< The section offset. const uint32_t type; //< The type of relocation record. const uint32_t info; //< The ELF info field. const int32_t addend; //< The constant addend. const std::string symname; //< The name of the symbol. const uint32_t symtype; //< The type of symbol. const int symsect; //< The symbol's section symbol. const uint32_t symvalue; //< The symbol's value. const uint32_t symbinding;//< The symbol's binding. /** * Construct from an ELF relocation record. */ relocation (const elf::relocation& er); private: /** * The default constructor is not allowed due to all elements being * const. */ relocation (); }; /** * A container of relocations. */ typedef std::list < relocation > relocations; /** * The sections attributes. We extract what we want because the * elf::section class requires the image be left open as references are * alive. We extract and keep the data we need to create the image. */ struct section { const std::string name; //< The name of the section. const int index; //< The section's index in the object file. const uint32_t type; //< The type of section. const size_t size; //< The size of the section. const uint32_t alignment; //< The alignment of the section. const uint32_t link; //< The ELF link field. const uint32_t info; //< The ELF info field. const uint32_t flags; //< The ELF flags. const off_t offset; //< The ELF file offset. const uint64_t address; //< The ELF address. bool rela; //< Relocation records have the addend field. relocations relocs; //< The sections relocations. /** * Construct from an ELF section. * * @param es The ELF section to load the object file section from. */ section (const elf::section& es); /** * Load the ELF relocations. * * @param es The ELF section to load the relocations from. */ void load_relocations (const elf::section& es); private: /** * The default constructor is not allowed due to all elements being * const. */ section (); }; /** * A container of sections. */ typedef std::list < section > sections; /** * Sum the sizes of a container of sections. */ size_t sum_sizes (const sections& secs); /** * Find the section that matches the index in the sections provided. */ const section* find (const sections& secs, const int index); /** * The object file cab be in an archive or a file. */ class object: public image { public: /** * Construct an object image that is part of an archive. * * @param archive_ The archive the object file is part of. * @param file_ The image file. */ object (archive& archive_, file& file_); /** * Construct the object file. * * @param path The object file path. */ object (const std::string& path); /** * Construct the object file. */ object (); /** * Destruct the object file. */ virtual ~object (); /** * Open the object file. */ virtual void open (bool writable = false); /** * Close the object. */ virtual void close (); /** * Begin the object file session. */ void begin (); /** * End the object file session. */ void end (); /** * If valid returns true the begin has been called and the object has * been validated as being in a suitable format. */ bool valid () const; /** * Load the symbols into the symbols table. * * @param symbols The symbol table to load. * @param local Include local symbols. The default is not to. */ void load_symbols (symbols::table& symbols, bool local = false); /** * Load the relocations. */ void load_relocations (); /** * References to the image. */ virtual int references () const; /** * The file size. */ virtual size_t size () const; /** * The file descriptor. */ virtual int fd () const; /** * A symbol in the image has been referenced. */ virtual void symbol_referenced (); /** * The archive the object file is contained in. If 0 the object file is * not contained in an archive. */ archive* get_archive (); /** * Return the unresolved symbol table for this object file. */ symbols::symtab& unresolved_symbols (); /** * Return the list external symbols. */ symbols::pointers& external_symbols (); /** * Return a container sections that match the requested type and * flags. The filtered section container is not cleared so any matching * sections are appended. * * @param filtered_secs The container of the matching sections. * @param type The section type. Must match. If 0 matches any. * @param flags_in The sections flags that must be set. This is a * mask. If 0 matches any. * @param flags_out The sections flags that must be clear. This is a * mask. If 0 this value is ignored. */ void get_sections (sections& filtered_secs, uint32_t type = 0, uint64_t flags_in = 0, uint64_t flags_out = 0); /** * Return a container sections that match the requested name. The * filtered section container is not cleared so any matching sections are * appended. * * @param filtered_secs The container of the matching sections. * @param name The name of the section. */ void get_sections (sections& filtered_secs, const std::string& name); /** * Get a section given an index number. * * @param index The section index to search for. */ const section& get_section (int index) const; /** * Set the object file's resolving flag. */ void resolve_set (); /** * Clear the object file's resolving flag. */ void resolve_clear (); /** * The resolving state. */ bool resolving () const; /** * Set the object file resolved flag. */ void resolved_set (); /** * The resolved state. */ bool resolved () const; private: archive* archive_; //< Points to the archive if part of an // archive. bool valid_; //< If true begin has run and finished. symbols::symtab unresolved; //< This object's unresolved symbols. symbols::pointers externals; //< This object's external symbols. sections secs; //< The sections. bool resolving_; //< The object is being resolved. bool resolved_; //< The object has been resolved. /** * Cannot copy via a copy constructor. */ object (const object& orig); /** * Cannot assign using the assignment operator. */ object& operator= (const object& rhs); }; /** * A collection of objects files as a cache. This currently is not a cache * but it could become one. */ class cache { public: /** * Construct the cache. */ cache (); /** * Destruct the objects. */ virtual ~cache (); /** * Open the cache by collecting the file names, loading object headers * and loading the archive file names. */ void open (); /** * Close the cache. */ void close (); /** * Add a file path to the cache. */ void add (const std::string& path); /** * Add a container of path to the cache. */ void add (path::paths& paths__); /** * Add a container of path to the cache. */ void add_libraries (path::paths& paths__); /** * Being a session on an archive. */ void archive_begin (const std::string& path); /** * End a session on an archive. */ void archive_end (const std::string& path); /** * Being sessions on all archives. */ void archives_begin (); /** * End the archive sessions. */ void archives_end (); /** * Collect the object names and add them to the cache. */ void collect_object_files (); /** * Collect the object file names by verifing the paths to the files are * valid or read the object file names contained in any archives. */ void collect_object_files (const std::string& path); /** * Load the symbols into the symbol table. * * @param symbols The symbol table to load. * @param locals Include local symbols. The default does not include them. */ void load_symbols (symbols::table& symbols, bool locals = false); /** * Output the unresolved symbol table to the output stream. */ void output_unresolved_symbols (std::ostream& out); /** * Get the archives. */ archives& get_archives (); /** * Get the objects inlcuding those in archives. */ objects& get_objects (); /** * Get the added objects. Does not include the ones in th archives. */ void get_objects (object_list& list) const; /** * Get the paths. */ const path::paths& get_paths () const; /** * Get the archive files. */ void get_archive_files (files& afiles); /** * Get the object files including those in archives. */ void get_object_files (files& ofiles); /** * Get the archive count. */ int archive_count () const; /** * Get the object count. */ int object_count () const; /** * Get the path count. */ int path_count () const; /** * Output archive files. */ void output_archive_files (std::ostream& out); /** * Output archive files. */ void output_object_files (std::ostream& out); protected: /** * Input a path into the cache. */ virtual void input (const std::string& path); private: path::paths paths_; //< The names of the files to process. archives archives_; //< The archive files. objects objects_; //< The object files. bool opened; //< The cache is open. }; /** * Copy the in file to the out file. * * @param in The input file. * @param out The output file. * @param size The amount to copy. If 0 the whole on in is copied. */ void copy_file (image& in, image& out, size_t size = 0); /** * Find the libraries given the list of libraries as bare name which * have 'lib' and '.a' added. */ void find_libraries (path::paths& libraries, path::paths& libpaths, path::paths& libs); } } #endif