diff options
-rw-r--r-- | rld-elf-types.h | 25 | ||||
-rw-r--r-- | rld-elf.cpp | 772 | ||||
-rw-r--r-- | rld-elf.h | 383 | ||||
-rw-r--r-- | rld-files.cpp | 214 | ||||
-rw-r--r-- | rld-files.h | 98 | ||||
-rw-r--r-- | rld-outputter.cpp | 44 | ||||
-rw-r--r-- | rld-resolver.cpp | 17 | ||||
-rw-r--r-- | rld-symbols.cpp | 64 | ||||
-rw-r--r-- | rld-symbols.h | 77 | ||||
-rw-r--r-- | rld.cpp | 16 | ||||
-rw-r--r-- | rtems-ld.cpp (renamed from main.cpp) | 55 | ||||
-rw-r--r-- | rtems-syms.cpp | 311 | ||||
-rw-r--r-- | wscript | 38 |
13 files changed, 1620 insertions, 494 deletions
diff --git a/rld-elf-types.h b/rld-elf-types.h index 2c9c149..ece0928 100644 --- a/rld-elf-types.h +++ b/rld-elf-types.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -36,15 +36,18 @@ namespace rld /** * Hide the types from libelf we use. */ - typedef ::GElf_Word elf_word; - typedef ::GElf_Addr elf_addr; - typedef ::GElf_Sym elf_sym; - typedef ::Elf_Kind elf_kind; - typedef ::Elf_Scn elf_scn; - typedef ::GElf_Shdr elf_shdr; - typedef ::GElf_Ehdr elf_ehdr; - typedef ::Elf_Data elf_data; - typedef ::Elf elf; + typedef ::GElf_Word elf_word; + typedef ::GElf_Xword elf_xword; + typedef ::GElf_Addr elf_addr; + typedef ::GElf_Off elf_off; + typedef ::GElf_Sym elf_sym; + typedef ::Elf_Kind elf_kind; + typedef ::Elf_Scn elf_scn; + typedef ::GElf_Ehdr elf_ehdr; + typedef ::GElf_Shdr elf_shdr; + typedef ::GElf_Phdr elf_phdr; + typedef ::Elf_Data elf_data; + typedef ::Elf elf; } } diff --git a/rld-elf.cpp b/rld-elf.cpp index 8f983b6..30cd4b6 100644 --- a/rld-elf.cpp +++ b/rld-elf.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org> * * 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 @@ -30,18 +30,23 @@ namespace rld { namespace elf { - void error (const std::string& where) + /** + * Throw an ELF error. + * + * @param where Where the error is raised. + */ + void libelf_error (const std::string& where) { - throw rld::error (::elf_errmsg (-1), "elf:" + where); + throw rld::error (::elf_errmsg (-1), "libelf:" + where); } /** * We record the first class, machine and .. type of object file we get the * header of and all header must match. We cannot mix object module types. */ - static int elf_object_class = ELFCLASSNONE; - static int elf_object_data = ELFDATANONE; - static int elf_object_machinetype = EM_NONE; + static unsigned int elf_object_class = ELFCLASSNONE; + static unsigned int elf_object_data = ELFDATANONE; + static unsigned int elf_object_machinetype = EM_NONE; /** * A single place to initialise the libelf library. This must be called @@ -54,255 +59,656 @@ namespace rld if (!libelf_initialised) { if (::elf_version (EV_CURRENT) == EV_NONE) - error ("initialisation"); + libelf_error ("initialisation"); libelf_initialised = true; } } - /** - * Return the RTEMS target type given the ELF machine type. - */ - const std::string - machine_type () + section::section (file& file_, int index_) + : file_ (&file_), + index_ (index_), + scn (0), + data_ (0) { - struct types_and_labels - { - const char* name; //< The RTEMS label. - int machinetype; //< The machine type. - }; - types_and_labels types_to_labels[] = - { - { "arm", EM_ARM }, - { "avr", EM_AVR }, - { "bfin", EM_BLACKFIN }, - { "h8300", EM_H8_300 }, - { "i386", EM_386 }, - /* { "m32c", EM_M32C }, Not in libelf I imported */ - { "m32r", EM_M32R }, - { "m68k", EM_68K }, - { "m68k", EM_COLDFIRE }, - { "mips", EM_MIPS }, - { "powerpc", EM_PPC }, - { "sh", EM_SH }, - { "sparc", EM_SPARC }, - { "sparc64", EM_SPARC }, - { 0, EM_NONE } - }; + memset (&shdr, 0, sizeof (shdr)); - int m = 0; - while (types_to_labels[m].machinetype != EM_NONE) + scn = ::elf_getscn (file_.get_elf (), index_); + if (!scn) + libelf_error ("elf_getscn: " + file_.name ()); + + if (!::gelf_getshdr (scn, &shdr)) + libelf_error ("gelf_getshdr: " + file_.name ()); + + if (shdr.sh_type != SHT_NULL) { - if (elf_object_machinetype == types_to_labels[m].machinetype) - return types_to_labels[m].name; - ++m; + name_ = file_.get_string (shdr.sh_name); + data_ = ::elf_getdata (scn, NULL); + if (!data_) + libelf_error ("elf_getdata: " + name_ + '(' + file_.name () + ')'); } - - std::ostringstream what; - what << "unknown machine type: " << elf_object_machinetype; - throw rld::error (what, "machine-type"); } - section::section (int index, - std::string& name, - elf_scn* scn, - elf_shdr& shdr) - : index (index), - name (name), - scn (scn), - shdr (shdr) + section::section (const section& orig) + : file_ (orig.file_), + index_ (orig.index_), + name_ (orig.name_), + scn (orig.scn), + shdr (orig.shdr), + data_ (orig.data_) { - data = ::elf_getdata (scn, NULL); - if (!data) - error ("elf_getdata"); } section::section () - : index (-1), + : file_ (0), + index_ (-1), scn (0), - data (0) + data_ (0) { memset (&shdr, 0, sizeof (shdr)); } + int + section::index () const + { + check (); + return index_; + } + + const std::string& + section::name () const + { + check (); + return name_; + } + + elf_data* + section::data () + { + check (); + return data_; + } + + elf_word + section::type () const + { + check (); + return shdr.sh_type; + } + + elf_xword + section::flags () const + { + check (); + return shdr.sh_flags; + } + + elf_addr + section::address () const + { + check (); + return shdr.sh_addr; + } + + elf_xword + section::alignment () const + { + check (); + return shdr.sh_addralign; + } + + elf_off + section::offset () const + { + check (); + return shdr.sh_offset; + } + + elf_word + section::link () const + { + check (); + return shdr.sh_link; + } + + elf_word + section::info () const + { + check (); + return shdr.sh_info; + } + + elf_xword + section::size () const + { + check (); + return shdr.sh_size; + } + + elf_xword + section::entry_size () const + { + check (); + return shdr.sh_entsize; + } + + int + section::entries () const + { + return size () / entry_size (); + } + + void + section::check () const + { + if (!file_ || (index_ < 0)) + throw rld::error ("Invalid section.", "section:check:"); + } + + file::file () + : fd_ (-1), + archive (false), + writable (false), + elf_ (0), + oclass (0), + ident_str (0), + ident_size (0) + { + memset (&ehdr, 0, sizeof (ehdr)); + memset (&phdr, 0, sizeof (phdr)); + } + + file::~file () + { + end (); + } + + void + file::begin (const std::string& name__, int fd__, const bool writable_) + { + begin (name__, fd__, writable_, 0, 0); + } + + void + file::begin (const std::string& name__, file& archive_, off_t offset) + { + archive_.check ("begin:archive"); + + if (archive_.writable) + throw rld::error ("archive is writable", "elf:file:begin"); + + begin (name__, archive_.fd_, false, &archive_, offset); + } + #define rld_archive_fhdr_size (60) void - begin (rld::files::image& image) + file::begin (const std::string& name__, + int fd__, + const bool writable_, + file* archive_, + off_t offset_) { - libelf_initialise (); + if (fd__ < 0) + throw rld::error ("no file descriptor", "elf:file:begin"); /* * Begin's are not nesting. */ - Elf* elf = image.elf (); - if (elf) - error ("begin: already done: " + image.name ().full ()); + if (elf_ || (fd_ >= 0)) + throw rld::error ("already called", "elf:file:begin"); /* - * Is this image part of an archive ? + * Cannot write directly into archive. Create a file then archive it. */ - elf = image.elf (true); - if (elf) - { - ssize_t offset = image.name ().offset () - rld_archive_fhdr_size; + if (archive_ && writable_) + throw rld::error ("cannot write into archives directly", + "elf:file:begin"); - if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::rand: " << elf << " offset:" << offset - << ' ' << image.name ().full () << std::endl; + libelf_initialise (); - if (::elf_rand (elf, offset) != offset) - error ("begin:" + image.name ().full ()); + /* + * Is this image part of an archive ? + */ + if (archive_) + { + ssize_t offset = offset_ - rld_archive_fhdr_size; + if (::elf_rand (archive_->elf_, offset) != offset) + libelf_error ("rand: " + archive_->name_); } /* * Note, the elf passed is either the archive or NULL. */ - elf = ::elf_begin (image.fd (), ELF_C_READ, elf); - if (!elf) - error ("begin:" + image.name ().full ()); + elf* elf__ = ::elf_begin (fd__, + writable_ ? ELF_C_WRITE : ELF_C_READ, + archive_ ? archive_->elf_ : 0); + if (!elf__) + libelf_error ("begin: " + name__); if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::begin: " << elf - << ' ' << image.name ().full () << std::endl; + std::cout << "elf::begin: " << elf__ << ' ' << name__ << std::endl; - image.set_elf (elf); + elf_kind ek = ::elf_kind (elf__); - elf_kind ek = ::elf_kind (elf); - if (image.name ().is_archive ()) + /* + * If this is inside an archive it must be an ELF file. + */ + + if (archive_ && (ek != ELF_K_ELF)) + throw rld::error ("File format in archive not ELF", "elf:file:begin: " + name__); + else { - if (ek != ELF_K_AR) - throw rld::error ("File not an ar archive", "libelf:" + image.name ().full ()); + if (ek == ELF_K_AR) + archive = true; + else if (ek == ELF_K_ELF) + archive = false; + else + throw rld::error ("File format not ELF or archive", + "elf:file:begin: " + name__); } - else if (ek != ELF_K_ELF) - throw rld::error ("File format not ELF", "libelf:" + image.name ().full ()); - /* - * If an ELF file make sure they all match. On the first file that begins - * an ELF session record its settings. - */ - if (ek == ELF_K_ELF) + if (!writable_) { - int cl = ::gelf_getclass (elf); - - if (elf_object_class == ELFCLASSNONE) - elf_object_class = cl; - else if (cl != elf_object_class) - throw rld::error ("Mixed classes not allowed (32bit/64bit).", - "begin:" + image.name ().full ()); - - char* ident = elf_getident (elf, NULL); - - if (elf_object_data == ELFDATANONE) - elf_object_data = ident[EI_DATA]; - else if (elf_object_data != ident[EI_DATA]) - throw rld::error ("Mixed data types not allowed (LSB/MSB).", - "begin:" + image.name ().full ()); + /* + * If an ELF file make sure they all match. On the first file that + * begins an ELF session record its settings. + */ + if (ek == ELF_K_ELF) + { + oclass = ::gelf_getclass (elf__); + ident_str = elf_getident (elf__, &ident_size); + } } + + fd_ = fd__; + name_ = name__; + writable = writable_; + elf_ = elf__; + + if (!archive) + load_header (); } void - end (rld::files::image& image) + file::end () { - ::Elf* elf = image.elf (); - if (elf) + if (elf_) { if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) - std::cout << "elf::end: " << elf - << ' ' << image.name ().full () << std::endl; - ::elf_end (elf); + std::cout << "libelf::end: " << elf_ + << ' ' << name_ << std::endl; + ::elf_end (elf_); } - image.set_elf (0); + + fd_ = -1; + name_.clear (); + archive = false; + elf_ = 0; + oclass = 0; + ident_str = 0; + ident_size = 0; + memset (&ehdr, 0, sizeof (ehdr)); + memset (&phdr, 0, sizeof (phdr)); + stab.clear (); + secs.clear (); } void - get_header (rld::files::image& image, elf_ehdr& ehdr) + file::load_header () { - if (::gelf_getehdr (image.elf (), &ehdr) == NULL) - error ("get-header:" + image.name ().full ()); - - if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_REL)) - throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", - "get-header:" + image.name ().full ()); + check ("get_header"); - if (elf_object_machinetype == EM_NONE) - elf_object_machinetype = ehdr.e_machine; - else if (elf_object_machinetype != ehdr.e_machine) + if (::gelf_getehdr (elf_, &ehdr) == NULL) + error ("get-header"); + } + + unsigned int + file::machinetype () const + { + check ("machinetype"); + return ehdr.e_machine; + } + + unsigned int + file::type () const + { + check ("type"); + return ehdr.e_type; + } + + unsigned int + file::object_class () const + { + check ("object_class"); + return oclass; + } + + unsigned int + file::data_type () const + { + check ("data_type"); + if (!ident_str) + throw rld::error ("No ELF ident str", "elf:file:data_type: " + name_); + return ident_str[EI_DATA]; + } + + bool + file::is_archive () const + { + check ("is_archive"); + return archive; + } + + bool + file::is_executable () const + { + check ("is_executable"); + return ehdr.e_type != ET_REL; + } + + bool + file::is_relocatable() const + { + check ("is_relocatable"); + return ehdr.e_type == ET_REL; + } + + int + file::section_count () const + { + check ("section_count"); + return ehdr.e_shnum; + } + + void + file::load_sections () + { + if (secs.empty ()) { - std::ostringstream oss; - oss << "get-header:" << image.name ().full () - << ": " << elf_object_machinetype << '/' << ehdr.e_machine; - throw rld::error ("Mixed machine types not supported.", oss.str ()); + check ("load_sections_headers"); + for (int sn = 0; sn < section_count (); ++sn) + secs.push_back (section (*this, sn)); } } void - get_section_headers (rld::files::object& object, - sections& secs, - unsigned int type) + file::get_sections (sections& filtered_secs, unsigned int type) { - for (int sn = 0; sn < object.sections (); ++sn) + load_sections (); + filtered_secs.clear (); + for (sections::iterator si = secs.begin (); + si != secs.end (); + ++si) { - ::Elf_Scn* scn = ::elf_getscn (object.elf (), sn); - if (!scn) - error ("elf_getscn:" + object.name ().full ()); - ::GElf_Shdr shdr; - if (!::gelf_getshdr (scn, &shdr)) - error ("gelf_getshdr:" + object.name ().full ()); - if (shdr.sh_type == type) - { - std::string name = get_string (object, - object.section_strings (), - shdr.sh_name); - secs.push_back (section (sn, name, scn, shdr)); - } + if ((type == 0) || ((*si).type () == type)) + filtered_secs.push_back (*si); } } void - load_symbol_table (rld::symbols::table& exported, - rld::files::object& object, - section& sec, - bool local, - bool weak, - bool global) - { - int count = sec.shdr.sh_size / sec.shdr.sh_entsize; - for (int s = 0; s < count; ++s) + file::load_symbols () + { + if (symbols.empty ()) { - GElf_Sym esym; - if (!::gelf_getsym (sec.data, s, &esym)) - error ("gelf_getsym"); - std::string name = get_string (object, sec.shdr.sh_link, esym.st_name); - if (!name.empty ()) + sections symbol_secs; + + get_sections (symbol_secs, SHT_SYMTAB); + + for (sections::iterator si = symbol_secs.begin (); + si != symbol_secs.end (); + ++si) { - int stype = GELF_ST_TYPE (esym.st_info); - int sbind = GELF_ST_BIND (esym.st_info); - if (rld::verbose () >= RLD_VERBOSE_TRACE) - { - rld::symbols::symbol sym (name, esym); - std::cout << "elf::symbol: "; - sym.output (std::cout); - std::cout << std::endl; - } - if ((stype == STT_NOTYPE) && (esym.st_shndx == SHN_UNDEF)) - object.unresolved_symbols ()[name] = rld::symbols::symbol (name, esym); - else if (((stype == STT_NOTYPE) || - (stype == STT_OBJECT) || - (stype == STT_FUNC)) && - ((local && (sbind == STB_LOCAL)) || - (weak && (sbind == STB_WEAK)) || - (global && (sbind == STB_GLOBAL)))) + section& sec = *si; + int syms = sec.entries (); + + for (int s = 0; s < syms; ++s) { - exported[name] = rld::symbols::symbol (name, object, esym);; - object.external_symbols ().push_back (&exported[name]); + elf_sym esym; + + if (!::gelf_getsym (sec.data (), s, &esym)) + error ("gelf_getsym"); + + std::string name = get_string (sec.link (), esym.st_name); + + if (!name.empty ()) + { + symbols::symbol sym (name, esym); + + if (rld::verbose () >= RLD_VERBOSE_TRACE) + { + std::cout << "elf::symbol: "; + sym.output (std::cout); + std::cout << std::endl; + } + + symbols.push_back (sym); + } } } } } void + file::get_symbols (symbols::pointers& filtered_syms, + bool unresolved, + bool local, + bool weak, + bool global) + { + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "elf:get-syms: unresolved:" << unresolved + << " local:" << local + << " weak:" << weak + << " global:" << global + << " " << name_ + << std::endl; + + load_symbols (); + + filtered_syms.clear (); + + for (symbols::bucket::iterator si = symbols.begin (); + si != symbols.end (); + ++si) + { + symbols::symbol& sym = *si; + + int stype = sym.type (); + int sbind = sym.binding (); + + /* + * If wanting unresolved symbols and the type is no-type and the + * section is undefined, or, the type is no-type or object or function + * and the bind is local and we want local symbols, or the bind is weak + * and we want weak symbols, or the bind is global and we want global + * symbols then add the filtered symbols container. + */ + bool add = false; + + if ((stype == STT_NOTYPE) && (sym.index () == SHN_UNDEF)) + { + if (unresolved) + add = true; + } + else if (!unresolved) + { + if (((stype == STT_NOTYPE) || + (stype == STT_OBJECT) || + (stype == STT_FUNC)) && + ((local && (sbind == STB_LOCAL)) || + (weak && (sbind == STB_WEAK)) || + (global && (sbind == STB_GLOBAL)))) + add = true; + } + + if (add) + filtered_syms.push_back (&sym); + } + } + + int + file::strings_section () const + { + check ("strings_sections"); + return ehdr.e_shstrndx; + } + + std::string + file::get_string (int section, size_t offset) + { + check ("get_string"); + char* s = ::elf_strptr (elf_, section, offset); + if (!s) + error ("elf_strptr"); + return s; + } + + std::string + file::get_string (size_t offset) + { + check ("get_string"); + char* s = ::elf_strptr (elf_, strings_section (), offset); + if (!s) + error ("elf_strptr"); + return s; + } + +#if 0 + void + file::set_header (xxx) + { + elf_ehdr* ehdr_ = ::gelf_newehdr (elf_); + + if (ehdr == NULL) + error ("set-header"); + + ehdr->xx = xx; + + ::gelf_flagphdr (elf_, ELF_C_SET , ELF_F_DIRTY); + } +#endif + + elf* + file::get_elf () + { + return elf_; + } + + const std::string& + file::name () const + { + return name_; + } + + bool + file::is_writable () const + { + return writable; + } + + void + file::check (const char* where) const + { + if (!elf_ || (fd_ < 0)) + { + std::string w = where; + throw rld::error ("no elf file or header", "elf:file:" + w); + } + } + + void + file::check_writable (const char* where) const + { + check (where); + if (!writable) + { + std::string w = where; + throw rld::error ("not writable", "elf:file:" + w); + } + } + + void + file::error (const char* where) const + { + std::string w = where; + libelf_error (w + ": " + name_); + } + + const std::string + machine_type (unsigned int machinetype) + { + struct types_and_labels + { + const char* name; //< The RTEMS label. + unsigned int machinetype; //< The machine type. + }; + types_and_labels types_to_labels[] = + { + { "arm", EM_ARM }, + { "avr", EM_AVR }, + { "bfin", EM_BLACKFIN }, + { "h8300", EM_H8_300 }, + { "i386", EM_386 }, + /* { "m32c", EM_M32C }, Not in libelf I imported */ + { "m32r", EM_M32R }, + { "m68k", EM_68K }, + { "m68k", EM_COLDFIRE }, + { "mips", EM_MIPS }, + { "powerpc", EM_PPC }, + { "sh", EM_SH }, + { "sparc", EM_SPARC }, + { "sparc64", EM_SPARC }, + { 0, EM_NONE } + }; + + int m = 0; + while (types_to_labels[m].machinetype != EM_NONE) + { + if (machinetype == types_to_labels[m].machinetype) + return types_to_labels[m].name; + ++m; + } + + std::ostringstream what; + what << "unknown machine type: " << elf_object_machinetype; + throw rld::error (what, "machine-type"); + } + + const std::string machine_type () + { + return machine_type (elf_object_machinetype); + } + + void + check_file(const file& file) + { + if (elf_object_machinetype == EM_NONE) + elf_object_machinetype = file.machinetype (); + else if (file.machinetype () != elf_object_machinetype) + { + std::ostringstream oss; + oss << "elf:check_file:" << file.name () + << ": " << elf_object_machinetype << '/' << file.machinetype (); + throw rld::error ("Mixed machine types not supported.", oss.str ()); + } + + if (elf_object_class == ELFCLASSNONE) + elf_object_class = file.object_class (); + else if (file.object_class () != elf_object_class) + throw rld::error ("Mixed classes not allowed (32bit/64bit).", + "elf:check_file: " + file.name ()); + + if (elf_object_data == ELFDATANONE) + elf_object_data = file.data_type (); + else if (elf_object_data != file.data_type ()) + throw rld::error ("Mixed data types not allowed (LSB/MSB).", + "elf:check_file: " + file.name ()); + } + +#if 0 + void load_symbols (rld::symbols::table& symbols, - rld::files::object& object, + rld::files::object& object, bool local, bool weak, bool global) @@ -314,17 +720,7 @@ namespace rld ++si) load_symbol_table (symbols, object, *si, local, weak, global); } - - std::string - get_string (rld::files::object& object, - int section, - size_t offset) - { - char* s = ::elf_strptr (object.elf (), section, offset); - if (!s) - error ("elf_strptr"); - return s; - } +#endif } } @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -34,87 +34,360 @@ namespace rld namespace elf { /** - * Sections. + * Forward decl. */ - struct section + class file; + + /** + * An ELF Section. + */ + class section { - int index; //< The section header index. - std::string name; //< The section's name. - elf_scn* scn; //< ELF private section data. - elf_shdr shdr; //< The section header. - elf_data* data; //< The section's data. - + public: + /** + * Construct the section getting the details. + * + * @param elf The ELF file this section is part of. + * @param index The sections index in the ELF file. + */ + section (file& file_, int index); + /** - * Construct the section and get the data value. + * Copy constructor. */ - section (int index, - std::string& name, - elf_scn* scn, - elf_shdr& sdhr); + section (const section& orig); /** * Default constructor. */ section (); + + /** + * The section's index in the ELF file. + * + * @return int The section number. + */ + int index () const; + + /** + * The name of the section. + * + * @return const std::string& The section's name. + */ + const std::string& name () const; + + /** + * The section's data. + */ + elf_data* data (); + + /** + * Get the type of the section. + */ + elf_word type () const; + + /** + * The section flags. + */ + elf_xword flags () const; + + /** + * In-memory address of the section. + */ + elf_addr address () const; + + /** + * Alignment constraint. + */ + elf_xword alignment () const; + + /** + * The file offset of the section. + */ + elf_off offset () const; + + /** + * The header table link. + */ + elf_word link () const; + + /** + * Extra information. + */ + elf_word info () const; + + /** + * Size of the section. + */ + elf_xword size () const; + + /** + * Size of the entries in the section. + */ + elf_xword entry_size () const; + + /** + * Number of entries. + */ + int entries () const; + + private: + + /** + * Check the section is acrtual valid. + */ + void check () const; + + file* file_; //< The ELF file. + int index_; //< The section header index. + std::string name_; //< The section's name. + elf_scn* scn; //< ELF private section data. + elf_shdr shdr; //< The section header. + elf_data* data_; //< The section's data. }; /** - * Container of section headers. + * Container of ELF sections. */ typedef std::list < section > sections; /** - * Get the machine type detected in the object files as their headers are read. + * An ELF file. */ - const std::string machine_type (); + class file + { + public: + /** + * Construct an ELF file. + */ + file (); - /** - * Begin a libelf session with the image. - */ - void begin (rld::files::image& image); + /** + * Destruct the ELF file object. + */ + ~file (); - /** - * End the libelf session with the image. - */ - void end (rld::files::image& image); + /** + * Begin using the ELF file. + * + * @param name The full name of the file. + * @param fd The file descriptor to read or write the file. + * @param writable The file is writeable. The default is false. + */ + void begin (const std::string& name, int fd, const bool writable = false); - /** - * Get the ELF header. - */ - void get_header (rld::files::image& image, elf_ehdr& ehdr); + /** + * Begin using the ELF file in an archive. + * + * @param name The full name of the file. + * @param archive The file that is the archive. + * @param offset The offset of the ELF file in the archive. + */ + void begin (const std::string& name, file& archive, off_t offset); + + /** + * End using the ELF file. + */ + void end (); + + /** + * Load the header. Done automatically. + */ + void load_header (); + + /** + * Get the machine type. + */ + unsigned int machinetype () const; + + /** + * Get the type of ELF file. + */ + unsigned int type () const; + + /** + * Get the class of the object file. + */ + unsigned int object_class () const; + + /** + * Get the data type, ie LSB or MSB. + */ + unsigned int data_type () const; + + /** + * Is the file an archive format file ? + */ + bool is_archive () const; + + /** + * Is the file an executable ? + */ + bool is_executable () const; + + /** + * Is the file relocatable ? + */ + bool is_relocatable() const; + + /** + * The number of sections in the file. + */ + int section_count () const; + + /** + * Load the sections. + */ + void load_sections (); + + /** + * Get a filtered container of the sections. The key is the section + * type. If the sections are not loaded they are loaded. If the type is 0 + * all sections are returned. + * + * @param filtered_secs The container the copy of the filtered sections + * are placed in. + * @param type The type of sections to filter on. If 0 all sections are + * matched. + */ + void get_sections (sections& filtered_secs, unsigned int type); + + /** + * Return the index of the string section. + */ + int strings_section () const; + + /** + * Get the string from the specified section at the requested offset. + * + * @param section The section to search for the string. + * @param offset The offset in the string section. + * @return std::string The string. + */ + std::string get_string (int section, size_t offset); + + /** + * Get the string from the ELF header declared string section at the + * requested offset. + * + * @param offset The offset in the string section. + * @return std::string The string. + */ + std::string get_string (size_t offset); + + /** + * Load the symbols. + */ + void load_symbols (); + + /** + * Get a filtered container of symbols given the various types. If the + * symbols are not loaded they are loaded. + * + * @param filter_syms The filtered symbols found in the file. This is a + * container of pointers. + * @param local Return local symbols. + * @param weak Return weak symbols. + * @param global Return global symbols. + * @param unresolved Return unresolved symbols. + */ + void get_symbols (rld::symbols::pointers& filtered_syms, + bool unresolved = false, + bool local = false, + bool weak = true, + bool global = true); + + /** + * Get the ELF reference. + */ + elf* get_elf (); + + /** + * Get the name of the file. + */ + const std::string& name () const; + + /** + * Is the file writable ? + */ + bool is_writable () const; + + private: + + /** + * Begin using the ELF file. + * + * @param name The full name of the file. + * @param fd The file descriptor to read or write the file. + * @param writable The file is writeable. It cannot be part of an archive. + * @param archive The archive's ELF handle or 0 if not an archive. + * @param offset The offset of the ELF file in the archive if elf is non-zero. + */ + void begin (const std::string& name, + int fd, + const bool writable, + file* archive, + off_t offset); + + /** + * Check if the file is usable. Throw an exception if not. + * + * @param where Where the check is performed. + */ + void check (const char* where) const; + + /** + * Check if the file is usable and writable. Throw an exception if not. + * + * @param where Where the check is performed. + */ + void check_writable (const char* where) const; + + /** + * Generate libelf error. + * + * @param where Where the error is generated. + */ + void error (const char* where) const; + + int fd_; //< The file handle. + std::string name_; //< The name of the file. + bool archive; //< The ELF file is part of an archive. + bool writable; //< The file is writeable. + elf* elf_; //< The ELF handle. + unsigned int mtype; //< The machine type. + unsigned int oclass; //< The object class. + const char* ident_str; //< The ELF file's ident string. + size_t ident_size; //< The size of the ident. + elf_ehdr ehdr; //< The ELF header. + elf_phdr phdr; //< The ELF program header. + std::string stab; //< The string table. + sections secs; //< The sections. + rld::symbols::bucket symbols; //< The symbols. All tables point here. + }; /** - * Get the section headers for an object file. - */ - void get_section_headers (rld::files::object& object, - sections& secs, - unsigned int type = SHT_NULL); - - /** - * Load the symbol table with the symbols. + * Return the machine type label given the machine type. + * + * @param machinetype The ELF machine type. */ - void load_symbol_table (rld::symbols::table& exported, - rld::files::object& object, - section& sec, - bool local = false, - bool weak = true, - bool global = true); - + const std::string machine_type (unsigned int machinetype); + /** - * Load the symbol table with an object's symbols. + * Return the global machine type set by the check_file call. */ - void load_symbols (rld::symbols::table& symbols, - rld::files::object& object, - bool local = false, - bool weak = true, - bool global = true); + const std::string machine_type (); /** - * Get a string. + * Check the file against the global machine type, object class and data + * type. If this is the first file checked it becomes the default all + * others are checked against. This is a simple way to make sure all files + * are the same type. + * + * @param file The check to check. */ - std::string get_string (rld::files::object& object, - int section, - size_t offset); + void check_file(const file& file); + } } diff --git a/rld-files.cpp b/rld-files.cpp index d44474b..108f920 100644 --- a/rld-files.cpp +++ b/rld-files.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -45,7 +45,7 @@ namespace rld scan_decimal (const uint8_t* string, size_t len) { uint64_t value = 0; - + while (len && (*string != ' ')) { value *= 10; @@ -104,7 +104,7 @@ namespace rld joined = path_ + RLD_PATH_SEPARATOR + file_; else if ((path_[path_.size () - 1] == RLD_PATH_SEPARATOR) && (file_[0] == RLD_PATH_SEPARATOR)) - joined = path_ + &file_[1]; + joined = path_ + &file_[1]; else joined = path_ + file_; } @@ -147,7 +147,7 @@ namespace rld const std::string& oname, off_t offset, size_t size) - : aname_ (aname), + : aname_ (aname), oname_ (oname), offset_ (offset), size_ (size) @@ -246,8 +246,8 @@ namespace rld return aname_; return oname_; } - - const std::string + + const std::string file::full () const { std::string f; @@ -297,8 +297,7 @@ namespace rld image::image (file& name) : name_ (name), references_ (0), - fd_ (-1), - elf_ (0) + fd_ (-1) { } @@ -306,15 +305,14 @@ namespace rld : name_ (path, is_object), references_ (0), fd_ (-1), - elf_ (0), - symbol_refs (0) + symbol_refs (0), + writeable (false) { } image::image () : references_ (0), fd_ (-1), - elf_ (0), symbol_refs (0) { } @@ -335,26 +333,34 @@ namespace rld } void - image::open (bool writable) + image::open (bool writeable_) { const std::string path = name_.path (); if (path.empty ()) - throw rld::error ("No file name", "open" + path); + throw rld::error ("No file name", "open:" + path); if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "image::open: " << name (). full () + << " writable:" << (char*) (writeable_ ? "yes" : "no") << " refs:" << references_ + 1 << std::endl; if (fd_ < 0) { - if (writable) + writeable = writeable_; + + if (writeable) fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDWR | O_CREAT | O_TRUNC, CREATE_MODE); else fd_ = ::open (path.c_str (), OPEN_FLAGS | O_RDONLY); if (fd_ < 0) throw rld::error (::strerror (errno), "open:" + path); } + else + { + if (writeable_ != writeable) + throw rld::error ("Cannot change write status", "open:" + path); + } ++references_; } @@ -385,7 +391,7 @@ namespace rld throw rld::error (strerror (errno), "read:" + name ().path ()); return rsize; } - + ssize_t image::write (const void* buffer, size_t size) { @@ -394,28 +400,28 @@ namespace rld throw rld::error (strerror (errno), "write:" + name ().path ()); return wsize; } - + void image::seek (off_t offset) { if (::lseek (fd (), name_.offset () + offset, SEEK_SET) < 0) throw rld::error (strerror (errno), "lseek:" + name ().path ()); } - + bool image::seek_read (off_t offset, uint8_t* buffer, size_t size) { seek (offset); return size == (size_t) read (buffer, size); } - + bool image::seek_write (off_t offset, const void* buffer, size_t size) { seek (offset); return size == (size_t) write (buffer, size); } - + const file& image::name () const { @@ -423,41 +429,35 @@ namespace rld } int - image::references () const + image::references () const { return references_; } size_t - image::size () const + image::size () const { return name ().size (); } int - image::fd () const + image::fd () const { return fd_; } - rld::elf::elf* - image::elf (bool ) + rld::elf::file& + image::elf () { return elf_; } void - image::set_elf (rld::elf::elf* elf) - { - elf_ = elf; - } - - void image::symbol_referenced () { ++symbol_refs; } - + int image::symbol_references () const { @@ -474,6 +474,10 @@ namespace rld buffer = new uint8_t[COPY_FILE_BUFFER_SIZE]; while (size) { + /* + * @fixme the reading and writing are not POSIX; sigints could split them. + */ + size_t l = size < COPY_FILE_BUFFER_SIZE ? size : COPY_FILE_BUFFER_SIZE; ssize_t r = ::read (in.fd (), buffer, l); @@ -545,6 +549,25 @@ namespace rld close (); } + void + archive::begin () + { + elf ().begin (name ().full (), fd ()); + + /* + * Make sure it is an archive. + */ + if (!elf ().is_archive ()) + throw rld::error ("Not an archive.", + "archive-begin:" + name ().full ()); + } + + void + archive::end () + { + elf ().end (); + } + bool archive::is (const std::string& path) const { @@ -580,8 +603,8 @@ namespace rld /* * The archive file headers are always aligned to an even address. */ - size = - (scan_decimal (&header[rld_archive_size], + size = + (scan_decimal (&header[rld_archive_size], rld_archive_size_size) + 1) & ~1; /* @@ -625,15 +648,15 @@ namespace rld off_t off = offset; while (extended_file_names == 0) { - size_t esize = + size_t esize = (scan_decimal (&header[rld_archive_size], rld_archive_size_size) + 1) & ~1; off += esize + rld_archive_fhdr_size; - + if (!read_header (off, &header[0])) throw rld::error ("No GNU extended file name section found", "get-names:" + name ().path ()); - + if ((header[0] == '/') && (header[1] == '/')) { extended_file_names = off + rld_archive_fhdr_size; @@ -693,7 +716,7 @@ namespace rld (header[rld_archive_magic + 1] != 0x0a)) throw rld::error ("Invalid header magic numbers at " + rld::to_string (offset), "read-header:" + name ().path ()); - + return true; } @@ -725,7 +748,7 @@ namespace rld uint8_t header[rld_archive_fhdr_size]; memset (header, ' ', sizeof (header)); - + size_t len = name.length (); if (len > rld_archive_fname_size) len = rld_archive_fname_size; @@ -756,7 +779,7 @@ namespace rld * GNU extended filenames. */ std::string extended_file_names; - + for (object_list::iterator oi = objects.begin (); oi != objects.end (); ++oi) @@ -818,7 +841,7 @@ namespace rld close (); throw; } - + close (); } @@ -877,16 +900,34 @@ namespace rld object::begin () { /* - * Begin an ELF session and get the ELF header. + * Begin a session. + */ + if (archive_) + elf ().begin (name ().full (), archive_->elf(), name ().offset ()); + else + elf ().begin (name ().full (), fd ()); + + /* + * Cannot be an archive. */ - rld::elf::begin (*this); - rld::elf::get_header (*this, ehdr); + if (elf ().is_archive ()) + throw rld::error ("Is an archive not an object file.", + "object-begin:" + name ().full ()); + + /* + * We only support executable or relocatable ELF files. + */ + if (!elf ().is_executable () && !elf ().is_relocatable ()) + throw rld::error ("Invalid ELF type (only ET_EXEC/ET_REL supported).", + "object-begin:" + name ().full ()); + + elf::check_file (elf ()); } void object::end () { - rld::elf::end (*this); + elf ().end (); } void @@ -894,17 +935,58 @@ namespace rld { if (rld::verbose () >= RLD_VERBOSE_DETAILS) std::cout << "object:load-sym: " << name ().full () << std::endl; - rld::elf::load_symbols (symbols, *this, local); - } - std::string - object::get_string (int section, size_t offset) - { - return rld::elf::get_string (*this, section, offset); + rld::symbols::pointers syms; + + elf ().get_symbols (syms, false, local); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "object:load-sym: exported: total " + << syms.size () << std::endl; + + for (symbols::pointers::iterator si = syms.begin (); + si != syms.end (); + ++si) + { + symbols::symbol& sym = *(*si); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + { + std::cout << "object:load-sym: exported: "; + sym.output (std::cout); + std::cout << std::endl; + } + + sym.set_object (*this); + symbols[sym.name ()] = &sym; + externals.push_back (&sym); + } + + elf ().get_symbols (syms, true); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + std::cout << "object:load-sym: unresolved: total " + << syms.size () << std::endl; + + for (symbols::pointers::iterator si = syms.begin (); + si != syms.end (); + ++si) + { + symbols::symbol& sym = *(*si); + + if (rld::verbose () >= RLD_VERBOSE_DETAILS) + { + std::cout << "object:load-sym: unresolved: "; + sym.output (std::cout); + std::cout << std::endl; + } + + unresolved[sym.name ()] = &sym; + } } - + int - object::references () const + object::references () const { if (archive_) return archive_->references (); @@ -912,7 +994,7 @@ namespace rld } size_t - object::size () const + object::size () const { if (archive_) return archive_->size (); @@ -920,21 +1002,13 @@ namespace rld } int - object::fd () const + object::fd () const { if (archive_) return archive_->fd (); return image::fd (); } - rld::elf::elf* - object::elf (bool archive__) - { - if (archive__ && archive_) - return archive_->elf (); - return image::elf (); - } - void object::symbol_referenced () { @@ -942,13 +1016,14 @@ namespace rld if (archive_) archive_->symbol_referenced (); } - + archive* object::get_archive () { return archive_; } +#if 0 int object::sections () const { @@ -960,6 +1035,7 @@ namespace rld { return ehdr.e_shstrndx; } +#endif rld::symbols::table& object::unresolved_symbols () @@ -967,7 +1043,7 @@ namespace rld return unresolved; } - rld::symbols::list& + rld::symbols::pointers& object::external_symbols () { return externals; @@ -1047,7 +1123,7 @@ namespace rld if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "cache:archive-begin: " << path << std::endl; ar->open (); - rld::elf::begin (*ar); + ar->begin (); } } } @@ -1063,7 +1139,7 @@ namespace rld { if (rld::verbose () >= RLD_VERBOSE_TRACE) std::cout << "cache:archive-end: " << path << std::endl; - rld::elf::end (*ar); + ar->end (); ar->close (); } } @@ -1082,7 +1158,7 @@ namespace rld for (archives::iterator ai = archives_.begin (); ai != archives_.end (); ++ai) archive_end (((*ai).second)->path ()); } - + void cache::collect_object_files () { @@ -1173,7 +1249,7 @@ namespace rld { return archives_; } - + objects& cache::get_objects () { diff --git a/rld-files.h b/rld-files.h index 976f60a..26c7723 100644 --- a/rld-files.h +++ b/rld-files.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -26,7 +26,7 @@ * 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_) @@ -67,7 +67,7 @@ namespace rld * Container list of object files. */ typedef std::list < object* > object_list; - + /** * Split a path from a string with a delimiter to the path container. Add * only the paths that exist and ignore those that do not. @@ -78,8 +78,8 @@ namespace rld /** * Make a path by joining the parts with required separator. */ - void path_join (const std::string& path_, - const std::string& file_, + void path_join (const std::string& path_, + const std::string& file_, std::string& joined); /** @@ -91,7 +91,7 @@ namespace rld * Check the path is a directory. */ bool check_directory (const std::string& path); - + /** * Find the file given a container of paths and file names. * @@ -99,7 +99,7 @@ namespace rld * @param name The name of the file to search for. * @param search_paths The container of paths to search. */ - void find_file (std::string& path, + void find_file (std::string& path, const std::string& name, paths& search_paths); @@ -323,15 +323,9 @@ namespace rld virtual int fd () const; /** - * The libelf reference. The ELF image could be in an archive container - * so set container to true to get the archive's reference. + * The ELF reference. */ - virtual rld::elf::elf* elf (bool archive = false); - - /** - * Set the libelf reference. - */ - void set_elf (rld::elf::elf* elf); + elf::file& elf (); /** * A symbol in the image has been referenced. @@ -353,21 +347,33 @@ namespace rld } /** - * Is the archive open ? + * Is the image open ? * - * @retval true The archive is open. - * @retval false The archive is not 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 writeable. + * @retval false The image is not writeable. + */ + bool is_writeable () const { + return writeable; + } + private: + file name_; //< The name of the file. int references_; //< The number of handles open. int fd_; //< The file descriptor of the archive. - elf::elf* elf_; //< The libelf reference. + elf::file elf_; //< The libelf reference. int symbol_refs; //< The number of symbols references made. + bool writeable; //< The image is writable. }; /** @@ -396,6 +402,16 @@ namespace rld 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. @@ -413,7 +429,7 @@ namespace rld * Load objects. */ void load_objects (objects& objs); - + /** * Get the name. */ @@ -431,6 +447,7 @@ namespace rld void create (object_list& objects); private: + /** * Read header. */ @@ -441,7 +458,7 @@ namespace rld */ void add_object (objects& objs, const char* name, - off_t offset, + off_t offset, size_t size); /** @@ -528,7 +545,7 @@ namespace rld /** * Get the string from the string table. */ - std::string get_string (int section, size_t offset); +// std::string get_string (int section, size_t offset); /** * References to the image. @@ -546,12 +563,6 @@ namespace rld virtual int fd () const; /** - * The libelf reference. The ELF image could be in an archive container - * so set container to true to get the archive's reference. - */ - virtual elf::elf* elf (bool archive = false); - - /** * A symbol in the image has been referenced. */ virtual void symbol_referenced (); @@ -562,6 +573,7 @@ namespace rld */ archive* get_archive (); +#if 0 /** * Number of sections in the object file. */ @@ -571,6 +583,7 @@ namespace rld * Section string index. */ int section_strings () const; +#endif /** * Return the unresolved symbol table for this object file. @@ -580,14 +593,13 @@ namespace rld /** * Return the list external symbols. */ - rld::symbols::list& external_symbols (); + rld::symbols::pointers& external_symbols (); private: - archive* archive_; //< Points to the archive if part of an - // archive. - elf::elf_ehdr ehdr; //< The ELF header. - rld::symbols::table unresolved; //< This object's unresolved symbols. - rld::symbols::list externals; //< This object's external symbols. + archive* archive_; //< Points to the archive if part of + // an archive. + rld::symbols::table unresolved; //< This object's unresolved symbols. + rld::symbols::pointers externals; //< This object's external symbols. /** * Cannot copy via a copy constructor. @@ -644,22 +656,22 @@ namespace rld void add_libraries (paths& paths__); /** - * Being an ELF session on an archive. + * Being a session on an archive. */ void archive_begin (const std::string& path); /** - * End an ELF session on an archive. + * End a session on an archive. */ void archive_end (const std::string& path); /** - * Being ELF sessions on all archives. + * Being sessions on all archives. */ void archives_begin (); /** - * End the archive elf sessions. + * End the archive sessions. */ void archives_end (); @@ -667,13 +679,13 @@ namespace rld * 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. * @@ -691,12 +703,12 @@ namespace rld * 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. */ diff --git a/rld-outputter.cpp b/rld-outputter.cpp index ef18d5d..bdd9dfa 100644 --- a/rld-outputter.cpp +++ b/rld-outputter.cpp @@ -68,7 +68,7 @@ namespace rld ursi != unresolved.begin (); ++ursi) { - rld::symbols::symbol& urs = (*ursi).second; + rld::symbols::symbol& urs = *((*ursi).second); ++count; @@ -98,6 +98,8 @@ namespace rld ++oi) objects.push_back (*oi); + objects.unique (); + rld::files::archive arch (name); arch.create (objects); } @@ -128,46 +130,6 @@ namespace rld } out.close (); - -#if 0 - rld::files::object_list objects; - cache.get_objects (objects); - - for (rld::files::object_list::iterator oi = objects.begin (); - oi != objects.end (); - ++oi) - { - rld::files::object& obj = *(*oi); - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << " o: " << obj.name ().full () << std::endl; - - out << "o:" << obj.name ().basename () << std::endl; - } - - for (rld::files::object_list::iterator oi = dependents.begin (); - oi != dependents.end (); - ++oi) - { - rld::files::object& obj = *(*oi); - rld::symbols::table& unresolved = obj.unresolved_symbols (); - - if (rld::verbose () >= RLD_VERBOSE_INFO) - std::cout << " d: " << obj.name ().full () << std::endl; - - out << "d:" << obj.name ().basename () << std::endl; - - int count = 0; - for (rld::symbols::table::iterator ursi = unresolved.begin (); - ursi != unresolved.begin (); - ++ursi) - { - ++count; - rld::symbols::symbol& urs = (*ursi).second; - out << " u:" << count << ':' << urs.name () << std::endl; - } - } -#endif } } } diff --git a/rld-resolver.cpp b/rld-resolver.cpp index fe75754..60b69ef 100644 --- a/rld-resolver.cpp +++ b/rld-resolver.cpp @@ -54,7 +54,7 @@ namespace rld * unresolved symbol's object file to the file that resolves the * symbol. Record each object file that is found and when all unresolved * symbols in this object file have been found iterate over the found - * object files resolving them. The 'usr' is the unresolved symbol and + * object files resolving them. The 'urs' is the unresolved symbol and * 'es' is the exported symbol. */ @@ -66,19 +66,26 @@ namespace rld << object.name ().basename () << ", unresolved: " << unresolved.size () - << ((*unresolved.begin ()).second.object () ? " (resolved)" : "") + << (((*unresolved.begin ()).second)->object () ? " (resolved)" : "") << std::endl; rld::files::object_list objects; for (rld::symbols::table::iterator ursi = unresolved.begin (); - (ursi != unresolved.end ()) && !(*ursi).second.object (); + (ursi != unresolved.end ()) && !((*ursi).second)->object (); ++ursi) { - rld::symbols::symbol& urs = (*ursi).second; + rld::symbols::symbol& urs = *((*ursi).second); rld::symbols::table::iterator esi = base_symbols.find (urs.name ()); bool base = true; + if (rld::verbose () >= RLD_VERBOSE_INFO) + { + std::cout << "resolver:resolve : " + << std::setw (nesting + 1) << ' ' + << urs.name () << std::endl; + } + if (esi == base_symbols.end ()) { esi = symbols.find (urs.name ()); @@ -88,7 +95,7 @@ namespace rld base = false; } - rld::symbols::symbol& es = (*esi).second; + rld::symbols::symbol& es = *((*esi).second); if (rld::verbose () >= RLD_VERBOSE_INFO) { diff --git a/rld-symbols.cpp b/rld-symbols.cpp index 7c55869..127bb2f 100644 --- a/rld-symbols.cpp +++ b/rld-symbols.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -57,7 +57,7 @@ namespace rld } symbol::symbol (const std::string& name, - rld::files::object& object, + files::object& object, const elf::elf_sym& esym) : name_ (name), object_ (&object), @@ -104,13 +104,13 @@ namespace rld esym_.st_value = value; } - const std::string& + const std::string& symbol::name () const { return name_; } - const std::string& + const std::string& symbol::demangled () const { return demangled_; @@ -122,25 +122,43 @@ namespace rld return (name_[0] == '_') && (name_[1] == 'Z'); } + int + symbol::type () const + { + return GELF_ST_TYPE (esym_.st_info); + } + + int + symbol::binding () const + { + return GELF_ST_BIND (esym_.st_info); + } + + int + symbol::index () const + { + return esym_.st_shndx; + } + rld::files::object* symbol::object () const { return object_; } - + void symbol::set_object (rld::files::object& obj) { object_ = &obj; } - const elf::elf_sym& + const elf::elf_sym& symbol::esym () const { return esym_; } - void + void symbol::referenced () { ++references_; @@ -148,7 +166,7 @@ namespace rld object_->symbol_referenced (); } - bool + bool symbol::operator< (const symbol& rhs) const { return name_ < rhs.name_; @@ -207,14 +225,14 @@ namespace rld break; } - out << binding + out << binding << ' ' << type - << " 0x" << std::setw (8) << std::setfill ('0') << std::hex - << es.st_value + << " 0x" << std::setw (8) << std::setfill ('0') << std::hex + << es.st_value << std::dec << std::setfill (' ') << ' ' << std::setw (7) << es.st_size << ' '; - + if (is_cplusplus ()) out << demangled (); else @@ -224,15 +242,27 @@ namespace rld out << " (" << object ()->name ().basename () << ')'; } + void + load (bucket& bucket_, table& table_) + { + for (bucket::iterator sbi = bucket_.begin (); + sbi != bucket_.end (); + ++sbi) + { + symbol& sym = *sbi; + table_[sym.name ()] = &sym; + } + } + size_t - referenced (list& symbols) + referenced (pointers& symbols) { size_t used = 0; - for (rld::symbols::list::iterator sli = symbols.begin (); + for (pointers::iterator sli = symbols.begin (); sli != symbols.end (); ++sli) { - rld::symbols::symbol& sym = *(*sli); + symbol& sym = *(*sli); if (sym.references ()) ++used; } @@ -249,7 +279,7 @@ namespace rld si != symbols.end (); ++si) { - const symbol& sym = (*si).second; + const symbol& sym = *((*si).second); out << std::setw (5) << index << ' ' << sym << std::endl; ++index; } diff --git a/rld-symbols.h b/rld-symbols.h index ec6938d..f566efe 100644 --- a/rld-symbols.h +++ b/rld-symbols.h @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -58,27 +58,27 @@ namespace rld /** * Construct an exported symbol with a object file. */ - symbol (const std::string& name, - rld::files::object& object, + symbol (const std::string& name, + files::object& object, const elf::elf_sym& esym); /** * Construct an unresolved symbol with no object file. */ symbol (const std::string& name, const elf::elf_sym& esym); - + /** * Construct a linker symbol that is internally created. */ symbol (const std::string& name, const elf::elf_addr value); - + /** * Construct a linker symbol that is internally created. */ - symbol (const char* name, - rld::elf::elf_addr value = 0); - + symbol (const char* name, + elf::elf_addr value = 0); + /** * The symbol's name. */ @@ -95,20 +95,35 @@ namespace rld bool is_cplusplus () const; /** + * The symbol's type. + */ + int type () const; + + /** + * The symbol's binding, ie local, weak, or global. + */ + int binding () const; + + /** + * The synbol's section index. + */ + int index () const; + + /** * The symbol's object file name. */ - rld::files::object* object () const; + files::object* object () const; /** * Set the symbol's object file name. Used when resolving unresolved * symbols. */ - void set_object (rld::files::object& obj); + void set_object (files::object& obj); /** * The ELF symbol. */ - const ::GElf_Sym& esym () const; + const elf::elf_sym& esym () const; /** * Return the number of references. @@ -133,28 +148,39 @@ namespace rld void output (std::ostream& out) const; private: - std::string name_; //< The name of the symbol. - std::string demangled_; //< If a C++ symbol the demangled name. - rld::files::object* object_; //< The object file containing the - // symbol. - ::GElf_Sym esym_; //< The ELF symbol. - int references_; //< The number of times if it referenced. + + std::string name_; //< The name of the symbol. + std::string demangled_; //< If a C++ symbol the demangled name. + files::object* object_; //< The object file containing the symbol. + elf::elf_sym esym_; //< The ELF symbol. + int references_; //< The number of times if it referenced. }; /** - * List of symbol references. + * Container of symbols. A bucket of symbols. + */ + typedef std::list < symbol > bucket; + + /** + * References to symbols. Should always point to symbols held in a bucket. + */ + typedef std::list < symbol* > pointers; + + /** + * A symbols table is a map container of symbols. Should always point to + * symbols held in a bucket. */ - typedef std::list < symbol* > list; + typedef std::map < std::string, symbol* > table; /** - * A symbols table is a map container of symbols. + * Load a table from a buckey. */ - typedef std::map < std::string, symbol > table; + void load (bucket& bucket_, table& table_); /** - * Given a list of symbols return how many are referenced. + * Given a container of symbols return how many are referenced. */ - size_t referenced (list& symbols); + size_t referenced (pointers& symbols); /** * Output the symbol table. @@ -166,7 +192,8 @@ namespace rld /** * Output stream operator. */ -static inline std::ostream& operator<< (std::ostream& out, const rld::symbols::symbol& sym) { +static inline std::ostream& operator<< (std::ostream& out, + const rld::symbols::symbol& sym) { sym.output (out); return out; } @@ -1,10 +1,10 @@ /* - * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> + * Copyright (c) 2011, Chris Johns <chrisj@rtems.org> * * 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 @@ -64,7 +64,7 @@ namespace rld * The output passed on the command line. */ static std::string output; - + void verbose_inc () { @@ -116,7 +116,7 @@ namespace rld std::cout << "Archive files : " << cache.archive_count () << std::endl; std::cout << "Object files : " << cache.object_count () << std::endl; std::cout << "Exported symbols : " << symbols.size () << std::endl; - + std::cout << "Archives:" << std::endl; cache.output_archive_files (std::cout); std::cout << "Objects:" << std::endl; @@ -136,9 +136,9 @@ namespace rld oli != objects.end (); ++oli) { - rld::files::object& object = *(*oli); - rld::symbols::list& externals = object.external_symbols (); - + rld::files::object& object = *(*oli); + rld::symbols::pointers& externals = object.external_symbols (); + if (rld::symbols::referenced (externals) != externals.size ()) { if (first) @@ -149,7 +149,7 @@ namespace rld std::cout << ' ' << object.name ().basename () << std::endl; - for (rld::symbols::list::iterator sli = externals.begin (); + for (rld::symbols::pointers::iterator sli = externals.begin (); sli != externals.end (); ++sli) { @@ -155,24 +155,26 @@ main (int argc, char* argv[]) try { - rld::files::cache cache; - rld::files::cache base; - rld::files::paths libpaths; - rld::files::paths libs; - rld::files::paths objects; - rld::files::paths libraries; - rld::symbols::table base_symbols; - rld::symbols::table symbols; - rld::symbols::table undefined; - std::string entry; - std::string output = "a.out"; - std::string base_name; - std::string cc_name; - bool script = false; - bool standard_libs = true; - bool exec_prefix_set = false; - bool map = false; - bool warnings = false; + rld::files::cache cache; + rld::files::cache base; + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths objects; + rld::files::paths libraries; + rld::symbols::bucket defines; + rld::symbols::bucket undefines; + rld::symbols::table base_symbols; + rld::symbols::table symbols; + rld::symbols::table undefined; + std::string entry; + std::string output = "a.out"; + std::string base_name; + std::string cc_name; + bool script = false; + bool standard_libs = true; + bool exec_prefix_set = false; + bool map = false; + bool warnings = false; libpaths.push_back ("."); @@ -254,11 +256,11 @@ main (int argc, char* argv[]) break; case 'd': - symbols[optarg] = rld::symbols::symbol (optarg); + defines.push_back (rld::symbols::symbol (optarg)); break; case 'u': - undefined[optarg] = rld::symbols::symbol (optarg); + undefines.push_back (rld::symbols::symbol (optarg)); break; case 'b': @@ -295,6 +297,17 @@ main (int argc, char* argv[]) objects.push_back (*argv++); /* + * Load the symbol table with the defined symbols from the defines bucket. + */ + rld::symbols::load (defines, symbols); + + /* + * Load the undefined table with the undefined symbols from the undefines + * bucket. + */ + rld::symbols::load (undefines, undefined); + + /* * Add the object files to the cache. */ cache.add (objects); @@ -397,7 +410,7 @@ main (int argc, char* argv[]) int status; char* realname; realname = abi::__cxa_demangle (e.what(), 0, 0, &status); - std::cerr << "error: std::exception: " << realname << " ["; + std::cerr << "error: exception: " << realname << " ["; ::free (realname); const std::type_info &ti = typeid (e); realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); diff --git a/rtems-syms.cpp b/rtems-syms.cpp new file mode 100644 index 0000000..822e0e6 --- /dev/null +++ b/rtems-syms.cpp @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2011-2012, Chris Johns <chrisj@rtems.org> + * + * 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_rld + * + * @brief RTEMS Symbols Main manages opions, sequence of operations and exceptions. + * + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <iostream> + +#include <cxxabi.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <getopt.h> + +#include <rld.h> +#include <rld-cc.h> +#include <rld-outputter.h> +#include <rld-process.h> +#include <rld-resolver.h> + +#ifndef HAVE_KILL +#define kill(p,s) raise(s) +#endif + +/** + * RTEMS Linker options. This needs to be rewritten to be like cc where only a + * single '-' and long options is present. + */ +static struct option rld_opts[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "verbose", no_argument, NULL, 'v' }, + { "warn", no_argument, NULL, 'w' }, + { "lib-path", required_argument, NULL, 'L' }, + { "lib", required_argument, NULL, 'l' }, + { "no-stdlibs", no_argument, NULL, 'n' }, + { "cc", required_argument, NULL, 'C' }, + { "exec-prefix", required_argument, NULL, 'E' }, + { "march", required_argument, NULL, 'a' }, + { "mcpu", required_argument, NULL, 'c' }, + { NULL, 0, NULL, 0 } +}; + +void +usage (int exit_code) +{ + std::cout << "rtems-syms [options] objects" << std::endl + << "Options and arguments:" << std::endl + << " -h : help (also --help)" << std::endl + << " -V : print linker version number and exit (also --version)" << std::endl + << " -v : verbose (trace import parts), can be supply multiple times" << std::endl + << " to increase verbosity (also --verbose)" << std::endl + << " -w : generate warnings (also --warn)" << std::endl + << " -L path : path to a library, add multiple for more than" << std::endl + << " one path (also --lib-path)" << std::endl + << " -l lib : add lib to the libraries searched, add multiple" << std::endl + << " for more than one library (also --lib)" << std::endl + << " -S : search standard libraries (also --stdlibs)" << std::endl + << " -C file : execute file as the target C compiler (also --cc)" << std::endl + << " -E prefix : the RTEMS tool prefix (also --exec-prefix)" << std::endl + << " -a march : machine architecture (also --march)" << std::endl + << " -c cpu : machine architecture's CPU (also --mcpu)" << std::endl; + ::exit (exit_code); +} + +static void +fatal_signal (int signum) +{ + signal (signum, SIG_DFL); + + rld::process::temporaries.clean_up (); + + /* + * Get the same signal again, this time not handled, so its normal effect + * occurs. + */ + kill (getpid (), signum); +} + +static void +setup_signals (void) +{ + if (signal (SIGINT, SIG_IGN) != SIG_IGN) + signal (SIGINT, fatal_signal); +#ifdef SIGHUP + if (signal (SIGHUP, SIG_IGN) != SIG_IGN) + signal (SIGHUP, fatal_signal); +#endif + if (signal (SIGTERM, SIG_IGN) != SIG_IGN) + signal (SIGTERM, fatal_signal); +#ifdef SIGPIPE + if (signal (SIGPIPE, SIG_IGN) != SIG_IGN) + signal (SIGPIPE, fatal_signal); +#endif +#ifdef SIGCHLD + signal (SIGCHLD, SIG_DFL); +#endif +} + +int +main (int argc, char* argv[]) +{ + int ec = 0; + + setup_signals (); + + try + { + rld::files::cache cache; + rld::files::paths libpaths; + rld::files::paths libs; + rld::files::paths objects; + rld::files::paths libraries; + rld::symbols::table symbols; + std::string base_name; + std::string cc_name; + bool standard_libs = false; + bool exec_prefix_set = false; + bool warnings = false; + + libpaths.push_back ("."); + + while (true) + { + int opt = ::getopt_long (argc, argv, "hvwVSE:L:l:a:c:C:", rld_opts, NULL); + if (opt < 0) + break; + + switch (opt) + { + case 'V': + std::cout << "rtems-syms (RTEMS Symbols) " << rld::version () + << std::endl; + ::exit (0); + break; + + case 'v': + rld::verbose_inc (); + break; + + case 'w': + warnings = true; + break; + + case 'l': + /* + * The order is important. It is the search order. + */ + libs.push_back (optarg); + break; + + case 'L': + if ((optarg[::strlen (optarg) - 1] == '/') || + (optarg[::strlen (optarg) - 1] == '\\')) + optarg[::strlen (optarg) - 1] = '\0'; + libpaths.push_back (optarg); + break; + + case 'S': + standard_libs = true; + break; + + case 'C': + if (exec_prefix_set == true) + std::cerr << "warning: exec-prefix ignored when CC provided" << std::endl; + rld::cc::cc = optarg; + break; + + case 'E': + exec_prefix_set = true; + rld::cc::exec_prefix = optarg; + break; + + case 'a': + rld::cc::march = optarg; + break; + + case 'c': + rld::cc::mcpu = optarg; + break; + + case '?': + usage (3); + break; + + case 'h': + usage (0); + break; + } + } + + argc -= optind; + argv += optind; + + std::cout << "RTEMS Symbols " << rld::version () << std::endl; + + /* + * If there are no object files there is nothing to link. + */ + if (argc == 0) + throw rld::error ("no object files", "options"); + + /* + * Load the remaining command line arguments into the cache as object + * files. + */ + while (argc--) + objects.push_back (*argv++); + + /* + * Add the object files to the cache. + */ + cache.add (objects); + + /* + * Open the cache. + */ + cache.open (); + + /* + * If the full path to CC is not provided and the exec-prefix is not set by + * the command line see if it can be detected from the object file + * types. This must be after we have added the object files because they + * are used when detecting. + */ + if (rld::cc::cc.empty () && !exec_prefix_set) + rld::cc::exec_prefix = rld::elf::machine_type (); + + /* + * Get the standard library paths + */ + rld::cc::get_standard_libpaths (libpaths); + + /* + * Get the command line libraries. + */ + rld::files::find_libraries (libraries, libpaths, libs); + + /* + * Are we to load standard libraries ? + */ + if (standard_libs) + rld::cc::get_standard_libs (libraries, libpaths); + + /* + * Load the library to the cache. + */ + cache.add_libraries (libraries); + + /* + * Load the symbol table. + */ + cache.load_symbols (symbols); + + rld::map (cache, symbols); + } + catch (rld::error re) + { + std::cerr << "error: " + << re.where << ": " << re.what + << std::endl; + ec = 10; + } + catch (std::exception e) + { + int status; + char* realname; + realname = abi::__cxa_demangle (e.what(), 0, 0, &status); + std::cerr << "error: exception: " << realname << " ["; + ::free (realname); + const std::type_info &ti = typeid (e); + realname = abi::__cxa_demangle (ti.name(), 0, 0, &status); + std::cerr << realname << "] " << e.what () << std::endl; + ::free (realname); + ec = 11; + } + catch (...) + { + /* + * Helps to know if this happens. + */ + std::cout << "error: unhandled exception" << std::endl; + ec = 12; + } + + return ec; +} @@ -60,7 +60,7 @@ def build(bld): # Build flags. # bld.warningflags = ['-Wall', '-Wextra', '-pedantic'] - bld.optflags = ['-O2'] + bld.optflags = [] #['-O2'] bld.cflags = ['-pipe', '-g'] + bld.optflags bld.cxxflags = ['-pipe', '-g'] + bld.optflags bld.linkflags = ['-g'] @@ -79,19 +79,35 @@ def build(bld): modules = ['fastlz', 'elf', 'iberty'] # + # RLD source. + # + rld_source = ['rld-elf.cpp', + 'rld-files.cpp', + 'rld-cc.cpp', + 'rld-outputter.cpp', + 'rld-process.cpp', + 'rld-resolver.cpp', + 'rld-symbols.cpp', + 'rld.cpp'] + + # # Build the linker. # bld.program(target = 'rtems-ld', - source = ['main.cpp', - 'pkgconfig.cpp', - 'rld-elf.cpp', - 'rld-files.cpp', - 'rld-cc.cpp', - 'rld-outputter.cpp', - 'rld-process.cpp', - 'rld-resolver.cpp', - 'rld-symbols.cpp', - 'rld.cpp'], + source = ['rtems-ld.cpp', + 'pkgconfig.cpp'] + rld_source, + defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], + includes = ['.'] + bld.includes, + cflags = bld.cflags + bld.warningflags, + cxxflags = bld.cxxflags + bld.warningflags, + linkflags = bld.linkflags, + use = modules) + + # + # Build the symbols. + # + bld.program(target = 'rtems-syms', + source = ['rtems-syms.cpp'] + rld_source, defines = ['HAVE_CONFIG_H=1', 'RTEMS_VERSION=' + bld.env.RTEMS_VERSION], includes = ['.'] + bld.includes, cflags = bld.cflags + bld.warningflags, |