diff options
Diffstat (limited to 'src/rtld')
-rw-r--r-- | src/rtld/COPYING | 339 | ||||
-rw-r--r-- | src/rtld/COPYING.LIB | 502 | ||||
-rw-r--r-- | src/rtld/ChangeLog | 267 | ||||
-rw-r--r-- | src/rtld/Makefile.am | 32 | ||||
-rw-r--r-- | src/rtld/README-rtld | 18 | ||||
-rw-r--r-- | src/rtld/dl-hash.h | 77 | ||||
-rw-r--r-- | src/rtld/dl-load.c | 279 | ||||
-rw-r--r-- | src/rtld/dl-lookup.c | 131 | ||||
-rw-r--r-- | src/rtld/dl-lookupX.h | 896 | ||||
-rw-r--r-- | src/rtld/dl-misc.c | 106 | ||||
-rw-r--r-- | src/rtld/dl-object.c | 57 | ||||
-rw-r--r-- | src/rtld/dl-tls.c | 287 | ||||
-rw-r--r-- | src/rtld/dl-version.c | 369 | ||||
-rw-r--r-- | src/rtld/rtld.c | 1425 | ||||
-rw-r--r-- | src/rtld/rtld.h | 338 |
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, + ¤t_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, + ¤t_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 + |