aboutsummaryrefslogtreecommitdiffstats
path: root/src/rtld
diff options
context:
space:
mode:
Diffstat (limited to 'src/rtld')
-rw-r--r--src/rtld/COPYING339
-rw-r--r--src/rtld/COPYING.LIB502
-rw-r--r--src/rtld/ChangeLog267
-rw-r--r--src/rtld/Makefile.am32
-rw-r--r--src/rtld/README-rtld18
-rw-r--r--src/rtld/dl-hash.h77
-rw-r--r--src/rtld/dl-load.c279
-rw-r--r--src/rtld/dl-lookup.c131
-rw-r--r--src/rtld/dl-lookupX.h896
-rw-r--r--src/rtld/dl-misc.c106
-rw-r--r--src/rtld/dl-object.c57
-rw-r--r--src/rtld/dl-tls.c287
-rw-r--r--src/rtld/dl-version.c369
-rw-r--r--src/rtld/rtld.c1425
-rw-r--r--src/rtld/rtld.h338
15 files changed, 5123 insertions, 0 deletions
diff --git a/src/rtld/COPYING b/src/rtld/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/src/rtld/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 2 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/rtld/COPYING.LIB b/src/rtld/COPYING.LIB
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/src/rtld/COPYING.LIB
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/rtld/ChangeLog b/src/rtld/ChangeLog
new file mode 100644
index 0000000..ae208d7
--- /dev/null
+++ b/src/rtld/ChangeLog
@@ -0,0 +1,267 @@
+2015-10-21 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/: Resync to glibc-2.22
+ * rtld/*: Update copyright dates to match glibc-2.22
+ * rtld/rtld.c: Update the elf_machine_type class entries
+ Add support for ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA via
+ new extern_protected_data function.
+ rename reloc_typeclass to elf_machine_type_class
+ add machine_no_rela, machine_no_rel funcs
+ Update debug msg
+ Fix missing dso_list->map = NULL
+ * rtld/dl-tls.c: (rtld_determine_tlsoffsets) add NIOS2 definition
+ * rtld/dl-lookup.c: Add EXTERN_PROTECTED_DATA support
+ * rtld/dl-lookupX.h: Add EXTERN_PROTECTED_DATA support
+ update debug msgs
+ * rtld/dl-load.c: (create_map_object_from_dso_ent) Add ld.so like debug
+ When an executable sets a load address use it
+ Update the load address calculation, prevents visual overlaps
+ * rtld/dl-version.c: update debug msgs
+ * rtld/rtld.h: define _dl_debug_printf to act like ld.so debug
+ define RTLD_DEBUG_PID to set the debug prefix
+
+ * glibc changes directly affecting the implementation:
+
+ 2013-12-04 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+ Alan Modra <amodra@gmail.com>
+ * libc/sysdeps/powerpc/powerpc64/dl-machine.h
+ (elf_machine_type_class): Use SHN_UNDEF PLT handling for ELFv2 ABI.
+
+ 2015-01-18 Chung-Lin Tang <cltang@codesourcery.com>
+ Sandra Loosemore <sandra@codesourcery.com>
+ Andrew Jenner <andrew@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Nathan Sidwell <nathan@codesourcery.com>
+ * sysdeps/nios2/dl-machine.h: New file.
+
+ 2015-03-31 H.J. Lu <hongjiu.lu@intel.com>
+ * elf/dl-lookup.c (do_lookup_x): When UNDEF_MAP is NULL, which
+ indicates it is called from do_lookup_x on relocation against
+ protected data, skip the data definion in the executable from
+ copy reloc.
+ (_dl_lookup_symbol_x): Pass ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA,
+ instead of ELF_RTYPE_CLASS_PLT, to do_lookup_x for
+ EXTERN_PROTECTED_DATA relocation against STT_OBJECT symbol.
+ * sysdeps/i386/dl-machine.h (elf_machine_type_class): Set class
+ to ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA for R_386_GLOB_DAT.
+ * sysdeps/x86_64/dl-machine.h (elf_machine_type_class): Set class
+ to ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA for R_X86_64_GLOB_DAT.
+
+ 2015-07-24 Szabolcs Nagy <szabolcs.nagy@arm.com>
+ * sysdeps/aarch64/dl-machine.h (elf_machine_type_class): Handle
+ ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA.
+ * sysdeps/arm/dl-machine.h (elf_machine_type_class): Handle
+ ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA.
+
+2015-09-11 Vaneet Narang <v.narang@samsung.com>
+ * rtld/rtld.c: Add ability to specify preloaded libraries
+
+2015-09-09 Maninder Singh <maninder1.s@samsung.com>
+ Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: dso null pointer check fix
+
+2015-04-06 Mark Hatle <mark.hatle@windriver.com>
+ Maninder Singh <maninder1.s@samsung.com>
+ * rtld/dl-version.c: Add debug for mising ld-linux or libc.so
+
+2014-12-10 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: Sync aarch64 elf_machine_type_class (dl-machine.h)
+ (do_relocs): fix comparison pltrel_end >= rel_end
+ * rtld/dl-tls.c: Add basic aarch64 support
+
+2014-12-10 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/: Resync to glibc-2.20
+ Replace referenced to GLRO_dl_debug_mask to
+ GLRO(dl_debug_mask)
+
+ * rtld/rtld.h: Sync DL_DEBUG_* defines from ldsodefs.h
+ add DSO_FILENAME and RTLD_PROGNAME definitions
+ Move to __glibc_unlikely/likely instead of __builtin_expect
+ rename link_map and update unique_sym_table to match glibc
+
+ * rtld/dl-hash.h:
+ Apply glibc changes:
+ 2011-12-03 Ulrich Drepper <drepper@gmail.com>
+ Fix more warnings
+
+ 2011-12-04 Ulrich Drepper <drepper@gmail.com>
+ Fix attreibute for _dl_elf_hash
+
+ 2011-12-04 Ulrich Drepper <drepper@gmail.com>
+ Small optimization of generic ELF hash function
+
+ 2011-12-10 Ulrich Drepper <drepper@gmail.com>
+ Optimize generic ELF hash function a bit more
+
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ * rtld/dl-load.c: split (_dl_new_object) move to dl-object
+ Remove VERSYMIDX, already defined in rtld.h
+
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2012-04-04 Siddhesh Poyarekar <siddhesh@redhat.com>
+ (Updated copyright date)
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ 2014-02-10 Ond<C5><99>ej B<C3><AD>lka <neleai@seznam.cz>
+ Use glibc_likely instead __builtin_expect.
+
+ * rtld/dl-object.c:
+ Apply glibc changes:
+ 2013-11-11 Jan Kratochvil <jan.kratochvil@redhat.com>
+ [BZ #387]
+ * elf/dl-object.c (_dl_new_object): Initialize L_NAME from NEWNAME if
+ it is empty.
+
+ * rtld/dl-lookup.c, rtld/dl-lookupX.h:
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2012-04-05 David S. Miller <davem@davemloft.net>
+ * elf/dl-lookup (_dl_lookup_symbol_x): If DL_DEBUG_UNUSED, ignore
+ undefined symbol errors.
+
+ 2012-08-14 Roland McGrath <roland@hack.frob.com>
+ (Updated copyright date)
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2013-05-29 Siddhesh Poyarekar <siddhesh@redhat.com>
+ Avoid crashing in LD_DEBUG when program name is unavailable
+
+ 2013-11-13 Marcus Shawcroft <marcus.shawcroft@linaro.org>
+ Avoid passing NULL to DSO_FILENAME.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ 2014-02-10 Ond<C5><99>ej B<C3><AD>lka <neleai@seznam.cz>
+ Use glibc_likely instead __builtin_expect.
+
+ 2014-02-11 Joseph Myers <joseph@codesourcery.com>
+ Merge MIPS dl-lookup.c into generic file.
+ * elf/dl-lookup.c (ELF_MACHINE_SYM_NO_MATCH): Define if not
+ already defined.
+ (do_lookup_x): Use ELF_MACHINE_SYM_NO_MATCH.
+ * sysdeps/mips/dl-lookup.c: Remove.
+ * sysdeps/mips/dl-machine.h (ELF_MACHINE_SYM_NO_MATCH): New macro.
+
+ 2014-02-28 Carlos O'Donell <carlos@redhat.com>
+ Promote do_lookup_x:check_match to a full function.
+
+ 2014-04-02 Will Newton <will.newton@linaro.org>
+ elf/dl-lookup.c: Remove obsolete comment about nested function
+ * elf/dl-lookup.c (do_lookup_x): Remove comment
+ referring to nested function and move variable
+ declarations down to before first use.
+
+ 2014-04-04 Will Newton <will.newton@linaro.org>
+ elf/dl-lookup.c: Remove unnecessary static variable
+ * elf/dl-lookup.c (undefined_msg): Remove variable.
+ (_dl_lookup_symbol_x): Replace undefined_msg with string
+ literal.
+
+ 2014-04-11 Will Newton <will.newton@linaro.org>
+ elf/dl-lookup.c: Use __glibc_likely and __glibc_unlikely
+
+ * rtld/dl-misc.c:
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ * rtld/dl-tls.c:
+ Sync spacing with glibc for easier diffs (content remained the same)
+
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ * rtld/dl-version:
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2013-05-29 Siddhesh Poyarekar <siddhesh@redhat.com>
+ Avoid crashing in LD_DEBUG when program name is unavailable
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ 2014-02-10 Ond<C5><99>ej B<C3><AD>lka <neleai@seznam.cz>
+ Use glibc_likely instead __builtin_expect.
+
+2014-12-10 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/COPYING, rtld/COPYING.LIB,
+ rtld/ChangeLog, rtld/README-rtld: Add local history
+ information to setup for a resync to glibc-2.20
+
+2012-09-12 Joseph Myers <joseph@codesourcery.com>
+ * rtld/dl-lookup.c: Fix variable copy reloc when host/target
+ byte size is different
+
+2012-04-10 Maxim Kuvyrkov <maxim@codesourcery.com>
+ * rtld/rtld.c (find_lib_by_soname): Follow ld.so's behavior of
+ pulling its name from PT_INTERP.
+
+2012-01-26 Mark Hatle <mark.hatle@windriver.com>
+ * elf.h, rtld/dl-lookupX.h, rtld/rtld.c: Sync to eglibc 2.15
+
+2011-12-08 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: Add support for $ORIGIN, $PLATFORM and $LIB.
+ Note: $PLATFORM = ""
+
+2011-12-08 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: Fix an issue where missing objects would trigger
+ an assert in dl-version.c
+ * rtld/rtld.h: Add _dl_new_object prototype
+
+2011-09-13 Mark Hatle <mark.hatle@windriver.com>
+ * Fix printf problem causing prelink-rtld issues on x86 (32-bit)
+ and arm
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Add a special check for invalid GNU_HASH entries
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Sync to eglibc 2.13 ld.so code
+ * sync elf_machine_type_class macros for supports archs
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Sync to eglibc 2.13 ld.so code
+ * mips specific items from ports
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Rename ld-libs.c to rtld.c
+ * Sync to eglibc 2.13 ld.so code
+
+2011-08-18 Mark Hatle <mark.hatle@windriver.com>
+ * Move prelink-rtld specific components to rtld
+
diff --git a/src/rtld/Makefile.am b/src/rtld/Makefile.am
new file mode 100644
index 0000000..b02c745
--- /dev/null
+++ b/src/rtld/Makefile.am
@@ -0,0 +1,32 @@
+## Process this file with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = 1.4 gnu
+
+PKGVERSION = "\"@PKGVERSION@\""
+REPORT_BUGS_TO = "\"@REPORT_BUGS_TO@\""
+
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall -Wno-pointer-sign
+AM_CFLAGS = -Wall -Wno-pointer-sign
+AM_CPPFLAGS = -DSBINDIR='"@sbindir@"' -DBINDIR='"@bindir@"' \
+ -DEXECSTACK_PROG="\"`echo execstack | sed '$(transform)'`\"" \
+ -DPRELINK_PROG="\"`echo prelink | sed '$(transform)'`\"" \
+ -DPRELINK_RTLD_PROG="\"`echo prelink-rtld | \
+ sed '$(transform)'`\"" \
+ -DEXEEXT='"$(EXEEXT)"' \
+ -DPKGVERSION=$(PKGVERSION) \
+ -DREPORT_BUGS_TO=$(REPORT_BUGS_TO)
+INCLUDES = -I$(top_srcdir)/src @GELFINCLUDE@
+
+sbin_PROGRAMS = prelink-rtld
+
+prelink_rtld_SOURCES = $(top_srcdir)/src/data.c $(top_srcdir)/src/dso.c \
+ $(top_srcdir)/src/canonicalize.c $(top_srcdir)/src/wrap-file.c \
+ $(top_srcdir)/src/reloc-info.c $(top_srcdir)/src/reloc-info.h \
+ rtld.c ld-libs.h \
+ dl-hash.h dl-object.c dl-load.c \
+ dl-tls.c dl-version.c dl-misc.c \
+ dl-lookup.c dl-lookupX.h
+
+prelink_rtld_LDADD = @LIBGELF@ -liberty
+prelink_rtld_CFLAGS = -DDSO_READONLY
+prelink_rtld_LDFLAGS =
diff --git a/src/rtld/README-rtld b/src/rtld/README-rtld
new file mode 100644
index 0000000..fa737dc
--- /dev/null
+++ b/src/rtld/README-rtld
@@ -0,0 +1,18 @@
+The rtld emulation is based on the system libc ld.so code.
+
+The original version of this code was written by Daniel Jacobowitz in
+2003. It needed little modification/updating until recently (2011) when
+new constructs, such as STB_GNU_UNIQUE, were introduced into the dynamic
+linking.
+
+The 2011 work was done by Mark Hatle and based on eglibc-2.13. I
+attempted to document all of the code that had origins in eglibc and where
+the code originated from.
+
+As eglibc continues to advance, similar resyncs will be needed over time.
+Hopefully not such a dramatic resync will be required in the future.
+
+Mark Hatle <mark.hatle@windriver.com>,
+August 2011
+
+See the ChangeLog for additional changes.
diff --git a/src/rtld/dl-hash.h b/src/rtld/dl-hash.h
new file mode 100644
index 0000000..2b1f0b7
--- /dev/null
+++ b/src/rtld/dl-hash.h
@@ -0,0 +1,77 @@
+/* glibc-2.22: sysdeps/generic/dl-hash.h */
+
+/* Compute hash value for given string according to ELF standard.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_HASH_H
+#define _DL_HASH_H 1
+
+#define _dl_elf_hash rtld_elf_hash
+
+/* This is the hashing function specified by the ELF ABI. In the
+ first five operations no overflow is possible so we optimized it a
+ bit. */
+static unsigned int
+_dl_elf_hash (const char *name_arg)
+{
+ const unsigned char *name = (const unsigned char *) name_arg;
+ unsigned long int hash = *name;
+ if (hash != 0 && name[1] != '\0')
+ {
+ hash = (hash << 4) + name[1];
+ if (name[2] != '\0')
+ {
+ hash = (hash << 4) + name[2];
+ if (name[3] != '\0')
+ {
+ hash = (hash << 4) + name[3];
+ if (name[4] != '\0')
+ {
+ hash = (hash << 4) + name[4];
+ name += 5;
+ while (*name != '\0')
+ {
+ unsigned long int hi;
+ hash = (hash << 4) + *name++;
+ hi = hash & 0xf0000000;
+
+ /* The algorithm specified in the ELF ABI is as
+ follows:
+
+ if (hi != 0)
+ hash ^= hi >> 24;
+
+ hash &= ~hi;
+
+ But the following is equivalent and a lot
+ faster, especially on modern processors. */
+
+ hash ^= hi >> 24;
+ }
+
+ /* Second part of the modified formula. This
+ operation can be lifted outside the loop. */
+ hash &= 0x0fffffff;
+ }
+ }
+ }
+ }
+ return hash;
+}
+
+#endif /* dl-hash.h */
diff --git a/src/rtld/dl-load.c b/src/rtld/dl-load.c
new file mode 100644
index 0000000..5dc913e
--- /dev/null
+++ b/src/rtld/dl-load.c
@@ -0,0 +1,279 @@
+/* Restructure code containing the original statement:
+ Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Restructed and synced to latest eglibc 2.13 by
+ Mark Hatle <mark.hatle@windriver.com>, 2011
+
+ 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* glibc-2.20: elf/dl-load.c */
+
+/* Map in a shared object's segments from the file.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+/* Add `name' to the list of names for a particular shared object.
+ `name' is expected to have been allocated with malloc and will
+ be freed if the shared object already has this name.
+ Returns false if the object already had this name. */
+static void
+add_name_to_object (struct link_map *l, const char *name)
+{
+ struct libname_list *lnp, *lastp;
+ struct libname_list *newname;
+ size_t name_len;
+
+ lastp = NULL;
+ for (lnp = l->l_libname; lnp != NULL; lastp = lnp, lnp = lnp->next)
+ if (strcmp (name, lnp->name) == 0)
+ return;
+
+ name_len = strlen (name) + 1;
+ newname = (struct libname_list *) malloc (sizeof *newname + name_len);
+ if (newname == NULL)
+ {
+ /* No more memory. */
+ _dl_signal_error (ENOMEM, name, NULL, ("cannot allocate name record"));
+ return;
+ }
+ /* The object should have a libname set from _dl_new_object. */
+ assert (lastp != NULL);
+
+ newname->name = memcpy (newname + 1, name, name_len);
+ newname->next = NULL;
+ lastp->next = newname;
+}
+
+const char *rtld_progname;
+
+static Elf64_Addr load_addr = 0xdead0000;
+static Elf64_Addr dynamic_addr = 0xfeed0000;
+
+/* mimic behavior of _dl_map_object_from_fd(...)
+ Note: this is not a copy of the function! */
+void
+create_map_object_from_dso_ent (struct dso_list *cur_dso_ent)
+{
+ struct link_map *l = NULL;
+ DSO *dso = cur_dso_ent->dso;
+
+ int i;
+ Elf_Data *data;
+
+
+ const char * realname, * name, *soname;
+ int l_type;
+
+ soname = dso->soname;
+ realname = dso->filename;
+ name = dso->filename;
+
+ l_type = (dso->ehdr.e_type == ET_EXEC ? lt_executable : lt_library);
+
+
+ /* Print debug message. */
+ if ((l_type == lt_library && !is_ldso_soname(soname)) &&
+ __glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf("file=%s [0]; generating link map\n", soname);
+
+
+ l = _dl_new_object (realname, name, l_type);
+ if (l == NULL)
+ {
+ _dl_signal_error(errno, name, NULL, "cannot create shared object descriptor");
+ }
+
+ if (soname)
+ add_name_to_object(l, soname);
+
+ if (name)
+ add_name_to_object(l, name);
+
+ l->filename = dso->filename;
+
+ /* Set the elfclass */
+ l->elfclass = gelf_getclass (dso->elf);
+
+ /*** Setup the l_info as if this had been loaded into memory ***/
+
+ /* FIXME: gelfify, endianness issues */
+ /* and leaks? */
+ i = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[DT_SYMTAB] = data->d_buf;
+ }
+
+ i = addr_to_sec (dso, dso->info[DT_STRTAB]);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[DT_STRTAB] = data->d_buf;
+ }
+
+ if (dynamic_info_is_set (dso, DT_GNU_HASH_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_GNU_HASH);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+
+#if 0
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ printf("l_info DT_GNU_HASH: offset %d -- addr %p (0x%lx) - type %d\n",
+ (DT_ADDRTAGIDX(DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM),
+ data->d_buf, (unsigned long) data->d_size);
+#endif
+
+ l->l_info[DT_ADDRTAGIDX(DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM] = data->d_buf;
+
+ /* PPC64 workaround */
+ l->l_buckets_start = data->d_buf;
+ l->l_buckets_end = (char *)data->d_buf + data->d_size;
+ /* end workaround */
+ }
+ }
+
+ i = addr_to_sec (dso, dso->info[DT_HASH]);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[DT_HASH] = data->d_buf;
+ }
+
+ if (dynamic_info_is_set (dso, DT_VERNEED_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_VERNEED);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[VERSYMIDX (DT_VERNEED)] = data->d_buf;
+ }
+ }
+
+ if (dynamic_info_is_set (dso, DT_VERDEF_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_VERDEF);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[VERSYMIDX (DT_VERDEF)] = data->d_buf;
+ }
+ }
+
+ if (dynamic_info_is_set (dso, DT_VERSYM_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_VERSYM);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[VERSYMIDX (DT_VERSYM)] = data->d_buf;
+ }
+ }
+
+ if (dso->base) {
+ l->l_map_start = dso->base;
+
+ /* We need to ensure that we don't have two DSOs loading at the same place! */
+ struct dso_list * dso_list_ptr;
+ for (dso_list_ptr = cur_dso_ent->prev; dso_list_ptr; dso_list_ptr = dso_list_ptr->prev)
+ {
+ /* This looks for fairly obvious overlaps... */
+ if ((dso_list_ptr->dso->base <= dso->base && dso->base <= dso_list_ptr->dso->end) || \
+ (dso->base <= dso_list_ptr->dso->base && dso_list_ptr->dso->base <= dso->end))
+ {
+ l->l_map_start = (Elf64_Addr)NULL;
+ break;
+ }
+ }
+ }
+
+ if (l->l_map_start == (Elf64_Addr)NULL)
+ {
+ l->l_map_start = load_addr;
+ load_addr += ( ((dso->end - dso->base) + (0x1000 - 1)) & (~(0x1000-1)) );
+ }
+
+ l->sym_base = dso->info[DT_SYMTAB] - dso->base;
+
+ if ((l_type == lt_library && !is_ldso_soname(soname))
+ && (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))) {
+ _dl_debug_printf ("\
+ dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n",
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) dynamic_addr,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) l->l_map_start,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (dso->end - dso->base));
+ _dl_debug_printf ("\
+ entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n",
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) l->l_map_start + dso->ehdr.e_entry,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) l->l_map_start + dso->ehdr.e_ehsize,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ dso->ehdr.e_phnum);
+ _dl_debug_printf ("\n");
+
+ /* Only used for debugging output */
+ dynamic_addr += ( ((dso->end - dso->base) + (0x1000 - 1)) & (~(0x1000-1)) );
+ }
+
+ /* Set up the symbol hash table. */
+ _dl_setup_hash (l);
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_TLS)
+ {
+ l->l_tls_blocksize = dso->phdr[i].p_memsz;
+ l->l_tls_align = dso->phdr[i].p_align;
+ if (l->l_tls_align == 0)
+ l->l_tls_firstbyte_offset = 0;
+ else
+ l->l_tls_firstbyte_offset = dso->phdr[i].p_vaddr & (l->l_tls_align - 1);
+ break;
+ }
+
+ l->machine = dso->ehdr.e_machine;
+
+ cur_dso_ent->map = l;
+}
diff --git a/src/rtld/dl-lookup.c b/src/rtld/dl-lookup.c
new file mode 100644
index 0000000..6688966
--- /dev/null
+++ b/src/rtld/dl-lookup.c
@@ -0,0 +1,131 @@
+/* glibc-2.22: elf/dl-lookup.c */
+
+/* Look up a symbol in the loaded objects.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is based on the original eglibc-2.13 libc/elf/dl-lookup.c
+ code.
+
+ It has been split into two pieces dl-lookup.c and dl-lookupX.c,
+ the purpose of the split is to enable both 32-bit and 64-bit ELF
+ processing in the same application. This file contains the ELF
+ size neutral routines.
+ */
+
+#include <config.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dl-hash.h>
+
+#include <assert.h>
+
+#include <errno.h>
+
+#include <elf.h>
+
+#include <inttypes.h>
+
+#include "prelinktab.h"
+#include "reloc.h"
+
+#include "rtld.h"
+
+/* Return nonzero if check_match should consider SYM to fail to match a
+ symbol reference for some machine-specific reason. */
+#ifndef ELF_MACHINE_SYM_NO_MATCH
+/* glibc-2.20: sysdeps/mips/dl-machine.h */
+/* The semantics of zero/non-zero values of undefined symbols differs
+ depending on whether the non-PIC ABI is in use. Under the non-PIC
+ ABI, a non-zero value indicates that there is an address reference
+ to the symbol and thus it must always be resolved (except when
+ resolving a jump slot relocation) to the PLT entry whose address is
+ provided as the symbol's value; a zero value indicates that this
+ canonical-address behaviour is not required. Yet under the classic
+ MIPS psABI, a zero value indicates that there is an address
+ reference to the function and the dynamic linker must resolve the
+ symbol immediately upon loading. To avoid conflict, symbols for
+ which the dynamic linker must assume the non-PIC ABI semantics are
+ marked with the STO_MIPS_PLT flag. */
+#define ELF_MACHINE_SYM_NO_MATCH(sym) \
+ (map->machine == EM_MIPS && \
+ ((sym)->st_shndx == SHN_UNDEF && !((sym)->st_other & STO_MIPS_PLT)) \
+ )
+#endif
+
+struct unique_sym_table * _ns_unique_sym_table = NULL;
+
+/* This file is from eglibc 2.13, libc/elf/dl-lookup.c
+ It has been split into two pieces dl-lookup.c and dl-lookupX.c,
+ the purpose of the split is to enable both 32-bit and 64-bit ELF
+ processing in the same application. This file contains the common
+ routines ... and is the entry to the overall set of files.
+ */
+
+#define make_string(string, rest...) \
+ ({ \
+ const char *all[] = { string, ## rest }; \
+ size_t len, cnt; \
+ char *result, *cp; \
+ \
+ len = 1; \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ len += strlen (all[cnt]); \
+ \
+ cp = result = alloca (len); \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ cp = __stpcpy (cp, all[cnt]); \
+ \
+ result; \
+ })
+
+static uint_fast32_t
+dl_new_hash (const char *s)
+{
+ uint_fast32_t h = 5381;
+ unsigned char c = *s;
+ for (c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
+
+#undef RTLD_ELF_SIZE
+#define RTLD_ELF_SIZE 32
+#include "dl-lookupX.h"
+
+#undef RTLD_ELF_SIZE
+#define RTLD_ELF_SIZE 64
+#include "dl-lookupX.h"
+
+#undef RTLD_ELF_SIZE
+
+void
+_dl_setup_hash (struct link_map *map)
+{
+ if (map)
+ {
+ if (map->elfclass == ELFCLASS32)
+ rtld_setup_hash32(map);
+ else if (map->elfclass == ELFCLASS64)
+ rtld_setup_hash64(map);
+ else
+ _dl_signal_error(EINVAL, map->l_name, NULL, "elfclass is not defined 32-bit or 64-bit!");
+ }
+}
diff --git a/src/rtld/dl-lookupX.h b/src/rtld/dl-lookupX.h
new file mode 100644
index 0000000..dc6d4bf
--- /dev/null
+++ b/src/rtld/dl-lookupX.h
@@ -0,0 +1,896 @@
+/* glibc-2.22: elf/dl-lookup.c */
+
+/* Look up a symbol in the loaded objects.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is from eglibc 2.15, libc/elf/dl-lookup.c
+ It has been split into two pieces dl-lookup.c and dl-lookupX.c,
+ the purpose of the split is to enable both 32-bit and 64-bit ELF
+ processing in the same application. This file contains the ELF
+ size specific routines. It must be included from dl-lookup.c and
+ not used directly!
+ */
+
+#if RTLD_ELF_SIZE == 32
+ #define enter_unique_sym enter_unique_sym_val32
+ #define sym_val sym_val32
+ #define check_match check_match32
+ #define do_lookup_unique do_lookup_unique32
+ #define do_lookup_x do_lookup_x32
+ #undef _dl_setup_hash
+ #define _dl_setup_hash rtld_setup_hash32
+ #define _dl_debug_bindings rtld_debug_bindings32
+ #define _dl_lookup_symbol_x rtld_lookup_symbol_x32
+ #define rtld_size_t uint32_t
+ #define rtld_size_fmtx PRIx32
+
+#elif RTLD_ELF_SIZE == 64
+ #define enter_unique_sym enter_unique_sym_val64
+ #define sym_val sym_val64
+ #define check_match check_match64
+ #define do_lookup_unique do_lookup_unique64
+ #define do_lookup_x do_lookup_x64
+ #undef _dl_setup_hash
+ #define _dl_setup_hash rtld_setup_hash64
+ #define _dl_debug_bindings rtld_debug_bindings64
+ #define _dl_lookup_symbol_x rtld_lookup_symbol_x64
+ #define rtld_size_t uint64_t
+ #define rtld_size_fmtx PRIx64
+
+#else
+ #error "You must declare RTLD_ELF_SIZE to be either 32 or 64"
+#endif
+
+#define __ELF_NATIVE_CLASS RTLD_ELF_SIZE
+
+/* From eglibc 2.15 - elf/link.h */
+
+/* We use this macro to refer to ELF types independent of the native wordsize.
+ `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
+#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type)
+#define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type)
+#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
+#define _ElfW_1(e,w,t) e##w##t
+
+struct sym_val
+ {
+ const ElfW(Sym) *s;
+ struct link_map *m;
+ };
+
+/* Utility function for do_lookup_x. The caller is called with undef_name,
+ ref, version, flags and type_class, and those are passed as the first
+ five arguments. The caller then computes sym, symidx, strtab, and map
+ and passes them as the next four arguments. Lastly the caller passes in
+ versioned_sym and num_versions which are modified by check_match during
+ the checking process. */
+static const ElfW(Sym) *
+check_match (const char *const undef_name,
+ const ElfW(Sym) *const ref,
+ const struct r_found_version *const version,
+ const int flags,
+ const int type_class,
+ const ElfW(Sym) *const sym,
+ const Elf_Symndx symidx,
+ const char *const strtab,
+ const struct link_map *const map,
+ const ElfW(Sym) **const versioned_sym,
+ int *const num_versions)
+{
+ unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
+ assert (ELF_RTYPE_CLASS_PLT == 1);
+ if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
+ && stt != STT_TLS)
+ || ELF_MACHINE_SYM_NO_MATCH (sym)
+ || (type_class & (sym->st_shndx == SHN_UNDEF))))
+ return NULL;
+
+ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
+ STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
+ code/data definitions. */
+#define ALLOWED_STT \
+ ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
+ | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
+ if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
+ return NULL;
+
+ if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+ /* Not the symbol we are looking for. */
+ return NULL;
+
+ const ElfW(Half) *verstab = map->l_versyms;
+ if (version != NULL)
+ {
+ if (__glibc_unlikely (verstab == NULL))
+ {
+ /* We need a versioned symbol but haven't found any. If
+ this is the object which is referenced in the verneed
+ entry it is a bug in the library since a symbol must
+ not simply disappear.
+
+ It would also be a bug in the object since it means that
+ the list of required versions is incomplete and so the
+ tests in dl-version.c haven't found a problem.*/
+ assert (version->filename == NULL
+ || ! _dl_name_match_p (version->filename, map));
+
+ /* Otherwise we accept the symbol. */
+ }
+ else
+ {
+ /* We can match the version information or use the
+ default one if it is not hidden. */
+ ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+ if ((map->l_versions[ndx].hash != version->hash
+ || strcmp (map->l_versions[ndx].name, version->name))
+ && (version->hidden || map->l_versions[ndx].hash
+ || (verstab[symidx] & 0x8000)))
+ /* It's not the version we want. */
+ return NULL;
+ }
+ }
+ else
+ {
+ /* No specific version is selected. There are two ways we
+ can got here:
+
+ - a binary which does not include versioning information
+ is loaded
+
+ - dlsym() instead of dlvsym() is used to get a symbol which
+ might exist in more than one form
+
+ If the library does not provide symbol version information
+ there is no problem at all: we simply use the symbol if it
+ is defined.
+
+ These two lookups need to be handled differently if the
+ library defines versions. In the case of the old
+ unversioned application the oldest (default) version
+ should be used. In case of a dlsym() call the latest and
+ public interface should be returned. */
+ if (verstab != NULL)
+ {
+ if ((verstab[symidx] & 0x7fff)
+ >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
+ {
+ /* Don't accept hidden symbols. */
+ if ((verstab[symidx] & 0x8000) == 0
+ && (*num_versions)++ == 0)
+ /* No version so far. */
+ *versioned_sym = sym;
+
+ return NULL;
+ }
+ }
+ }
+
+ /* There cannot be another entry for this symbol so stop here. */
+ return sym;
+}
+
+/* Utility function for do_lookup_unique. Add a symbol to TABLE. */
+static void
+enter_unique_sym (struct unique_sym *table, size_t size,
+ unsigned int hash, const char *name,
+ const ElfW(Sym) *sym, const struct link_map *map)
+{
+ size_t idx = hash % size;
+ size_t hash2 = 1 + hash % (size - 2);
+ while (table[idx].name != NULL)
+ {
+ idx += hash2;
+ if (idx >= size)
+ idx -= size;
+ }
+
+ table[idx].hashval = hash;
+ table[idx].name = name;
+ table[idx].sym = sym;
+ table[idx].map = map;
+}
+
+/* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
+ in the unique symbol table, creating a new entry if necessary.
+ Return the matching symbol in RESULT. */
+static void
+do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+ const struct link_map *map, struct sym_val *result,
+ int type_class, const ElfW(Sym) *sym, const char *strtab,
+ const ElfW(Sym) *ref, const struct link_map *undef_map)
+{
+ /* We have to determine whether we already found a symbol with this
+ name before. If not then we have to add it to the search table.
+ If we already found a definition we have to use it. */
+
+ struct unique_sym_table *tab
+ = _ns_unique_sym_table;
+
+ __rtld_lock_lock_recursive (tab->lock);
+
+ struct unique_sym *entries = tab->entries;
+ size_t size = tab->size;
+ if (entries != NULL)
+ {
+ size_t idx = new_hash % size;
+ size_t hash2 = 1 + new_hash % (size - 2);
+ while (1)
+ {
+ if (entries[idx].hashval == new_hash
+ && strcmp (entries[idx].name, undef_name) == 0)
+ {
+ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+ {
+ /* We possibly have to initialize the central
+ copy from the copy addressed through the
+ relocation. */
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ }
+ else
+ {
+ result->s = entries[idx].sym;
+ result->m = (struct link_map *) entries[idx].map;
+ }
+ __rtld_lock_unlock_recursive (tab->lock);
+ return;
+ }
+
+ if (entries[idx].name == NULL)
+ break;
+
+ idx += hash2;
+ if (idx >= size)
+ idx -= size;
+ }
+
+ if (size * 3 <= tab->n_elements * 4)
+ {
+ /* Expand the table. */
+#ifdef RTLD_CHECK_FOREIGN_CALL
+ /* This must not happen during runtime relocations. */
+ assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+ size_t newsize = _dl_higher_prime_number (size + 1);
+ struct unique_sym *newentries
+ = calloc (sizeof (struct unique_sym), newsize);
+ if (newentries == NULL)
+ {
+ nomem:
+ __rtld_lock_unlock_recursive (tab->lock);
+ _dl_fatal_printf ("out of memory\n");
+ }
+
+ for (idx = 0; idx < size; ++idx)
+ if (entries[idx].name != NULL)
+ enter_unique_sym (newentries, newsize, entries[idx].hashval,
+ entries[idx].name, entries[idx].sym,
+ entries[idx].map);
+
+ tab->free (entries);
+ tab->size = newsize;
+ size = newsize;
+ entries = tab->entries = newentries;
+ tab->free = free;
+ }
+ }
+ else
+ {
+#ifdef RTLD_CHECK_FOREIGN_CALL
+ /* This must not happen during runtime relocations. */
+ assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+
+#if 1
+ /* If tab->entries is NULL, but tab->size is not, it means
+ this is the second, conflict finding, lookup for
+ LD_TRACE_PRELINKING in _dl_debug_bindings. Don't
+ allocate anything and don't enter anything into the
+ hash table. */
+ if (__glibc_unlikely (tab->size))
+ {
+ assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
+ goto success;
+ }
+#endif
+
+#define INITIAL_NUNIQUE_SYM_TABLE 31
+ size = INITIAL_NUNIQUE_SYM_TABLE;
+ entries = calloc (sizeof (struct unique_sym), size);
+ if (entries == NULL)
+ goto nomem;
+
+ tab->entries = entries;
+ tab->size = size;
+ tab->free = free;
+ }
+
+ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+ enter_unique_sym (entries, size, new_hash, strtab + sym->st_name, ref,
+ undef_map);
+ else
+ {
+ enter_unique_sym (entries, size,
+ new_hash, strtab + sym->st_name, sym, map);
+
+#if 0
+ if (map->l_type == lt_loaded)
+ /* Make sure we don't unload this object by
+ setting the appropriate flag. */
+ ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
+#endif
+ }
+ ++tab->n_elements;
+
+#if 1
+ success:
+#endif
+
+ result->s = sym;
+ result->m = (struct link_map *) map;
+}
+
+/* Inner part of the lookup functions. We return a value > 0 if we
+ found the symbol, the value 0 if nothing is found and < 0 if
+ something bad happened. */
+static int
+do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ unsigned long int *old_hash, const ElfW(Sym) *ref,
+ struct sym_val *result, struct r_scope_elem *scope, size_t i,
+ const struct r_found_version *const version, int flags,
+ struct link_map *skip, int type_class, struct link_map *undef_map)
+{
+ size_t n = scope->r_nlist;
+ /* Make sure we read the value before proceeding. Otherwise we
+ might use r_list pointing to the initial scope and r_nlist being
+ the value after a resize. That is the only path in dl-open.c not
+ protected by GSCOPE. A read barrier here might be to expensive. */
+ __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
+ struct link_map **list = scope->r_list;
+
+ do
+ {
+ const struct link_map *map = list[i];
+
+ /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
+ if (map == skip)
+ continue;
+
+ /* Don't search the executable when resolving a copy reloc. */
+ if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
+ continue;
+
+ /* Print some debugging info if wanted. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
+ _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
+ undef_name, DSO_FILENAME (map->l_name),
+ 0UL);
+
+ /* If the hash table is empty there is nothing to do here. */
+ if (map->l_nbuckets == 0)
+ continue;
+
+ Elf_Symndx symidx;
+ int num_versions = 0;
+ const ElfW(Sym) *versioned_sym = NULL;
+
+ /* The tables for this map. */
+ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ const ElfW(Sym) *sym;
+ const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
+ if (__glibc_likely (bitmask != NULL))
+ {
+ ElfW(Addr) bitmask_word
+ = bitmask[(new_hash / __ELF_NATIVE_CLASS)
+ & map->l_gnu_bitmask_idxbits];
+
+ unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
+ unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
+ & (__ELF_NATIVE_CLASS - 1));
+
+ if (__glibc_unlikely ((bitmask_word >> hashbit1)
+ & (bitmask_word >> hashbit2) & 1))
+ {
+ Elf32_Word bucket = map->l_gnu_buckets[new_hash
+ % map->l_nbuckets];
+
+/* PPC64 workaround */
+ /* There is a bad hash entry and it's pointing beyond
+ the end of the bucket list. */
+ assert ((void *)&map->l_gnu_chain_zero[bucket] < map->l_buckets_end);
+/* END PPC64 workaround */
+ if (bucket != 0)
+ {
+ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
+
+ do
+ if (((*hasharr ^ new_hash) >> 1) == 0)
+ {
+ symidx = hasharr - map->l_gnu_chain_zero;
+ sym = check_match (undef_name, ref, version, flags,
+ type_class, &symtab[symidx], symidx,
+ strtab, map, &versioned_sym,
+ &num_versions);
+ if (sym != NULL)
+ goto found_it;
+ }
+ while ((*hasharr++ & 1u) == 0);
+ }
+ }
+ /* No symbol found. */
+ symidx = SHN_UNDEF;
+ }
+ else
+ {
+ if (*old_hash == 0xffffffff)
+ *old_hash = _dl_elf_hash (undef_name);
+
+ /* Use the old SysV-style hash table. Search the appropriate
+ hash bucket in this object's symbol table for a definition
+ for the same symbol name. */
+ for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ sym = check_match (undef_name, ref, version, flags,
+ type_class, &symtab[symidx], symidx,
+ strtab, map, &versioned_sym,
+ &num_versions);
+ if (sym != NULL)
+ goto found_it;
+ }
+ }
+
+ /* If we have seen exactly one versioned symbol while we are
+ looking for an unversioned symbol and the version is not the
+ default version we still accept this symbol since there are
+ no possible ambiguities. */
+ sym = num_versions == 1 ? versioned_sym : NULL;
+
+ if (sym != NULL)
+ {
+ found_it:
+ /* When UNDEF_MAP is NULL, which indicates we are called from
+ do_lookup_x on relocation against protected data, we skip
+ the data definion in the executable from copy reloc. */
+ if (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(map->machine)
+ && undef_map == NULL
+ && map->l_type == lt_executable
+ && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(map->machine))
+ {
+ const ElfW(Sym) *s;
+ unsigned int i;
+
+if (!ELF_MACHINE_NO_RELA(map->machine)) { /* #if ! ELF_MACHINE_NO_RELA */
+ if (map->l_info[DT_RELA] != NULL
+ && map->l_info[DT_RELASZ] != NULL
+ && ((ElfW(Dyn) *)(map->l_info[DT_RELASZ]))->d_un.d_val != 0)
+ {
+ const ElfW(Rela) *rela
+ = (const ElfW(Rela) *) D_PTR (map, l_info[DT_RELA]);
+ unsigned int rela_count
+ = ((ElfW(Dyn) *)(map->l_info[DT_RELASZ]))->d_un.d_val / sizeof (*rela);
+
+ for (i = 0; i < rela_count; i++, rela++)
+ if (elf_machine_type_class (ELFW(R_TYPE) (rela->r_info), map->machine)
+ == ELF_RTYPE_CLASS_COPY)
+ {
+ s = &symtab[ELFW(R_SYM) (rela->r_info)];
+ if (!strcmp (strtab + s->st_name, undef_name))
+ goto skip;
+ }
+ }
+} /* #endif */
+if (!ELF_MACHINE_NO_REL(map->machine)) { /* #if ! ELF_MACHINE_NO_REL */
+ if (map->l_info[DT_REL] != NULL
+ && map->l_info[DT_RELSZ] != NULL
+ && ((ElfW(Dyn) *)(map->l_info[DT_RELSZ]))->d_un.d_val != 0)
+ {
+ const ElfW(Rel) *rel
+ = (const ElfW(Rel) *) D_PTR (map, l_info[DT_REL]);
+ unsigned int rel_count
+ = ((ElfW(Dyn) *)(map->l_info[DT_RELSZ]))->d_un.d_val / sizeof (*rel);
+
+ for (i = 0; i < rel_count; i++, rel++)
+ if (elf_machine_type_class (ELFW(R_TYPE) (rel->r_info), map->machine)
+ == ELF_RTYPE_CLASS_COPY)
+ {
+ s = &symtab[ELFW(R_SYM) (rel->r_info)];
+ if (!strcmp (strtab + s->st_name, undef_name))
+ goto skip;
+ }
+ }
+} /* #endif */
+ }
+
+ switch (ELFW(ST_BIND) (sym->st_info))
+ {
+ case STB_WEAK:
+ /* Weak definition. Use this value if we don't find another. */
+ if (__glibc_unlikely (GLRO(dl_dynamic_weak)))
+ {
+ if (! result->s)
+ {
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ case STB_GLOBAL:
+ /* Global definition. Just what we need. */
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ return 1;
+
+ case STB_GNU_UNIQUE:;
+ do_lookup_unique (undef_name, new_hash, map, result, type_class,
+ sym, strtab, ref, undef_map);
+ return 1;
+
+ default:
+ /* Local symbols are ignored. */
+ break;
+ }
+ }
+
+skip:
+ /* If this current map is the one mentioned in the verneed entry
+ and we have not found a weak entry, it is a bug. */
+ if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
+ && __glibc_unlikely (_dl_name_match_p (version->filename, map)))
+ return -1;
+ }
+ while (++i < n);
+
+ /* We have not found anything until now. */
+ return 0;
+}
+
+
+static void
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref, struct sym_val *value,
+ const struct r_found_version *version, int type_class,
+ int protected);
+
+
+/* Search loaded objects' symbol tables for a definition of the symbol
+ UNDEF_NAME, perhaps with a requested version for the symbol.
+
+ We must never have calls to the audit functions inside this function
+ or in any function which gets called. If this would happen the audit
+ code might create a thread which can throw off all the scope locking. */
+lookup_t
+_dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags, struct link_map *skip_map)
+{
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
+ struct sym_val current_value = { NULL, NULL };
+ struct r_scope_elem **scope = symbol_scope;
+
+ /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
+ is allowed if we look up a versioned symbol. */
+ assert (version == NULL
+ || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
+ == 0);
+
+ size_t i = 0;
+ if (__glibc_unlikely (skip_map != NULL))
+ /* Search the relevant loaded objects for a definition. */
+ while ((*scope)->r_list[i] != skip_map)
+ ++i;
+
+ /* Search the relevant loaded objects for a definition. */
+ size_t start; /* requires C99 to put it into the loop */
+ for (start = i; *scope != NULL; start = 0, ++scope)
+ {
+ int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &current_value, *scope, start, version, flags,
+ skip_map, type_class, undef_map);
+ if (res > 0)
+ break;
+
+ if (__glibc_unlikely (res < 0) && skip_map == NULL)
+ {
+ /* Oh, oh. The file named in the relocation entry does not
+ contain the needed symbol. This code is never reached
+ for unversioned lookups. */
+ assert (version != NULL);
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+
+ /* XXX We cannot translate the message. */
+ _dl_signal_cerror (0, DSO_FILENAME (reference_name),
+ "relocation error",
+ make_string ("symbol ", undef_name, ", version ",
+ version->name,
+ " not defined in file ",
+ version->filename,
+ " with link time reference",
+ res == -2
+ ? " (no version symbols)" : ""));
+ *ref = NULL;
+ return 0;
+ }
+ }
+
+ if (__glibc_unlikely (current_value.s == NULL))
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && skip_map == NULL
+ && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+ const char *versionstr = version ? ", version " : "";
+ const char *versionname = (version && version->name
+ ? version->name : "");
+
+ /* XXX We cannot translate the message. */
+ _dl_signal_cerror (0, DSO_FILENAME (reference_name),
+ ("symbol lookup error"),
+ make_string ("undefined symbol: ", undef_name,
+ versionstr, versionname));
+ }
+ *ref = NULL;
+ return 0;
+ }
+
+ int protected = (*ref
+ && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
+ if (__glibc_unlikely (protected != 0))
+ {
+ /* It is very tricky. We need to figure out what value to
+ return for the protected symbol. */
+ if (type_class == ELF_RTYPE_CLASS_PLT)
+ {
+ if (current_value.s != NULL && current_value.m != undef_map)
+ {
+ current_value.s = *ref;
+ current_value.m = undef_map;
+ }
+ }
+ else
+ {
+ struct sym_val protected_value = { NULL, NULL };
+
+ for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
+ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &protected_value, *scope, i, version, flags,
+ skip_map,
+ (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(skip_map->machine)
+ && ELFW(ST_TYPE) ((*ref)->st_info) == STT_OBJECT
+ && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(skip_map->machine))
+ ? ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(skip_map->machine)
+ : ELF_RTYPE_CLASS_PLT, NULL) != 0)
+ break;
+
+ if (protected_value.s != NULL && protected_value.m != undef_map)
+ {
+ current_value.s = *ref;
+ current_value.m = undef_map;
+ }
+ }
+ }
+
+#if 0
+ /* We have to check whether this would bind UNDEF_MAP to an object
+ in the global scope which was dynamically loaded. In this case
+ we have to prevent the latter from being unloaded unless the
+ UNDEF_MAP object is also unloaded. */
+ if (__glibc_unlikely (current_value.m->l_type == lt_loaded)
+ /* Don't do this for explicit lookups as opposed to implicit
+ runtime lookups. */
+ && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
+ /* Add UNDEF_MAP to the dependencies. */
+ && add_dependency (undef_map, current_value.m, flags) < 0)
+ /* Something went wrong. Perhaps the object we tried to reference
+ was just removed. Try finding another definition. */
+ return _dl_lookup_symbol_x (undef_name, undef_map, ref,
+ symbol_scope,
+ version, type_class, flags, skip_map);
+#endif
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask)
+ & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK)))
+ _dl_debug_bindings (undef_name, undef_map, ref,
+ &current_value, version, type_class, protected);
+
+ *ref = current_value.s;
+ return LOOKUP_VALUE (current_value.m);
+}
+
+
+/* Cache the location of MAP's hash table. */
+
+void
+_dl_setup_hash (struct link_map *map)
+{
+ Elf_Symndx *hash;
+
+ if (__glibc_likely (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM] != NULL))
+ {
+ Elf32_Word *hash32
+ = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM]);
+ map->l_nbuckets = *hash32++;
+ Elf32_Word symbias = *hash32++;
+ Elf32_Word bitmask_nwords = *hash32++;
+ /* Must be a power of two. */
+ assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
+ map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
+ map->l_gnu_shift = *hash32++;
+
+ map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
+ hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
+
+ map->l_gnu_buckets = hash32;
+ hash32 += map->l_nbuckets;
+ map->l_gnu_chain_zero = hash32 - symbias;
+ return;
+ }
+
+ if (!map->l_info[DT_HASH])
+ return;
+ hash = (void *) D_PTR (map, l_info[DT_HASH]);
+
+ map->l_nbuckets = *hash++;
+ /* Skip nchain. */
+ hash++;
+ map->l_buckets = hash;
+ hash += map->l_nbuckets;
+ map->l_chain = hash;
+}
+
+
+static void
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref, struct sym_val *value,
+ const struct r_found_version *version, int type_class,
+ int protected)
+{
+ const char *reference_name = undef_map->l_name;
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
+ {
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+ DSO_FILENAME (reference_name),
+ 0UL,
+ DSO_FILENAME (value->m->l_name),
+ 0UL,
+ protected ? "protected" : "normal", undef_name);
+ if (version)
+ printf (" [%s]\n", version->name);
+ else
+ printf ("\n");
+ }
+#if 1
+ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+ int conflict = 0;
+ struct sym_val val = { NULL, NULL };
+
+ /* We need to always process these or we can miss conflict symbols when
+ RTLD_TRACE_PRELINKING=<library> */
+ if (1)
+ {
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
+ struct unique_sym *saved_entries
+ = _ns_unique_sym_table->entries;
+
+ _ns_unique_sym_table->entries = NULL;
+ do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
+ undef_map->l_local_scope[0], 0, version, 0, NULL,
+ type_class, undef_map);
+ if (val.s != value->s || val.m != value->m)
+ conflict = 1;
+ else if (1
+ && val.s
+ && __glibc_unlikely (ELFW(ST_BIND) (val.s->st_info)
+ == STB_GNU_UNIQUE))
+ {
+ /* If it is STB_GNU_UNIQUE and undef_map's l_local_scope
+ contains any DT_SYMBOLIC libraries, unfortunately there
+ can be conflicts even if the above is equal. As symbol
+ resolution goes from the last library to the first and
+ if a STB_GNU_UNIQUE symbol is found in some late DT_SYMBOLIC
+ library, it would be the one that is looked up. */
+ struct sym_val val2 = { NULL, NULL };
+ size_t n;
+ struct r_scope_elem *scope = undef_map->l_local_scope[0];
+
+ for (n = 0; n < scope->r_nlist; n++)
+ if (scope->r_list[n] == val.m)
+ break;
+
+ for (n++; n < scope->r_nlist; n++)
+ if (scope->r_list[n]->l_info[DT_SYMBOLIC] != NULL
+ && do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &val2,
+ scope,
+ 0, version, 0, NULL, type_class,
+ undef_map) > 0)
+ {
+ conflict = 1;
+ val = val2;
+ break;
+ }
+ }
+ _ns_unique_sym_table->entries = saved_entries;
+ }
+
+ if (value->s)
+ {
+ if (__glibc_unlikely (ELFW(ST_TYPE) (value->s->st_info)
+ == STT_TLS))
+ type_class = 4;
+ else if (__glibc_unlikely (ELFW(ST_TYPE) (value->s->st_info)
+ == STT_GNU_IFUNC))
+ type_class |= 8;
+ }
+
+ if (conflict
+ || GLRO(dl_trace_prelink_map) == undef_map
+ || GLRO(dl_trace_prelink_map) == NULL
+ || type_class >= 4)
+ {
+ printf ("%s 0x%0*"rtld_size_fmtx" 0x%0*"rtld_size_fmtx" -> 0x%0*"rtld_size_fmtx" 0x%0*"rtld_size_fmtx" ",
+ conflict ? "conflict" : "lookup",
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) undef_map->l_map_start,
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (((char *)*ref) - ((char *)undef_map->l_info[DT_SYMTAB]) + (char *)undef_map->sym_base),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (value->s ? value->m->l_map_start : 0),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (value->s ? value->s->st_value : 0));
+
+ if (conflict)
+ printf ("x 0x%0*"rtld_size_fmtx" 0x%0*"rtld_size_fmtx" ",
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (val.s ? val.m->l_map_start : 0),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (val.s ? val.s->st_value : 0));
+
+ printf ("/%x %s\n", type_class, undef_name);
+ }
+ }
+#endif
+}
+
+#undef enter_unique_sym
+#undef sym_val
+#undef check_match
+#undef do_lookup_unique
+#undef do_lookup_x
+#undef _dl_setup_hash
+#define _dl_setup_hash rtld_setup_hash
+#undef _dl_debug_bindings
+#undef _dl_lookup_symbol_x
+#undef rtld_size_t
+#undef rtld_size_fmtx
diff --git a/src/rtld/dl-misc.c b/src/rtld/dl-misc.c
new file mode 100644
index 0000000..c70956d
--- /dev/null
+++ b/src/rtld/dl-misc.c
@@ -0,0 +1,106 @@
+/* glibc 2.22, elf/dl-misc.c */
+
+/* Miscellaneous support functions for dynamic linker
+ Copyright (C) 1997-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+/* Test whether given NAME matches any of the names of the given object. */
+int
+_dl_name_match_p (const char *name, const struct link_map *map)
+{
+ if (strcmp (name, map->l_name) == 0)
+ return 1;
+
+ struct libname_list *runp = map->l_libname;
+
+ while (runp != NULL)
+ if (strcmp (name, runp->name) == 0)
+ return 1;
+ else
+ runp = runp->next;
+
+ return 0;
+}
+
+unsigned long int
+_dl_higher_prime_number (unsigned long int n)
+{
+ /* These are primes that are near, but slightly smaller than, a
+ power of two. */
+ static const uint32_t primes[] = {
+ UINT32_C (7),
+ UINT32_C (13),
+ UINT32_C (31),
+ UINT32_C (61),
+ UINT32_C (127),
+ UINT32_C (251),
+ UINT32_C (509),
+ UINT32_C (1021),
+ UINT32_C (2039),
+ UINT32_C (4093),
+ UINT32_C (8191),
+ UINT32_C (16381),
+ UINT32_C (32749),
+ UINT32_C (65521),
+ UINT32_C (131071),
+ UINT32_C (262139),
+ UINT32_C (524287),
+ UINT32_C (1048573),
+ UINT32_C (2097143),
+ UINT32_C (4194301),
+ UINT32_C (8388593),
+ UINT32_C (16777213),
+ UINT32_C (33554393),
+ UINT32_C (67108859),
+ UINT32_C (134217689),
+ UINT32_C (268435399),
+ UINT32_C (536870909),
+ UINT32_C (1073741789),
+ UINT32_C (2147483647),
+ /* 4294967291L */
+ UINT32_C (2147483647) + UINT32_C (2147483644)
+ };
+
+ const uint32_t *low = &primes[0];
+ const uint32_t *high = &primes[sizeof (primes) / sizeof (primes[0])];
+
+ while (low != high)
+ {
+ const uint32_t *mid = low + (high - low) / 2;
+ if (n > *mid)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+#if 0
+ /* If we've run out of primes, abort. */
+ if (n > *low)
+ {
+ fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+ abort ();
+ }
+#endif
+
+ return *low;
+}
diff --git a/src/rtld/dl-object.c b/src/rtld/dl-object.c
new file mode 100644
index 0000000..19f0265
--- /dev/null
+++ b/src/rtld/dl-object.c
@@ -0,0 +1,57 @@
+/* glibc-2.22: elf/dl-object.c */
+
+/* Storage management for the chain of loaded shared objects.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+/* Allocate a `struct link_map' for a new object being loaded,
+ and enter it into the _dl_loaded list. */
+struct link_map *
+_dl_new_object (const char *realname, const char *libname, int type)
+{
+ size_t libname_len = strlen (libname) + 1;
+ struct link_map *new;
+ struct libname_list *newname;
+
+ new = (struct link_map *) calloc (sizeof (*new) +
+ + sizeof (*newname) + libname_len, 1);
+
+ if (new == NULL)
+ return NULL;
+
+ new->l_libname = newname
+ = (struct libname_list *) ((char *) (new + 1));
+ newname->name = (char *) memcpy (newname + 1, libname, libname_len);
+ /* newname->next = NULL; We use calloc therefore not necessary. */
+
+ /* When we create the executable link map, or a VDSO link map, we start
+ with "" for the l_name. In these cases "" points to ld.so rodata
+ and won't get dumped during core file generation. Therefore to assist
+ gdb and to create more self-contained core files we adjust l_name to
+ point at the newly allocated copy (which will get dumped) instead of
+ the ld.so rodata copy. */
+ new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;
+ new->l_type = type;
+
+ return new;
+}
diff --git a/src/rtld/dl-tls.c b/src/rtld/dl-tls.c
new file mode 100644
index 0000000..8b972ff
--- /dev/null
+++ b/src/rtld/dl-tls.c
@@ -0,0 +1,287 @@
+/* Copyright (C) 2011 Wind River Systems, Inc.
+
+ Code reorganized from original code bearing the following copyright:
+ Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Code updated by Mark Hatle <mark.hatle@windriver.com>, 2011
+ to sync to eglibc 2.13 tls behavior...
+
+ 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* glibc 2.22: elf/dl-tls.c */
+
+/* Thread-local storage handling in the ELF dynamic linker. Generic version.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "rtld.h"
+
+/* Assign TLS offsets for every loaded library. This code is taken
+ almost directly from glibc! */
+
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+
+/* The following function needs to mimic the _dl_determine_tlsoffset in eglibc */
+void
+rtld_determine_tlsoffsets (int e_machine, struct r_scope_elem *search_list)
+{
+ uint64_t modid = 1;
+
+ uint64_t i;
+
+ /* skip max_align */
+ uint64_t freetop = 0;
+ uint64_t freebottom = 0;
+
+ /* This comes from each architecture's ABI. If TLS_TCB_AT_TP, then
+ set offset to -1; if TLS_DTV_AT_TP, then set offset to
+ TLS_TCB_SIZE. */
+
+ int tls_tcb_at_tp = 0;
+ int tls_dtv_at_tp = 0;
+ uint64_t tls_tcb_size;
+
+ switch (e_machine)
+ {
+ case EM_X86_64:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_386:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_SH:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 8;
+ break;
+
+ case EM_PPC:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ case EM_PPC64:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ case EM_ARM:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 8;
+ break;
+
+ case EM_AARCH64:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 16;
+ break;
+
+ case EM_MIPS:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_SPARCV9:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_ALTERA_NIOS2:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ default:
+ /* Hope there's no TLS! */
+ for (i = 0; i < search_list->r_nlist; i++)
+ {
+ struct link_map *map = search_list->r_list[i];
+
+ if (map->l_tls_blocksize > 0)
+ _dl_signal_error(0, map->l_name, NULL, "cannot handle TLS data");
+ }
+
+ return;
+ }
+
+ /* eglibc 2.20: elf/dl-tls.c: _dl_determine_tlsoffset (void) */
+ /* Determining the offset of the various parts of the static TLS
+ block has several dependencies. In addition we have to work
+ around bugs in some toolchains.
+
+ Each TLS block from the objects available at link time has a size
+ and an alignment requirement. The GNU ld computes the alignment
+ requirements for the data at the positions *in the file*, though.
+ I.e, it is not simply possible to allocate a block with the size
+ of the TLS program header entry. The data is layed out assuming
+ that the first byte of the TLS block fulfills
+
+ p_vaddr mod p_align == &TLS_BLOCK mod p_align
+
+ This means we have to add artificial padding at the beginning of
+ the TLS block. These bytes are never used for the TLS data in
+ this module but the first byte allocated must be aligned
+ according to mod p_align == 0 so that the first byte of the TLS
+ block is aligned according to p_vaddr mod p_align. This is ugly
+ and the linker can help by computing the offsets in the TLS block
+ assuming the first byte of the TLS block is aligned according to
+ p_align.
+
+ The extra space which might be allocated before the first byte of
+ the TLS block need not go unused. The code below tries to use
+ that memory for the next TLS block. This can work if the total
+ memory requirement for the next TLS block is smaller than the
+ gap. */
+
+ /* Loop over the loaded DSOs. We use the symbol search order; this
+ should be the same as glibc's ordering, which traverses l_next.
+ It's somewhat important that we use both the same ordering to
+ assign module IDs and the same algorithm to assign offsets,
+ because the prelinker will resolve all relocations using these
+ offsets... and then glibc will recalculate them. Future dynamic
+ relocations in any loaded modules will use glibc's values. Also
+ if we take too much space here, glibc won't allocate enough
+ static TLS area to hold it. */
+
+/* #if TLS_TCB_AT_TP */ if (tls_tcb_at_tp == 1) {
+ /* We simply start with zero. */
+ uint64_t offset = 0;
+
+ for (i = 0; i < search_list->r_nlist; i++)
+ {
+ struct link_map *map = search_list->r_list[i];
+
+ uint64_t firstbyte = (-map->l_tls_firstbyte_offset
+ & (map->l_tls_align - 1));
+ uint64_t off;
+
+ /* elf/rtld.c would have caused us to skip this block.. so emulate this */
+ if (map->l_tls_blocksize == 0)
+ continue;
+
+ /* allocate_tls_init would nomrally Increment the module id */
+ map->l_tls_modid = modid++;
+
+ if (freebottom - freetop >= map->l_tls_blocksize)
+ {
+ off = roundup (freetop + map->l_tls_blocksize
+ - firstbyte, map->l_tls_align)
+ + firstbyte;
+ if (off <= freebottom)
+ {
+ freetop = off;
+
+ /* XXX For some architectures we perhaps should store the
+ negative offset. */
+ map->l_tls_offset = off;
+ continue;
+ }
+ }
+
+ off = roundup (offset + map->l_tls_blocksize - firstbyte,
+ map->l_tls_align) + firstbyte;
+ if (off > offset + map->l_tls_blocksize
+ + (freebottom - freetop))
+ {
+ freetop = offset;
+ freebottom = off - map->l_tls_blocksize;
+ }
+ offset = off;
+
+ /* XXX For some architectures we perhaps should store the
+ negative offset. */
+ map->l_tls_offset = off;
+ }
+/* #elif TLS_DTV_AT_TP */ } else if (tls_dtv_at_tp == 1) {
+ /* The TLS blocks start right after the TCB. */
+ uint64_t offset = tls_tcb_size;
+
+ for (i = 0; i < search_list->r_nlist; i++)
+ {
+ struct link_map *map = search_list->r_list[i];
+
+ uint64_t firstbyte = (-map->l_tls_firstbyte_offset
+ & (map->l_tls_align - 1));
+ uint64_t off;
+
+ /* elf/rtld.c would have caused us to skip this block.. so emulate this */
+ if (map->l_tls_blocksize == 0)
+ continue;
+
+ /* allocate_tls_init would nomrally Increment the module id */
+ map->l_tls_modid = modid++;
+
+ if (map->l_tls_blocksize <= freetop - freebottom)
+ {
+ off = roundup (freebottom, map->l_tls_align);
+ if (off - freebottom < firstbyte)
+ off += map->l_tls_align;
+ if (off + map->l_tls_blocksize - firstbyte <= freetop)
+ {
+ map->l_tls_offset = off - firstbyte;
+ freebottom = (off + map->l_tls_blocksize
+ - firstbyte);
+ continue;
+ }
+ }
+
+ off = roundup (offset, map->l_tls_align);
+ if (off - offset < firstbyte)
+ off += map->l_tls_align;
+
+ map->l_tls_offset = off - firstbyte;
+ if (off - firstbyte - offset > freetop - freebottom)
+ {
+ freebottom = offset;
+ freetop = off - firstbyte;
+ }
+
+ offset = off + map->l_tls_blocksize - firstbyte;
+ }
+/* #else */ } else {
+ /* Should never happen... */
+ _dl_signal_error(0, NULL, NULL, "Neither TLS_TCB_AT_TP nor TLS_DTV_AT_TP is defined for this architecture");
+/* #endif */ }
+}
diff --git a/src/rtld/dl-version.c b/src/rtld/dl-version.c
new file mode 100644
index 0000000..042a70f
--- /dev/null
+++ b/src/rtld/dl-version.c
@@ -0,0 +1,369 @@
+/* Based on code originally in eglibc 2.13, libc/elf/dl-version.c */
+
+/* Handle symbol and library versioning.
+ Copyright (C) 1997-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+#define make_string(string, rest...) \
+ ({ \
+ const char *all[] = { string, ## rest }; \
+ size_t len, cnt; \
+ char *result, *cp; \
+ \
+ len = 1; \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ len += strlen (all[cnt]); \
+ \
+ cp = result = alloca (len); \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ cp = __stpcpy (cp, all[cnt]); \
+ \
+ result; \
+ })
+
+
+static inline struct link_map *
+find_needed (const char *name, struct link_map *map)
+{
+ struct link_map *tmap = map;
+ unsigned int n = 0;
+
+ for (n = 0; n < map->l_local_scope[0]->r_nlist; n++)
+ {
+ tmap = map->l_local_scope[0]->r_list[n];
+ if (_dl_name_match_p (name, tmap))
+ return tmap;
+ }
+
+ if (_dl_name_match_p (name, map))
+ return map;
+
+ /* Should never happen. */
+ return NULL;
+}
+
+
+static int
+match_symbol (const char *name, Elf64_Word hash, const char *string,
+ struct link_map *map, int verbose, int weak)
+{
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ Elf64_Verdef *def;
+ /* Initialize to make the compiler happy. */
+ const char *errstring = NULL;
+ int result = 0;
+
+ /* Display information about what we are doing while debugging. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
+ _dl_debug_printf ("\
+checking for version `%s' in file %s [0] required by file %s [0]\n",
+ string, DSO_FILENAME (map->l_name),
+ name);
+
+ if (__glibc_unlikely (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL))
+ {
+ /* The file has no symbol versioning. I.e., the dependent
+ object was linked against another version of this file. We
+ only print a message if verbose output is requested. */
+ if (verbose)
+ {
+ /* XXX We cannot translate the messages. */
+ errstring = make_string ("\
+no version information available (required by ", name, ")");
+ goto call_cerror;
+ }
+ return 0;
+ }
+
+ def = (Elf64_Verdef *) ((char *) map->l_info[VERSYMIDX (DT_VERDEF)]);
+ while (1)
+ {
+ /* Currently the version number of the definition entry is 1.
+ Make sure all we see is this version. */
+ if (__builtin_expect (def->vd_version, 1) != 1)
+ {
+ char buf[20];
+ buf[sizeof (buf) - 1] = '\0';
+ /* XXX We cannot translate the message. */
+ /* _itoa (def->vd_version,
+ &buf[sizeof (buf) - 1], 10, 0), */
+ errstring = make_string ("unsupported version ",
+ " of Verdef record");
+ result = 1;
+ goto call_cerror;
+ }
+
+ /* Compare the hash values. */
+ if (hash == def->vd_hash)
+ {
+ Elf64_Verdaux *aux = (Elf64_Verdaux *) ((char *) def + def->vd_aux);
+
+ /* To be safe, compare the string as well. */
+ if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
+ == 0)
+ /* Bingo! */
+ return 0;
+ }
+
+ /* If no more definitions we failed to find what we want. */
+ if (def->vd_next == 0)
+ break;
+
+ /* Next definition. */
+ def = (Elf64_Verdef *) ((char *) def + def->vd_next);
+ }
+
+ /* Symbol not found. If it was a weak reference it is not fatal. */
+ if (__glibc_likely (weak))
+ {
+ if (verbose)
+ {
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("weak version `", string,
+ "' not found (required by ", name, ")");
+ goto call_cerror;
+ }
+ return 0;
+ }
+
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("version `", string, "' not found (required by ",
+ name, ")");
+ result = 1;
+ call_cerror:
+ _dl_signal_cerror (0, DSO_FILENAME (map->l_name),
+ ("version lookup error"), errstring);
+ return result;
+}
+
+
+int
+_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
+{
+ int result = 0;
+ const char *strtab;
+ /* Pointer to section with needed versions. */
+ Elf64_Verneed *dyn;
+ /* This file may require special versions from its dependencies. */
+ Elf64_Verneed *ent;
+ /* Pointer to dynamic section with definitions. */
+ Elf64_Verdef *def;
+ /* We need to find out which is the highest version index used
+ in a dependecy. */
+ unsigned int ndx_high = 0;
+ /* Initialize to make the compiler happy. */
+ const char *errstring = NULL;
+ int errval = 0;
+
+ /* If we don't have a string table, we must be ok. */
+ if (map->l_info[DT_STRTAB] == NULL)
+ return 0;
+ strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
+ def = map->l_info[VERSYMIDX (DT_VERDEF)];
+ ent = (Elf64_Verneed *) (dyn);
+
+ if (dyn != NULL)
+ {
+
+ /* Currently the version number of the needed entry is 1.
+ Make sure all we see is this version. */
+ if (__builtin_expect (ent->vn_version, 1) != 1)
+ {
+ char buf[20];
+ buf[sizeof (buf) - 1] = '\0';
+ /* XXX We cannot translate the message. */
+ /* _itoa (def->vn_version,
+ &buf[sizeof (buf) - 1], 10, 0), */
+ errstring = make_string ("unsupported version ",
+ " of Verneed record\n");
+ call_error:
+ _dl_signal_error (errval, DSO_FILENAME (map->l_name),
+ NULL, errstring);
+ }
+
+ while (1)
+ {
+ Elf64_Vernaux *aux;
+ struct link_map *needed = find_needed (strtab + ent->vn_file, map);
+
+ /* If NEEDED is NULL this means a dependency was not found
+ and no stub entry was created. This should never happen. */
+ if (needed == NULL)
+ {
+ _dl_signal_error (errval, NULL, NULL, strtab + ent->vn_file);
+ printf("error while loading shared libraries: %s", strtab + ent->vn_file);
+ exit (1);
+ }
+ assert (needed != NULL);
+
+ /* Make sure this is no stub we created because of a missing
+ dependency. */
+ if (__builtin_expect (! trace_mode, 1))
+ {
+ /* NEEDED is the map for the file we need. Now look for the
+ dependency symbols. */
+ aux = (Elf64_Vernaux *) ((char *) ent + ent->vn_aux);
+ while (1)
+ {
+ /* Match the symbol. */
+ result |= match_symbol (DSO_FILENAME (map->l_name),
+ aux->vna_hash,
+ strtab + aux->vna_name,
+ needed, verbose,
+ aux->vna_flags & VER_FLG_WEAK);
+
+ /* Compare the version index. */
+ if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
+ ndx_high = aux->vna_other & 0x7fff;
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Next symbol. */
+ aux = (Elf64_Vernaux *) ((char *) aux + aux->vna_next);
+ }
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Next dependency. */
+ ent = (Elf64_Verneed *) ((char *) ent + ent->vn_next);
+ }
+ }
+
+ /* We also must store the names of the defined versions. Determine
+ the maximum index here as well.
+
+ XXX We could avoid the loop by just taking the number of definitions
+ as an upper bound of new indeces. */
+ if (def != NULL)
+ {
+ Elf64_Verdef *ent;
+ ent = (Elf64_Verdef *) (def);
+ while (1)
+ {
+ if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
+ ndx_high = ent->vd_ndx & 0x7fff;
+
+ if (ent->vd_next == 0)
+ /* No more definitions. */
+ break;
+
+ ent = (Elf64_Verdef *) ((char *) ent + ent->vd_next);
+ }
+ }
+
+ if (ndx_high > 0)
+ {
+ /* Now we are ready to build the array with the version names
+ which can be indexed by the version index in the VERSYM
+ section. */
+ map->l_versions = (struct r_found_version *)
+ calloc (ndx_high + 1, sizeof (*map->l_versions));
+ if (__glibc_unlikely (map->l_versions == NULL))
+ {
+ errstring = ("cannot allocate version reference table");
+ errval = ENOMEM;
+ goto call_error;
+ }
+
+ /* Store the number of available symbols. */
+ map->l_nversions = ndx_high + 1;
+
+ /* Compute the pointer to the version symbols. */
+ map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+
+ if (dyn != NULL)
+ {
+ Elf64_Verneed *ent;
+ ent = (Elf64_Verneed *) (dyn);
+ while (1)
+ {
+ Elf64_Vernaux *aux;
+ aux = (Elf64_Vernaux *) ((char *) ent + ent->vn_aux);
+ while (1)
+ {
+ Elf64_Half ndx = aux->vna_other & 0x7fff;
+ /* In trace mode, dependencies may be missing. */
+ if (__glibc_likely (ndx < map->l_nversions))
+ {
+ map->l_versions[ndx].hash = aux->vna_hash;
+ map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
+ map->l_versions[ndx].name = &strtab[aux->vna_name];
+ map->l_versions[ndx].filename = &strtab[ent->vn_file];
+ }
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Advance to next symbol. */
+ aux = (Elf64_Vernaux *) ((char *) aux + aux->vna_next);
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Advance to next dependency. */
+ ent = (Elf64_Verneed *) ((char *) ent + ent->vn_next);
+ }
+ }
+
+ /* And insert the defined versions. */
+ if (def != NULL)
+ {
+ Elf64_Verdef *ent;
+ ent = (Elf64_Verdef *) (def);
+ while (1)
+ {
+ Elf64_Verdaux *aux;
+ aux = (Elf64_Verdaux *) ((char *) ent + ent->vd_aux);
+
+ if ((ent->vd_flags & VER_FLG_BASE) == 0)
+ {
+ /* The name of the base version should not be
+ available for matching a versioned symbol. */
+ Elf64_Half ndx = ent->vd_ndx & 0x7fff;
+ map->l_versions[ndx].hash = ent->vd_hash;
+ map->l_versions[ndx].name = &strtab[aux->vda_name];
+ map->l_versions[ndx].filename = NULL;
+ }
+
+ if (ent->vd_next == 0)
+ /* No more definitions. */
+ break;
+
+ ent = (Elf64_Verdef *) ((char *) ent + ent->vd_next);
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/src/rtld/rtld.c b/src/rtld/rtld.c
new file mode 100644
index 0000000..82ba4b2
--- /dev/null
+++ b/src/rtld/rtld.c
@@ -0,0 +1,1425 @@
+/* Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Copyright (C) 2011 Wind River Systems, Inc.
+ Significantly updated by Mark Hatle <mark.hatle@windriver.com>, 2011
+
+ 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 2, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <ctype.h>
+#include <error.h>
+#include <errno.h>
+#include <argp.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <inttypes.h>
+
+#include "prelinktab.h"
+#include "reloc.h"
+#include "reloc-info.h"
+
+#include "rtld.h"
+
+unsigned int static_binary = 0;
+
+unsigned int _dl_debug_mask = 0;
+
+/* LD_DYNAMIC_WEAK option. Default is off, changing to 1
+ is equivalent to setting LD_DYNAMIC_WEAK. */
+unsigned int _dl_dynamic_weak = 0;
+#define MAX_PRELOADED_LIBS 20
+
+struct search_path
+{
+ int maxlen, count, allocated;
+ char **dirs;
+};
+
+struct search_path ld_dirs, ld_library_search_path;
+int host_paths;
+
+char * dst_ORIGIN;
+char * dst_PLATFORM = ""; /* undefined */
+char * dst_LIB = "lib";
+char * ld_preload = NULL;
+
+
+void string_to_path (struct search_path *path, const char *string);
+
+const char *argp_program_version = PRELINK_RTLD_PROG PKGVERSION " 1.0";
+
+const char *argp_program_bug_address = REPORT_BUGS_TO;
+
+static char argp_doc[] = PRELINK_RTLD_PROG " -- program to simulate the runtime linker";
+
+#define OPT_SYSROOT 0x8c
+#define OPT_LIBRARY_PATH 0x8e
+#define OPT_TARGET_PATHS 0x8f
+#define OPT_LD_PRELOAD 0x90
+
+static struct argp_option options[] = {
+ {"library-path", OPT_LIBRARY_PATH, "LIBRARY_PATH", 0, "Set library search path to LIBRARY_PATH" },
+ {"root", OPT_SYSROOT, "ROOT_PATH", 0, "Prefix all paths with ROOT_PATH" },
+ {"target-paths", OPT_TARGET_PATHS, 0, 0, "Specified paths are based on ROOT_PATH" },
+ {"ld-preload", OPT_LD_PRELOAD, "PATHLIST", 0, "List of LD_PRELOAD libraries"},
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case OPT_SYSROOT:
+ sysroot = arg;
+ break;
+ case OPT_LIBRARY_PATH:
+ string_to_path(&ld_library_search_path, arg);
+ break;
+ case OPT_TARGET_PATHS:
+ host_paths = 0;
+ break;
+ case OPT_LD_PRELOAD:
+ ld_preload = arg;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* This function returns the same constants expected by glibc's
+ symbol lookup routines. This is slightly different from the
+ equivalent routines in prelink. It should return PLT for any
+ relocation where an undefined symbol in the application should
+ be ignored: typically, this means any jump slot or TLS relocations,
+ but not copy relocations. Don't return the prelinker's
+ RTYPE_CLASS_TLS. */
+
+/* The following needs to be kept in sync with the
+ sysdeps/.../dl-machine.h: elf_machine_type_class macro */
+
+/* From glibc-2.22: sysdeps/i386/dl-machine.h */
+# define i386_elf_machine_type_class(type) \
+ ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \
+ || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \
+ || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_386_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_386)))
+
+/* From glibc-2.22: sysdeps/x86_64/dl-machine.h */
+# define x86_64_elf_machine_type_class(type) \
+ ((((type) == R_X86_64_JUMP_SLOT \
+ || (type) == R_X86_64_DTPMOD64 \
+ || (type) == R_X86_64_DTPOFF64 \
+ || (type) == R_X86_64_TPOFF64 \
+ || (type) == R_X86_64_TLSDESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_X86_64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_X86_64)))
+
+/* From glibc-2.22: ports/sysdeps/arm/dl-machine.h */
+# define arm_elf_machine_type_class(type) \
+ ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \
+ || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32 \
+ || (type) == R_ARM_TLS_DESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_ARM)))
+
+/* From glibc-2.22: ports/sysdeps/aarch64/dl-machine.h */
+# define aarch64_elf_machine_type_class(type) \
+ ((((type) == R_AARCH64_JUMP_SLOT || \
+ (type) == R_AARCH64_TLS_DTPMOD || \
+ (type) == R_AARCH64_TLS_DTPREL || \
+ (type) == R_AARCH64_TLS_TPREL || \
+ (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_AARCH64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_AARCH64)))
+
+/* From glibc-2.22: sysdeps/sh/dl-machine.h */
+# define sh_elf_machine_type_class(type) \
+ ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32 \
+ || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/powerpc/powerpc32/dl-machine.h */
+#define powerpc32_elf_machine_type_class(type) \
+ ((((type) == R_PPC_JMP_SLOT \
+ || (type) == R_PPC_REL24 \
+ || ((type) >= R_PPC_DTPMOD32 /* contiguous TLS */ \
+ && (type) <= R_PPC_DTPREL32) \
+ || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/powerpc/powerpc64/dl-machine.h */
+/* we only support ELFv2 at this point */
+#define IS_PPC64_TLS_RELOC(R) \
+ (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \
+ || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
+
+#define powerpc64_elf_machine_type_class(type) \
+ ((((type) == R_PPC64_JMP_SLOT \
+ || (type) == R_PPC64_ADDR24 \
+ || IS_PPC64_TLS_RELOC (type)) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/mips/dl-machine.h */
+#define ELF_MACHINE_JMP_SLOT R_MIPS_JUMP_SLOT
+#define mips_elf_machine_type_class(type) \
+ ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/sparc/sparc32/dl-machine.h */
+#define sparc_elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT \
+ || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/sparc/sparc64/dl-machine.h */
+# define sparc64_elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT \
+ || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/nios2/dl-machine.h */
+# define nios2_elf_machine_type_class(type) \
+ ((((type) == R_NIOS2_JUMP_SLOT \
+ || (type) == R_NIOS2_TLS_DTPMOD \
+ || (type) == R_NIOS2_TLS_DTPREL \
+ || (type) == R_NIOS2_TLS_TPREL) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_NIOS2_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_NIOS2_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_ALTERA_NIOS2)))
+
+int
+elf_machine_type_class (int type, int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ return i386_elf_machine_type_class(type);
+ case EM_X86_64:
+ return x86_64_elf_machine_type_class(type);
+ case EM_ARM:
+ return arm_elf_machine_type_class(type);
+ case EM_AARCH64:
+ return aarch64_elf_machine_type_class(type);
+ case EM_SH:
+ return sh_elf_machine_type_class(type);
+ case EM_PPC:
+ return powerpc32_elf_machine_type_class(type);
+ case EM_PPC64:
+ return powerpc64_elf_machine_type_class(type);
+ case EM_MIPS:
+ return mips_elf_machine_type_class(type);
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ return sparc_elf_machine_type_class(type);
+ case EM_SPARCV9:
+ return sparc64_elf_machine_type_class(type);
+ case EM_ALTERA_NIOS2:
+ return nios2_elf_machine_type_class(type);
+
+ default:
+ printf ("Unknown architecture!\n");
+ exit (1);
+ return 0;
+ }
+}
+
+int
+extern_protected_data(int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_X86_64:
+ case EM_ARM:
+ case EM_AARCH64:
+ case EM_ALTERA_NIOS2:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+int
+machine_no_rela (int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_X86_64:
+ case EM_ARM:
+ case EM_AARCH64:
+ case EM_SH:
+ case EM_PPC:
+ case EM_PPC64:
+ case EM_MIPS:
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_ALTERA_NIOS2:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+machine_no_rel (int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_MIPS:
+ case EM_ARM:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+is_ldso_soname (const char *soname)
+{
+ if ( ! strcmp (soname, "ld-linux.so.2")
+ || ! strcmp (soname, "ld-linux.so.3")
+ || ! strcmp (soname, "ld.so.1")
+ || ! strcmp (soname, "ld-linux-ia64.so.2")
+ || ! strcmp (soname, "ld-linux-x86-64.so.2")
+ || ! strcmp (soname, "ld64.so.2")
+ || ! strcmp (soname, "ld-linux-armhf.so.3")
+ || ! strcmp (soname, "ld-linux-aarch64.so.1")
+ || ! strcmp (soname, "ld-linux-aarch64_be.so.1")
+ || ! strcmp (soname, "ld-linux-nios2.so.1")
+ )
+ return 1;
+ return 0;
+}
+
+static int dso_open_error = 0;
+
+static void
+free_needed (struct needed_list *p)
+{
+ struct needed_list *old_p = p;
+ while (old_p)
+ {
+ old_p = p->next;
+ free (p);
+ p = old_p;
+ }
+}
+
+static struct dso_list *
+in_dso_list (struct dso_list *dso_list, const char *soname, const char *filename)
+{
+ while (dso_list != NULL)
+ {
+ if (dso_list->dso != NULL)
+ {
+ if (strcmp (dso_list->dso->soname, soname) == 0)
+ return dso_list;
+ }
+
+ if (strcmp (dso_list->name, soname) == 0)
+ return dso_list;
+
+ if (filename && dso_list->canon_filename
+ && strcmp (dso_list->canon_filename, filename) == 0)
+ return dso_list;
+
+ dso_list = dso_list->next;
+ }
+ return NULL;
+}
+
+static int
+in_needed_list (struct needed_list *needed_list, const char *soname)
+{
+ while (needed_list != NULL)
+ {
+ if (needed_list->ent->dso != NULL
+ && strcmp (needed_list->ent->dso->soname, soname) == 0)
+ return 1;
+ needed_list = needed_list->next;
+ }
+ return 0;
+}
+
+
+/****/
+
+void
+add_dir (struct search_path *path, const char *dir, int dirlen)
+{
+ if (path->allocated == 0)
+ {
+ path->allocated = 5;
+ path->dirs = malloc (sizeof (char *) * 5);
+ }
+ else if (path->count == path->allocated)
+ {
+ path->allocated *= 2;
+ path->dirs = realloc (path->dirs, sizeof (char *) * path->allocated);
+ }
+ path->dirs[path->count] = malloc (dirlen + 1);
+ memcpy (path->dirs[path->count], dir, dirlen);
+ path->dirs[path->count++][dirlen] = 0;
+
+ if (path->maxlen < dirlen)
+ path->maxlen = dirlen;
+}
+
+void
+free_path (struct search_path *path)
+{
+ if (path->allocated)
+ {
+ int i;
+ for (i = 0; i < path->count; i++)
+ free (path->dirs[i]);
+ free (path->dirs);
+ }
+}
+
+void
+load_ld_so_conf (int use_64bit, int use_mipsn32)
+{
+ int fd;
+ FILE *conf;
+ char buf[1024];
+
+ memset (&ld_dirs, 0, sizeof (ld_dirs));
+
+ /* Only use the correct machine, to prevent mismatches if we
+ have both /lib/ld.so and /lib64/ld.so on x86-64. */
+ if (use_64bit)
+ {
+ dst_LIB = "lib64";
+ add_dir (&ld_dirs, "/lib64/tls", strlen ("/lib64/tls"));
+ add_dir (&ld_dirs, "/lib64", strlen ("/lib64"));
+ add_dir (&ld_dirs, "/usr/lib64/tls", strlen ("/usr/lib64/tls"));
+ add_dir (&ld_dirs, "/usr/lib64", strlen ("/usr/lib64"));
+ }
+ else if (use_mipsn32)
+ {
+ dst_LIB = "lib32";
+ add_dir (&ld_dirs, "/lib32/tls", strlen ("/lib32/tls"));
+ add_dir (&ld_dirs, "/lib32", strlen ("/lib32"));
+ add_dir (&ld_dirs, "/usr/lib32/tls", strlen ("/usr/lib32/tls"));
+ add_dir (&ld_dirs, "/usr/lib32", strlen ("/usr/lib32"));
+ }
+ else
+ {
+ dst_LIB = "lib";
+ add_dir (&ld_dirs, "/lib/tls", strlen ("/lib/tls"));
+ add_dir (&ld_dirs, "/lib", strlen ("/lib"));
+ add_dir (&ld_dirs, "/usr/lib/tls", strlen ("/usr/lib/tls"));
+ add_dir (&ld_dirs, "/usr/lib", strlen ("/usr/lib"));
+ }
+
+ fd = wrap_open ("/etc/ld.so.conf", O_RDONLY);
+ if (fd == -1)
+ return;
+ conf = fdopen (fd, "r");
+ while (fgets (buf, 1024, conf) != NULL)
+ {
+ int len;
+ char *p;
+
+ p = strchr (buf, '#');
+ if (p)
+ *p = 0;
+ len = strlen (buf);
+ while (len > 0 && isspace (buf[len - 1]))
+ buf[--len] = 0;
+
+ if (len > 0)
+ add_dir (&ld_dirs, buf, len);
+ }
+ fclose (conf);
+}
+
+void
+string_to_path (struct search_path *path, const char *string)
+{
+ const char *start, *end, *end_tmp;
+
+ start = string;
+ while (1) {
+ end = start;
+ while (*end && *end != ':' && *end != ';')
+ end ++;
+
+ /* Eliminate any trailing '/' characters, but be sure to leave a
+ leading slash if someeone wants / in their RPATH. */
+ end_tmp = end;
+ while (end_tmp > start + 1 && end_tmp[-1] == '/')
+ end_tmp --;
+
+ add_dir (path, start, end_tmp - start);
+
+ if (*end == 0)
+ break;
+
+ /* Skip the separator. */
+ start = end + 1;
+ }
+}
+
+char *
+find_lib_in_path (struct search_path *path, const char *soname,
+ int elfclass, int machine)
+{
+ char *ret = NULL;
+ int i;
+ int alt_machine;
+
+ switch (machine)
+ {
+ case EM_SPARC:
+ alt_machine = EM_SPARC32PLUS;
+ break;
+ case EM_SPARC32PLUS:
+ alt_machine = EM_SPARC;
+ break;
+ default:
+ alt_machine = machine;
+ break;
+ }
+
+ for (i = 0; i < path->count; i++)
+ {
+ char * fixup_path, * path_string;
+
+ path_string = fixup_path = strdup(path->dirs[i]);
+
+ while ((path_string = strchr (path_string, '$')))
+ {
+ char * replace = NULL;
+ size_t len = 0;
+
+ if (strncmp("$ORIGIN", path_string, 7) == 0) {
+ replace = dst_ORIGIN;
+ len = 7;
+ } else if (strncmp("${ORIGIN}", path_string, 9) == 0) {
+ replace = dst_ORIGIN;
+ len = 9;
+ } else if (strncmp("$PLATFORM", path_string, 9) == 0) {
+ replace = dst_PLATFORM;
+ len = 9;
+ } else if (strncmp("${PLATFORM}", path_string, 11) == 0) {
+ replace = dst_PLATFORM;
+ len = 11;
+ } else if (strncmp("$LIB", path_string, 4) == 0) {
+ replace = dst_LIB;
+ len = 4;
+ } else if (strncmp("${LIB}", path_string, 6) == 0) {
+ replace = dst_LIB;
+ len = 6;
+ } else {
+ /* Not a defined item, so we skip to the next character */
+ path_string += 1;
+ }
+
+ if (replace) {
+ size_t new_path_len = strlen(fixup_path) - len + strlen(replace) + 1;
+ char * new_path = malloc(new_path_len);
+
+ /* Calculate the new path_string position based on the old position */
+ size_t new_path_pos = (path_string - fixup_path) + strlen(replace);
+
+ snprintf(new_path, new_path_len, "%.*s%s%s", (int)(path_string-fixup_path),
+ fixup_path, replace, path_string + len);
+
+ free(fixup_path);
+
+ fixup_path = new_path;
+ path_string = fixup_path + new_path_pos;
+ }
+ }
+
+ ret = malloc (strlen (soname) + 2 + strlen(fixup_path));
+ sprintf (ret, "%s/%s", fixup_path, soname);
+
+ if (wrap_access (ret, F_OK) == 0)
+ {
+ DSO *dso = open_dso (ret);
+ int dso_class, dso_machine;
+
+ if (dso == NULL)
+ continue;
+
+ dso_class = gelf_getclass (dso->elf);
+ dso_machine = (dso_class == ELFCLASS32) ?
+ elf32_getehdr (dso->elf)->e_machine :
+ elf64_getehdr (dso->elf)->e_machine;
+
+ /* Skip 32-bit libraries when looking for 64-bit. Also
+ skip libraries for alternative machines. */
+ if (gelf_getclass (dso->elf) != elfclass
+ || (dso_machine != machine && dso_machine != alt_machine))
+ {
+ close_dso (dso);
+ continue;
+ }
+
+ close_dso (dso);
+ return ret;
+ }
+ }
+
+ free (ret);
+ return NULL;
+}
+
+char *
+find_lib_by_soname (const char *soname, struct dso_list *loader,
+ int elfclass, int machine)
+{
+ char *ret;
+
+ if (strchr (soname, '/'))
+ return strdup (soname);
+
+ if (is_ldso_soname (soname))
+ /* For dynamic linker, pull the path out of PT_INTERP header.
+ When loading an executable the dynamic linker creates an entry for
+ itself under the name stored in PT_INTERP, and the name that we
+ record in .gnu.liblist should match that exactly. */
+ {
+ struct dso_list *loader_p = loader;
+
+ while (loader_p)
+ {
+ if (loader_p->dso->ehdr.e_type == ET_EXEC)
+ {
+ int i;
+
+ for (i = 0; i < loader_p->dso->ehdr.e_phnum; ++i)
+ if (loader_p->dso->phdr[i].p_type == PT_INTERP)
+ {
+ const char *interp;
+ interp = get_data (loader_p->dso,
+ loader_p->dso->phdr[i].p_vaddr,
+ NULL, NULL);
+ return strdup (interp);
+ }
+ }
+ loader_p = loader_p->loader;
+ }
+ }
+
+ if (loader->dso->info[DT_RUNPATH] == 0)
+ {
+ /* Search DT_RPATH all the way up. */
+ struct dso_list *loader_p = loader;
+ while (loader_p)
+ {
+ if (loader_p->dso->info[DT_RPATH])
+ {
+ struct search_path r_path;
+ const char *rpath = get_data (loader_p->dso,
+ loader_p->dso->info[DT_STRTAB]
+ + loader_p->dso->info[DT_RPATH],
+ NULL, NULL);
+ memset (&r_path, 0, sizeof (r_path));
+ string_to_path (&r_path, rpath);
+ ret = find_lib_in_path (&r_path, soname, elfclass, machine);
+ free_path (&r_path);
+ if (ret)
+ return ret;
+ }
+ loader_p = loader_p->loader;
+ }
+ }
+
+ ret = find_lib_in_path (&ld_library_search_path, soname, elfclass, machine);
+ if (ret)
+ return ret;
+
+ if (loader->dso->info[DT_RUNPATH])
+ {
+ struct search_path r_path;
+ const char *rpath = get_data (loader->dso,
+ loader->dso->info[DT_STRTAB]
+ + loader->dso->info[DT_RUNPATH],
+ NULL, NULL);
+ memset (&r_path, 0, sizeof (r_path));
+ string_to_path (&r_path, rpath);
+ ret = find_lib_in_path (&r_path, soname, elfclass, machine);
+ free_path (&r_path);
+ if (ret)
+ return ret;
+ }
+
+ ret = find_lib_in_path (&ld_dirs, soname, elfclass, machine);
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+static struct dso_list *
+load_dsos (DSO *dso, int host_paths)
+{
+ struct dso_list *dso_list, *dso_list_tail, *cur_dso_ent, *new_dso_ent;
+ struct stat64 st;
+ int total_preload = 0;
+ char * libname[MAX_PRELOADED_LIBS] = {NULL};
+
+ /* Assume it's static unless we find DT_NEEDED entries */
+ static_binary = 1;
+
+ dso_list = malloc (sizeof (struct dso_list));
+ dso_list->dso = dso;
+ dso_list->map = NULL;
+ dso_list->next = NULL;
+ dso_list->prev = NULL;
+ dso_list->needed = NULL;
+ dso_list->name = dso->filename;
+ dso_list->loader = NULL;
+
+ if (host_paths)
+ dso_list->canon_filename = canonicalize_file_name (dso->filename);
+ else
+ dso_list->canon_filename = prelink_canonicalize (dso->filename, &st);
+
+ if (dso_list->canon_filename == NULL)
+ dso_list->canon_filename = strdup (dso->filename);
+
+ cur_dso_ent = dso_list_tail = dso_list;
+
+ if(dso->ehdr.e_type == ET_EXEC && ld_preload) {
+ char *next_lib = ld_preload;
+ libname[total_preload] = ld_preload;
+ total_preload++;
+ next_lib=strchr(ld_preload,':');
+ while(next_lib!=NULL){
+ *next_lib = '\0';
+ next_lib++;
+ libname[total_preload] = next_lib;
+ total_preload++;
+ next_lib=strchr(next_lib,':');
+ }
+ }
+ else {
+ total_preload = 0;
+ }
+ while (cur_dso_ent != NULL)
+ {
+ DSO *cur_dso, *new_dso;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Dyn dyn;
+
+ cur_dso = cur_dso_ent->dso;
+ if (cur_dso == NULL)
+ {
+ cur_dso_ent = cur_dso_ent->next;
+ continue;
+ }
+
+ scn = cur_dso->scn[cur_dso->dynamic];
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ maxndx = data->d_size / cur_dso->shdr[cur_dso->dynamic].sh_entsize;
+ for (ndx = 0; ndx < maxndx + total_preload; ++ndx)
+ {
+
+ if(ndx - total_preload >= 0) {
+ gelfx_getdyn (cur_dso->elf, data, ndx - total_preload, &dyn);
+ }
+ else {
+ dyn.d_tag = DT_NEEDED;
+ }
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+ if (dyn.d_tag == DT_NEEDED)
+ {
+ /* Not static... */
+ static_binary = 0;
+
+ char *new_name=NULL, *new_canon_name=NULL;
+ const char * soname = NULL;
+ if(ndx - total_preload >= 0) {
+ soname = get_data (cur_dso,
+ cur_dso->info[DT_STRTAB]
+ + dyn.d_un.d_val,
+ NULL, NULL);
+ }
+ else {
+ soname = libname[ndx];
+ }
+
+ new_dso_ent = in_dso_list (dso_list, soname, NULL);
+ if (new_dso_ent == NULL)
+ {
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
+ _dl_debug_printf ("file=%s [0]; needed by %s [0]\n",
+ soname, cur_dso->filename);
+
+ int machine;
+ int class = gelf_getclass (dso->elf);
+ machine = (class == ELFCLASS32) ?
+ elf32_getehdr (dso->elf)->e_machine :
+ elf64_getehdr (dso->elf)->e_machine;
+ new_name = find_lib_by_soname (soname, cur_dso_ent,
+ class, machine);
+ if (new_name == 0 || wrap_access (new_name, R_OK) < 0)
+ {
+ dso_open_error ++;
+
+ new_dso_ent = malloc (sizeof (struct dso_list));
+ dso_list_tail->next = new_dso_ent;
+ dso_list_tail->next->prev = dso_list_tail;
+ dso_list_tail = dso_list_tail->next;
+ dso_list_tail->next = NULL;
+ dso_list_tail->dso = NULL;
+ dso_list_tail->map = NULL;
+ dso_list_tail->needed = NULL;
+ dso_list_tail->name = soname;
+ dso_list_tail->loader = NULL;
+ dso_list_tail->canon_filename = strdup(soname);
+ dso_list_tail->err_no = errno;
+
+ continue;
+ }
+
+ /* See if the filename we found has already been
+ opened (possibly under a different SONAME via
+ some symlink). */
+ new_canon_name = prelink_canonicalize (new_name, NULL);
+ if (new_canon_name == NULL)
+ new_canon_name = strdup (new_name);
+ new_dso_ent = in_dso_list (dso_list, soname, new_canon_name);
+ }
+ else if (new_dso_ent->dso == NULL)
+ continue;
+
+ if (new_dso_ent == NULL)
+ {
+ new_dso = open_dso (new_name);
+ free (new_name);
+ new_dso_ent = malloc (sizeof (struct dso_list));
+ dso_list_tail->next = new_dso_ent;
+ dso_list_tail->next->prev = dso_list_tail;
+ dso_list_tail = dso_list_tail->next;
+ dso_list_tail->next = NULL;
+ dso_list_tail->dso = new_dso;
+ dso_list_tail->map = NULL;
+ dso_list_tail->needed = NULL;
+ dso_list_tail->loader = cur_dso_ent;
+ dso_list_tail->canon_filename = new_canon_name;
+ dso_list_tail->err_no = 0;
+
+ if (is_ldso_soname (new_dso->soname))
+ dso_list_tail->name = new_dso->filename;
+ else if (strcmp (new_dso->soname, new_dso->filename) == 0)
+ /* new_dso->soname might be a full path if the library
+ had no SONAME. Use the original SONAME instead. */
+ dso_list_tail->name = soname;
+ else
+ /* Use the new SONAME if possible, in case some library
+ links to this one using an incorrect SONAME. */
+ dso_list_tail->name = new_dso->soname;
+ }
+
+ if (!cur_dso_ent->needed)
+ {
+ cur_dso_ent->needed = malloc (sizeof (struct needed_list));
+ cur_dso_ent->needed_tail = cur_dso_ent->needed;
+ cur_dso_ent->needed_tail->ent = new_dso_ent;
+ cur_dso_ent->needed_tail->next = NULL;
+ }
+ else if (!in_needed_list (cur_dso_ent->needed, soname))
+ {
+ cur_dso_ent->needed_tail->next = malloc (sizeof (struct needed_list));
+ cur_dso_ent->needed_tail = cur_dso_ent->needed_tail->next;
+ cur_dso_ent->needed_tail->ent = new_dso_ent;
+ cur_dso_ent->needed_tail->next = NULL;
+ }
+
+ continue;
+ }
+ if (dyn.d_tag == DT_FILTER || dyn.d_tag == DT_AUXILIARY)
+ {
+ // big fat warning;
+ }
+ }
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ return dso_list;
+}
+
+struct
+{
+ void *symptr;
+ int rtypeclass;
+} cache;
+
+void
+do_reloc (DSO *dso, struct link_map *map, struct r_scope_elem *scope[],
+ GElf_Word sym, GElf_Word type)
+{
+ struct r_found_version *ver;
+ int rtypeclass;
+ void *symptr;
+ const char *name;
+ Elf64_Word st_name;
+
+ if (map->l_versyms)
+ {
+ int vernum = map->l_versyms[sym] & 0x7fff;
+ ver = &map->l_versions[vernum];
+
+ /* Memory was allocated for the hash table, but it's empty! */
+ if (ver && (ver->name == NULL || ver->hash == 0))
+ ver = NULL;
+ }
+ else
+ ver = NULL;
+
+ rtypeclass = elf_machine_type_class (type, dso->ehdr.e_machine);
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ Elf32_Sym *sym32 = &((Elf32_Sym *)map->l_info[DT_SYMTAB])[sym];
+
+ if (ELF32_ST_BIND (sym32->st_info) == STB_LOCAL)
+ return;
+ symptr = sym32;
+ st_name = sym32->st_name;
+ }
+ else
+ {
+ Elf64_Sym *sym64 = &((Elf64_Sym *)map->l_info[DT_SYMTAB])[sym];
+
+ if (ELF64_ST_BIND (sym64->st_info) == STB_LOCAL)
+ return;
+ symptr = sym64;
+ st_name = sym64->st_name;
+ }
+
+ if (cache.symptr == symptr && cache.rtypeclass == rtypeclass)
+ return;
+ cache.symptr = symptr;
+ cache.rtypeclass = rtypeclass;
+
+ name = ((const char *)map->l_info[DT_STRTAB]) + st_name;
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ const Elf32_Sym *sym32 = symptr;
+ rtld_lookup_symbol_x32 (name, map, &sym32, scope, ver, rtypeclass,
+ 0, NULL);
+ symptr = (void *) sym32;
+ }
+ else
+ {
+ const Elf64_Sym *sym64 = symptr;
+ rtld_lookup_symbol_x64 (name, map, &sym64, scope, ver, rtypeclass,
+ 0, NULL);
+ symptr = (void *) sym64;
+ }
+}
+
+void
+do_rel_section (DSO *dso, struct link_map *map,
+ struct r_scope_elem *scope[],
+ int tag, int section)
+{
+ Elf_Data *data;
+ int ndx, maxndx, sym, type;
+
+ data = elf_getdata (dso->scn[section], NULL);
+ maxndx = data->d_size / dso->shdr[section].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ndx++)
+ {
+ if (tag == DT_REL)
+ {
+ GElf_Rel rel;
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sym = reloc_r_sym (dso, rel.r_info);
+ type = reloc_r_type (dso, rel.r_info);
+ }
+ else
+ {
+ GElf_Rela rela;
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sym = reloc_r_sym (dso, rela.r_info);
+ type = reloc_r_type (dso, rela.r_info);
+ }
+ if (sym != 0)
+ do_reloc (dso, map, scope, sym, type);
+ }
+}
+
+void
+do_relocs (DSO *dso, struct link_map *map, struct r_scope_elem *scope[], int tag)
+{
+ GElf_Addr rel_start, rel_end;
+ GElf_Addr pltrel_start, pltrel_end;
+ int first, last;
+
+ /* Load the DT_REL or DT_RELA section. */
+ if (dso->info[tag] != 0)
+ {
+ rel_start = dso->info[tag];
+ rel_end = rel_start + dso->info[tag == DT_REL ? DT_RELSZ : DT_RELASZ];
+ first = addr_to_sec (dso, rel_start);
+ last = addr_to_sec (dso, rel_end - 1);
+ while (first <= last)
+ do_rel_section (dso, map, scope, tag, first++);
+
+ /* If the DT_JMPREL relocs are of the same type and not included,
+ load them too. Assume they overlap completely or not at all,
+ and are in at most a single section. They also need to be adjacent. */
+ if (dso->info[DT_PLTREL] == tag)
+ {
+ pltrel_start = dso->info[DT_JMPREL];
+ pltrel_end = pltrel_start + dso->info[DT_PLTRELSZ];
+ if (pltrel_start < rel_start || pltrel_end >= rel_end)
+ do_rel_section (dso, map, scope, tag, addr_to_sec (dso, pltrel_start));
+ }
+ }
+ else if (dso->info[DT_PLTREL] == tag)
+ do_rel_section (dso, map, scope, tag, addr_to_sec (dso, dso->info[DT_JMPREL]));
+}
+
+/* MIPS GOTs are not handled by normal relocations. Instead, entry X
+ in the global GOT is associated with symbol DT_MIPS_GOTSYM + X.
+ For the purposes of symbol lookup and conflict resolution, we need
+ to act as though entry X had a dynamic relocation against symbol
+ DT_MIPS_GOTSYM + X. */
+
+void
+do_mips_global_got_relocs (DSO *dso, struct link_map *map,
+ struct r_scope_elem *scope[])
+{
+ GElf_Word i;
+
+ for (i = dso->info_DT_MIPS_GOTSYM; i < dso->info_DT_MIPS_SYMTABNO; i++)
+ do_reloc (dso, map, scope, i, R_MIPS_REL32);
+}
+
+void
+handle_relocs_in_entry (struct dso_list *entry, struct dso_list *dso_list)
+{
+ do_relocs (entry->dso, entry->map, dso_list->map->l_local_scope, DT_REL);
+ do_relocs (entry->dso, entry->map, dso_list->map->l_local_scope, DT_RELA);
+ if (entry->dso->ehdr.e_machine == EM_MIPS)
+ do_mips_global_got_relocs (entry->dso, entry->map,
+ dso_list->map->l_local_scope);
+}
+
+void
+handle_relocs (DSO *dso, struct dso_list *dso_list)
+{
+ struct dso_list *ldso, *tail;
+
+ /* do them all last to first.
+ skip the dynamic linker; then do it last
+ in glibc this is conditional on the opencount; but every binary
+ should be linked to libc and thereby have an opencount for ld.so...
+ besides, that's the only way it would get on our dso list. */
+
+ tail = dso_list;
+ while (tail->next)
+ tail = tail->next;
+
+ ldso = NULL;
+ while (tail)
+ {
+ if (is_ldso_soname (tail->dso->soname))
+ ldso = tail;
+ else
+ handle_relocs_in_entry (tail, dso_list);
+ tail = tail->prev;
+ }
+
+ if (ldso)
+ handle_relocs_in_entry (ldso, dso_list);
+}
+
+void
+add_to_scope (struct r_scope_elem *scope[], struct dso_list *ent)
+{
+ struct needed_list *n;
+ int i;
+
+ for (i = 0; i < scope[0]->r_nlist; i++)
+ if (scope[0]->r_list[i] == ent->map)
+ return;
+
+ scope[0]->r_list[scope[0]->r_nlist++] = ent->map;
+ n = ent->needed;
+ while (n)
+ {
+ add_to_scope (scope, n->ent);
+ n = n->next;
+ }
+}
+
+void
+build_local_scope (struct dso_list *ent, int max)
+{
+ ent->map->l_local_scope[0] = malloc (sizeof (struct r_scope_elem));
+ ent->map->l_local_scope[0]->r_list = malloc (sizeof (struct link_map *) * max);
+ ent->map->l_local_scope[0]->r_nlist = 0;
+ add_to_scope (ent->map->l_local_scope, ent);
+}
+
+static struct argp argp = { options, parse_opt, "[FILES]", argp_doc };
+
+struct link_map *requested_map = NULL;
+
+static void process_one_dso (DSO *dso, int host_paths);
+
+int
+main(int argc, char **argv)
+{
+ int remaining;
+ int multiple = 0;
+ host_paths = 1;
+
+ char * debug = NULL;
+
+ sysroot = getenv ("PRELINK_SYSROOT");
+#ifdef DEFAULT_SYSROOT
+ if (sysroot == NULL)
+ {
+ extern char *make_relative_prefix (const char *, const char *, const char *);
+ sysroot = make_relative_prefix (argv[0], BINDIR, DEFAULT_SYSROOT);
+ }
+#endif
+
+ elf_version (EV_CURRENT);
+
+ argp_parse (&argp, argc, argv, 0, &remaining, 0);
+
+ if (sysroot)
+ sysroot = canonicalize_file_name (sysroot);
+
+ if (remaining == argc)
+ error (1, 0, "missing file arguments\nTry `%s: --help' for more information.", argv[0]);
+
+ if ((argc-remaining) >= 2)
+ multiple = 1;
+
+ /* More simplistic then glibc, one option only... */
+ debug = getenv ("RTLD_DEBUG");
+ if (debug && (!strcmp(debug, "files") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_FILES;
+
+ if (debug && (!strcmp(debug, "symbols") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_SYMBOLS;
+
+ if (debug && (!strcmp(debug, "versions") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_VERSIONS;
+
+ if (debug && (!strcmp(debug, "bindings") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_BINDINGS;
+
+ while (remaining < argc)
+ {
+ DSO *dso = NULL;
+ int i, fd;
+
+ struct stat64 st;
+
+ if (host_paths)
+ fd = open (argv[remaining], O_RDONLY);
+ else
+ fd = wrap_open (argv[remaining], O_RDONLY);
+
+ if (fd >= 0 && fstat64(fd, &st) == 0)
+ if (!S_ISREG(st.st_mode))
+ {
+ error (0, 0, "%s: %s",
+ argv[remaining],
+ "not regular file");
+ goto exit;
+ }
+
+ if (fd >= 0) {
+ dso = fdopen_dso (fd, argv[remaining]);
+ dst_ORIGIN = dirname(strdup(dso->filename));
+ }
+
+ if (dso == NULL)
+ {
+ error (0, 0, "%s: %s",
+ argv[remaining],
+ strerror(errno));
+ goto exit;
+ }
+
+ load_ld_so_conf (gelf_getclass (dso->elf) == ELFCLASS64,
+ ( dso->ehdr.e_machine == EM_MIPS) && ( dso->ehdr.e_flags & EF_MIPS_ABI2 ) );
+
+ if (multiple)
+ printf ("%s:\n", argv[remaining]);
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ break;
+
+ /* If there are no PT_INTERP segments, it is statically linked. */
+ if (dso->ehdr.e_type == ET_EXEC && i == dso->ehdr.e_phnum)
+ printf ("\tnot a dynamic executable\n");
+ else
+ {
+ int j;
+ Elf_Data *data;
+ j = addr_to_sec (dso, dso->phdr[i].p_vaddr);
+ if (j != -1)
+ {
+ data = elf_getdata (dso->scn[j], NULL);
+ if (data != NULL)
+ {
+ i = strnlen (data->d_buf, data->d_size);
+ if (i == data->d_size)
+ {
+ rtld_signal_error (0, dso->filename, NULL, ".interp section not zero terminated", 0);
+ }
+ else
+ {
+ rtld_progname = strdup (data->d_buf);
+ }
+ }
+ }
+ process_one_dso (dso, host_paths);
+ }
+
+exit:
+ remaining++;
+ }
+
+ return 0;
+}
+
+/* If you run ldd /lib/ld.so you get:
+ \tstatically linked
+
+ The prelink-rtld does not do this, and returns blank...
+ */
+static void
+process_one_dso (DSO *dso, int host_paths)
+{
+ struct dso_list *dso_list, *cur_dso_ent, *old_dso_ent;
+ const char *req;
+ int i;
+ int ld_warn = 1;
+
+ if ((req = getenv ("RTLD_TRACE_PRELINKING")) != NULL)
+ _dl_debug_mask |= DL_DEBUG_PRELINK;
+
+ /* Close enough. Really it's if LD_WARN is "" and RTLD_TRACE_PRELINKING. */
+ if (getenv ("RTLD_WARN") == NULL)
+ ld_warn = 0;
+
+ /* Initialize unique symtable list */
+ _ns_unique_sym_table = calloc(sizeof (struct unique_sym_table), 1);
+
+ dso_list = load_dsos (dso, host_paths);
+
+ cur_dso_ent = dso_list;
+ i = 0;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->dso)
+ {
+ create_map_object_from_dso_ent (cur_dso_ent);
+ if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && strcmp (req, cur_dso_ent->dso->filename) == 0)
+ requested_map = cur_dso_ent->map;
+ }
+ else
+ {
+ /* This is a dummy entry, we couldn't find the object */
+ cur_dso_ent->map = _dl_new_object(cur_dso_ent->name, cur_dso_ent->canon_filename, lt_library);
+ }
+ i++;
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ dso_list->map->l_local_scope[0] = malloc (sizeof (struct r_scope_elem));
+ dso_list->map->l_local_scope[0]->r_list = malloc (sizeof (struct link_map *) * i);
+ dso_list->map->l_local_scope[0]->r_nlist = i;
+ cur_dso_ent = dso_list;
+ i = 0;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->map)
+ {
+ dso_list->map->l_local_scope[0]->r_list[i] = cur_dso_ent->map;
+ if (cur_dso_ent != dso_list)
+ build_local_scope (cur_dso_ent, dso_list->map->l_local_scope[0]->r_nlist);
+
+ i++;
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+
+ cur_dso_ent = dso_list;
+
+ for (i = 0; i < cur_dso_ent->map->l_local_scope[0]->r_nlist; ++i)
+ if (cur_dso_ent->map->l_local_scope[0]->r_list[i]->l_versions == NULL)
+ _dl_check_map_versions (cur_dso_ent->map->l_local_scope[0]->r_list[i], 0, 0);
+
+ rtld_determine_tlsoffsets (dso->ehdr.e_machine, dso_list->map->l_local_scope[0]);
+
+ cur_dso_ent = dso_list;
+
+ /* In ldd mode, do not show the application. Note that we do show it
+ in list-loaded-objects RTLD_TRACE_PRELINK mode. */
+ if (!(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && cur_dso_ent)
+ {
+ /* Based on the presence of DT_NEEDED, see load_dsos */
+ if (static_binary)
+ {
+ printf ("\tstatically linked\n");
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ while (cur_dso_ent)
+ {
+ char *filename;
+
+ if (host_paths && sysroot && cur_dso_ent->dso)
+ {
+ const char *rooted_filename;
+
+ if (cur_dso_ent->dso->filename[0] == '/')
+ rooted_filename = cur_dso_ent->dso->filename;
+ else
+ rooted_filename = cur_dso_ent->canon_filename;
+
+ filename = malloc (strlen (rooted_filename) + strlen (sysroot) + 1);
+ strcpy (filename, sysroot);
+ strcat (filename, rooted_filename);
+ }
+ else if (cur_dso_ent->dso)
+ filename = strdup (cur_dso_ent->dso->filename);
+ else
+ filename = NULL;
+
+ int size_pointer = 16;
+ if (cur_dso_ent && cur_dso_ent->dso && gelf_getclass (cur_dso_ent->dso->elf) == ELFCLASS32)
+ size_pointer = 8;
+
+ /* The difference between the two numbers must be dso->base,
+ and the first number must be unique. */
+ if (dso_open_error && ld_warn && (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK))
+ {
+ if (cur_dso_ent->dso == NULL)
+ rtld_signal_error(cur_dso_ent->err_no, cur_dso_ent->name, NULL, "cannot open shared object file", 0);
+ }
+ else if (cur_dso_ent->dso == NULL)
+ printf ("\t%s => not found\n", cur_dso_ent->name);
+ else if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+ struct link_map * l = cur_dso_ent->map;
+ if (size_pointer == 16)
+ printf ("\t%s => %s (0x%016"PRIx64", 0x%016"PRIx64")",
+ cur_dso_ent->name ? cur_dso_ent->name
+ : rtld_progname ?: "<main program>",
+ filename ? filename
+ : rtld_progname ?: "<main program>",
+ (uint64_t) l->l_map_start,
+ (uint64_t) (l->l_map_start == cur_dso_ent->dso->base ? 0 : l->l_map_start));
+ else
+ printf ("\t%s => %s (0x%08"PRIx32", 0x%08"PRIx32")",
+ cur_dso_ent->name ? cur_dso_ent->name
+ : rtld_progname ?: "<main program>",
+ filename ? filename
+ : rtld_progname ?: "<main program>",
+ (uint32_t) l->l_map_start,
+ (uint32_t) (l->l_map_start == cur_dso_ent->dso->base ? 0 : l->l_map_start));
+
+ if (l->l_tls_modid)
+ if (size_pointer == 16)
+ printf (" TLS(0x%"PRIx64", 0x%016"PRIx64")\n",
+ (uint64_t) l->l_tls_modid,
+ (uint64_t) l->l_tls_offset);
+ else
+ printf (" TLS(0x%"PRIx32", 0x%08"PRIx32")\n",
+ (uint32_t) l->l_tls_modid,
+ (uint32_t) l->l_tls_offset);
+ else
+ printf ("\n");
+ }
+ else
+ {
+ struct link_map * l = cur_dso_ent->map;
+ if (!(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && strcmp (cur_dso_ent->name, filename) == 0)
+ if (size_pointer == 16)
+ printf ("\t%s (0x%016"PRIx64")\n", cur_dso_ent->name,
+ (uint64_t) l->l_map_start);
+ else
+ printf ("\t%s (0x%08"PRIx32")\n", cur_dso_ent->name,
+ (uint32_t) l->l_map_start);
+ else
+ if (size_pointer == 16)
+ printf ("\t%s => %s (0x%016"PRIx64")\n", cur_dso_ent->name,
+ filename,
+ (uint64_t) l->l_map_start);
+ else
+ printf ("\t%s => %s (0x%08"PRIx32")\n", cur_dso_ent->name,
+ filename,
+ (uint32_t) l->l_map_start);
+ }
+
+ if (filename)
+ free (filename);
+
+ cur_dso_ent = cur_dso_ent->next;
+ }
+
+ if (dso_open_error)
+ exit (127);
+
+ if (!ld_warn && (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK))
+ handle_relocs (dso_list->dso, dso_list);
+
+ cur_dso_ent = dso_list;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->dso)
+ close_dso (cur_dso_ent->dso);
+ old_dso_ent = cur_dso_ent;
+ cur_dso_ent = cur_dso_ent->next;
+ if (old_dso_ent->needed)
+ free_needed (old_dso_ent->needed);
+ free (old_dso_ent);
+ }
+}
diff --git a/src/rtld/rtld.h b/src/rtld/rtld.h
new file mode 100644
index 0000000..c7b5d91
--- /dev/null
+++ b/src/rtld/rtld.h
@@ -0,0 +1,338 @@
+#ifndef _LD_LIBS_H
+#define _LD_LIBS_H
+
+#include "prelinktab.h"
+
+#include <elf.h>
+
+#if !defined (__linux__)
+#define DT_VERSIONTAGNUM 16
+#endif
+
+#define link_map ldlibs_link_map
+
+struct needed_list
+{
+ struct dso_list *ent;
+ struct needed_list *next;
+};
+
+struct dso_list
+{
+ DSO *dso;
+ struct link_map *map;
+ struct dso_list *next, *prev;
+ struct needed_list *needed, *needed_tail;
+ const char *name;
+ struct dso_list *loader;
+ const char *canon_filename;
+ int err_no;
+};
+
+/* A data structure for a simple single linked list of strings. */
+struct libname_list
+ {
+ const char *name; /* Name requested (before search). */
+ struct libname_list *next; /* Link to next name for this object. */
+ };
+
+struct link_map;
+
+struct r_scope_elem
+{
+ struct link_map **r_list;
+ unsigned int r_nlist;
+};
+
+struct r_found_version
+ {
+ const char *name;
+ Elf64_Word hash;
+
+ int hidden;
+ const char *filename;
+ };
+
+struct unique_sym_table
+ {
+ struct unique_sym
+ {
+ uint32_t hashval;
+ const char *name;
+ const void *sym;
+ const struct link_map *map;
+ } *entries;
+ size_t size;
+ size_t n_elements;
+ void (*free) (void *);
+ };
+
+extern struct unique_sym_table * _ns_unique_sym_table;
+
+/* The size of entries in .hash. Only Alpha and 64-bit S/390 use 64-bit
+ entries; those are not currently supported. */
+typedef uint32_t Elf_Symndx;
+
+/* Mimic libc/include/link.h struct link_map */
+
+struct link_map
+ {
+ int elfclass;
+
+ const char *l_name;
+
+ struct libname_list *l_libname;
+
+#undef DT_THISPROCNUM
+#define DT_THISPROCNUM 0
+
+ void *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
+
+ /* Array with vesion names. */
+ struct r_found_version *l_versions;
+ unsigned int l_nversions;
+
+ /* Symbol hash table. */
+ Elf_Symndx l_nbuckets;
+ /* Begin PPC64 workaround */
+ void *l_buckets_start;
+ void *l_buckets_end;
+ /* end workaround */
+ Elf32_Word l_gnu_bitmask_idxbits;
+ Elf32_Word l_gnu_shift;
+ void *l_gnu_bitmask;
+ union
+ {
+ const Elf32_Word *l_gnu_buckets;
+ const Elf_Symndx *l_chain;
+ };
+ union
+ {
+ const Elf32_Word *l_gnu_chain_zero;
+ const Elf_Symndx *l_buckets;
+ };
+
+ enum /* Where this object came from. */
+ {
+ lt_executable, /* The main executable program. */
+ lt_library, /* Library needed by main executable. */
+ lt_loaded /* Extra run-time loaded shared object. */
+ } l_type:2;
+
+ /* Pointer to the version information if available. */
+ Elf64_Versym *l_versyms;
+
+ /* Start and finish of memory map for this object. l_map_start
+ need not be the same as l_addr. */
+ Elf64_Addr l_map_start;
+
+ /* A similar array, this time only with the local scope. This is
+ used occasionally. */
+ struct r_scope_elem *l_local_scope[2];
+
+ /* Thread-local storage related info. */
+
+ /* Size of the TLS block. */
+ uint64_t l_tls_blocksize;
+ /* Alignment requirement of the TLS block. */
+ uint64_t l_tls_align;
+ /* Offset of first byte module alignment. */
+ uint64_t l_tls_firstbyte_offset;
+
+ /* For objects present at startup time: offset in the static TLS block. */
+ uint64_t l_tls_offset;
+ /* Index of the module in the dtv array. */
+ uint64_t l_tls_modid;
+
+ Elf64_Addr sym_base;
+ const char *filename;
+
+ Elf64_Half machine;
+ };
+
+#define ELF_RTYPE_CLASS_COPY 2
+#define ELF_RTYPE_CLASS_PLT 1
+
+int elf_machine_type_class(int type, int machine);
+
+int extern_protected_data(int machine);
+#define ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(machine) extern_protected_data(machine)
+
+int machine_no_rela(int machine);
+#define ELF_MACHINE_NO_RELA(machine) machine_no_rela(machine)
+
+int machine_no_rel(int machine);
+#define ELF_MACHINE_NO_REL(machine) machine_no_rel(machine)
+
+#define GL(x) _##x
+#define GLRO(x) _##x
+#define INTUSE(x) x
+
+#define D_PTR(MAP,MEM) MAP->MEM
+#define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+
+extern unsigned int _dl_debug_mask;
+extern unsigned int _dl_dynamic_weak;
+
+extern const char *rtld_progname;
+
+/* This is an optional value before the ':' when debuging is enabled. */
+/* Typically glibc sets this to a number of spaces and the pid of the process*/
+#ifndef RTLD_DEBUG_PID
+# define RTLD_DEBUG_PID " "
+#endif
+#define _dl_debug_printf(...) printf( RTLD_DEBUG_PID ":\t" __VA_ARGS__)
+
+#define __rtld_lock_lock_recursive(NAME)
+#define __rtld_lock_unlock_recursive(NAME)
+
+/* glibc-2.20: sysdeps/generic/ldsodefs.h */
+/* The filename itself, or the main program name, if available. */
+#define DSO_FILENAME(name) ((name)[0] ? (name) \
+ : (rtld_progname ?: "<main program>"))
+
+#define RTLD_PROGNAME (rtld_progname ?: "<program name unknown>")
+
+/* glibc-2.20: sysdeps/generic/ldsodefs.h */
+#define DL_DEBUG_LIBS (1 << 0)
+#define DL_DEBUG_IMPCALLS (1 << 1)
+#define DL_DEBUG_BINDINGS (1 << 2)
+#define DL_DEBUG_SYMBOLS (1 << 3)
+#define DL_DEBUG_VERSIONS (1 << 4)
+#define DL_DEBUG_RELOC (1 << 5)
+#define DL_DEBUG_FILES (1 << 6)
+#define DL_DEBUG_STATISTICS (1 << 7)
+#define DL_DEBUG_UNUSED (1 << 8)
+#define DL_DEBUG_SCOPES (1 << 9)
+/* These two are used only internally. */
+#define DL_DEBUG_HELP (1 << 10)
+#define DL_DEBUG_PRELINK (1 << 11)
+
+#define _dl_trace_prelink_map requested_map
+
+extern struct link_map *requested_map;
+
+#ifndef __glibc_unlikely
+#define __glibc_unlikely(a) (a)
+#endif
+
+#ifndef __glibc_likely
+#define __glibc_likely(a) (a)
+#endif
+
+/* dl-load.c */
+
+#define _dl_new_object rtld_new_object
+
+struct link_map * _dl_new_object (const char *realname, const char *libname, int type);
+
+/* dl-lookup.c */
+
+#define lookup_t struct link_map *
+#define LOOKUP_VALUE(map) map
+
+/* Search loaded objects' symbol tables for a definition of the symbol
+ referred to by UNDEF. *SYM is the symbol table entry containing the
+ reference; it is replaced with the defining symbol, and the base load
+ address of the defining object is returned. SYMBOL_SCOPE is a
+ null-terminated list of object scopes to search; each object's
+ l_searchlist (i.e. the segment of the dependency tree starting at that
+ object) is searched in turn. REFERENCE_NAME should name the object
+ containing the reference; it is used in error messages.
+ TYPE_CLASS describes the type of symbol we are looking for. */
+enum
+ {
+ /* If necessary add dependency between user and provider object. */
+ DL_LOOKUP_ADD_DEPENDENCY = 1,
+ /* Return most recent version instead of default version for
+ unversioned lookup. */
+ DL_LOOKUP_RETURN_NEWEST = 2,
+ /* Set if dl_lookup* called with GSCOPE lock held. */
+ DL_LOOKUP_GSCOPE_LOCK = 4,
+ };
+
+#define _dl_setup_hash rtld_setup_hash
+void _dl_setup_hash (struct link_map *map);
+
+#define _dl_lookup_symbol_x32 rtld_lookup_symbol_x32
+#define _dl_lookup_symbol_x64 rtld_lookup_symbol_x64
+
+/* Lookup versioned symbol. */
+inline lookup_t _dl_lookup_symbol_x (const char *undef,
+ struct link_map *undef_map,
+ const Elf64_Sym **sym,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags,
+ struct link_map *skip_map);
+
+/* Lookup versioned symbol. */
+lookup_t _dl_lookup_symbol_x32 (const char *undef,
+ struct link_map *undef_map,
+ const Elf32_Sym **sym,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags,
+ struct link_map *skip_map);
+
+/* Lookup versioned symbol. */
+lookup_t _dl_lookup_symbol_x64 (const char *undef,
+ struct link_map *undef_map,
+ const Elf64_Sym **sym,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags,
+ struct link_map *skip_map);
+
+/* dl-version.c */
+
+#define _dl_check_map_versions rtld_check_map_versions
+int _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode);
+
+#define _dl_name_match_p rtld_name_match_p
+int _dl_name_match_p (const char *name, const struct link_map *map);
+
+/* Error handling */
+
+#include <error.h>
+#include <errno.h>
+
+/* Mimic the behavior and output of _dl_signal_error */
+#define rtld_signal_error(errcode, objname, occation, errstring, status) \
+ error(status, errcode, "%s: %s%s%s", \
+ occation ?: "error while loading shared libraries", \
+ objname ?: "", (objname && *(char *)objname) ? ": " : "", \
+ errstring ?: "DYNAMIC LINKER BUG!!!")
+
+#define _dl_signal_error(errcode, objname, occation, errstring) rtld_signal_error(errcode, objname, occation, errstring, 1)
+#define _dl_signal_cerror(errcode, objname, occation, errstring) rtld_signal_error(errcode, objname, occation, errstring, 0)
+#define _dl_fatal_printf(errstring) rtld_signal_error(EINVAL, NULL, NULL, errstring, 1)
+
+/* dl-load.c */
+
+extern void create_map_object_from_dso_ent (struct dso_list *);
+
+/* dl-tls.c */
+
+void rtld_determine_tlsoffsets (int e_machine, struct r_scope_elem *search_list);
+
+#define _dl_determine_tlsoffsets rtld_determine_tlsoffsets
+
+/* dl-misc.c */
+
+#define _dl_name_match_p rtld_name_match_p
+#define _dl_higher_prime_number rtld_higher_prime_number
+
+extern int _dl_name_match_p (const char *name, const struct link_map *map);
+extern unsigned long int _dl_higher_prime_number (unsigned long int n);
+
+
+#if defined(__MINGW32__)
+# define HOST_LONG_LONG_FORMAT "I64"
+#else
+# define HOST_LONG_LONG_FORMAT "ll"
+#endif
+
+#endif
+