mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 04:43:53 +00:00
Initial import of elftoolchain r2974.
Obtained from: elftoolchain.org
This commit is contained in:
commit
5265ace0e4
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/elftoolchain/dist/; revision=260684 svn path=/vendor/elftoolchain/elftoolchain-r2974/; revision=260685; tag=vendor/elftoolchain/elftoolchain-r2974
22
GNUmakefile
Normal file
22
GNUmakefile
Normal file
|
@ -0,0 +1,22 @@
|
|||
# -*- mode: makefile; -*-
|
||||
#
|
||||
# Issue a useful error message if a user tries to build the project
|
||||
# using GNU make.
|
||||
|
||||
all:
|
||||
$(error ERROR: This source tree needs to be built with BSD 'make'.)
|
||||
|
||||
# Some GNU/Linux distributions offer pre-built packages of BSD 'make':
|
||||
#
|
||||
# - On Debian-derived distributions, the "pmake" package provides an
|
||||
# older version of BSD 'make' that should suffice.
|
||||
# - On Fedora, the 'bmake' package seems appropriate (untested).
|
||||
#
|
||||
# Portable source code for NetBSD 'make' may be found at:
|
||||
# http://www.crufty.net/help/sjg/bmake.html
|
||||
#
|
||||
#
|
||||
# Please also read the file "INSTALL" for additional information about
|
||||
# building the project from source.
|
||||
#
|
||||
# $Id: GNUmakefile 2568 2012-09-04 12:13:21Z jkoshy $
|
283
INSTALL
Normal file
283
INSTALL
Normal file
|
@ -0,0 +1,283 @@
|
|||
Installation Instructions
|
||||
=========================
|
||||
|
||||
This file contains instructions on building and installing the
|
||||
libraries and utilities in the elftoolchain project's sources.
|
||||
|
||||
Supported Operating Systems
|
||||
---------------------------
|
||||
|
||||
The source tree is currently built and tested on the following
|
||||
operating systems.
|
||||
|
||||
================= ======== =======================
|
||||
Operating System Version Supported Architectures
|
||||
----------------- -------- -----------------------
|
||||
`DragonFly BSD`_ 2.10.1 i386
|
||||
FreeBSD_ v8.2 amd64 & i386
|
||||
Minix_ 3.0.2 i386
|
||||
NetBSD_ v5.0.2 i386
|
||||
OpenBSD_ v5.0 i386
|
||||
Ubuntu_ GNU/Linux 10.04LTS i386 & x86_64
|
||||
================= ======== =======================
|
||||
|
||||
.. _DragonFly BSD: http://www.dragonflybsd.org/
|
||||
.. _FreeBSD: http://www.freebsd.org/
|
||||
.. _Minix: http://www.minix3.org/
|
||||
.. _NetBSD: http://www.netbsd.org/
|
||||
.. _OpenBSD: http://www.openbsd.org/
|
||||
.. _Ubuntu: http://www.ubuntu.com/
|
||||
|
||||
Building the Source Tree
|
||||
========================
|
||||
|
||||
The core libraries and utilities that make up the software release are
|
||||
always built by default. Builds of the project's test suites (in the
|
||||
``test/`` subdirectory), and of additional documentation (in the
|
||||
directory ``documentation/``) are optional and will only be attempted
|
||||
if these directories are present.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
:DragonFly BSD 2.10.1:
|
||||
- The core libraries and utilities should build out of the box on
|
||||
a stock install of DragonFly BSD.
|
||||
|
||||
- To build and run the test suite:
|
||||
|
||||
#. The current release of the `Test Execution Toolkit`_ needs to
|
||||
be downloaded and unpacked into the ``test/tet/`` directory.
|
||||
|
||||
#. The ``py26-yaml`` package needs to be installed::
|
||||
|
||||
% sudo pkgin install py26-yaml
|
||||
|
||||
- Building additional documentation is not currently supported
|
||||
under DragonFly BSD.
|
||||
|
||||
:FreeBSD 8.2:
|
||||
- The core libraries and utilities should build out of the box on
|
||||
a stock install of FreeBSD.
|
||||
|
||||
- To build and run the test suite:
|
||||
|
||||
#. The current release of the `Test Execution Toolkit`_ needs to
|
||||
be downloaded and unpacked into the ``test/tet/`` directory.
|
||||
|
||||
#. The ``py-yaml`` package needs to be installed::
|
||||
|
||||
% sudo pkg_add -r py-yaml
|
||||
|
||||
- To build additional documentation, the ``latex-pgf`` package is
|
||||
needed::
|
||||
|
||||
% sudo pkg_add -r latex-pgf
|
||||
|
||||
:Minix 3.2.0:
|
||||
- The following packages are pre-requisites for building the
|
||||
sources on Minix 3.2.0:
|
||||
|
||||
=================== =====================================
|
||||
**Package** **Description**
|
||||
=================== =====================================
|
||||
``gcc44`` The GNU C compiler.
|
||||
=================== =====================================
|
||||
|
||||
The following command line may be used to install the necessary
|
||||
pre-requisites::
|
||||
|
||||
# pkgin install gcc44
|
||||
|
||||
- The test suites cannot currently be built under Minix.
|
||||
|
||||
- Building additional documentation is not currently supported
|
||||
under Minix.
|
||||
|
||||
:OpenBSD 5.0:
|
||||
- The following packages are pre-requisites for building the
|
||||
sources on OpenBSD 5.0:
|
||||
|
||||
=================== =====================================
|
||||
**Package** **Description**
|
||||
=================== =====================================
|
||||
``libarchive`` An archive access library.
|
||||
=================== =====================================
|
||||
|
||||
The following command line may be used to install the necessary
|
||||
pre-requisites::
|
||||
|
||||
# pkg_add libarchive-2.8.4p0
|
||||
|
||||
- The test suites cannot currently be built under OpenBSD.
|
||||
|
||||
- Building additional documentation is not currently supported
|
||||
under OpenBSD.
|
||||
|
||||
:NetBSD 5.0.2:
|
||||
- The core libraries and utilities should build out of the box
|
||||
on a stock install of NetBSD.
|
||||
|
||||
- To build and run the test suite:
|
||||
|
||||
#. The current release of the `Test Execution Toolkit`_, needs
|
||||
to be downloaded and unpacked into the ``test/tet/``
|
||||
directory.
|
||||
|
||||
#. The following additional package needs to be installed, as
|
||||
listed in the example command line below ::
|
||||
|
||||
% sudo pkg_add py26-yaml
|
||||
|
||||
- Building additional documentation is not currently supported
|
||||
under NetBSD.
|
||||
|
||||
:Ubuntu GNU/Linux 10.04:
|
||||
- The following packages are pre-requisites for building the
|
||||
sources on Ubuntu GNU/Linux 10.04:
|
||||
|
||||
=================== =====================================
|
||||
**Package** **Description**
|
||||
=================== =====================================
|
||||
``binutils`` Needed for the build.
|
||||
``bison`` Parser generator.
|
||||
``flex`` Lexical analyser.
|
||||
``gcc`` C compiler.
|
||||
``libarchive-dev`` Archive access library.
|
||||
``libc6-dev`` Files for C language development.
|
||||
``libexpat1-dev`` An XML processing library.
|
||||
``m4`` Macro processor.
|
||||
``pmake`` A ``make`` that uses BSD-make syntax.
|
||||
``python-yaml`` A YAML library for Python.
|
||||
``sharutils`` For ``uudecode``.
|
||||
=================== =====================================
|
||||
|
||||
The following command line may be used to install the necessary
|
||||
pre-requisites::
|
||||
|
||||
% sudo apt-get install binutils bison flex gcc libarchive-dev \
|
||||
libc6-dev m4 pmake
|
||||
|
||||
- To build and run the test suite:
|
||||
|
||||
#. The current release of the `Test Execution Toolkit`_, needs
|
||||
to be downloaded and unpacked into the ``test/tet/``
|
||||
directory.
|
||||
|
||||
#. The following additional packages need to be installed, as
|
||||
listed in the example command line below::
|
||||
|
||||
% sudo apt-get install libexpat1-dev python-yaml sharutils
|
||||
|
||||
- To build additional documentation, the ``pgf`` package is
|
||||
needed::
|
||||
|
||||
% sudo apt-get install pgf
|
||||
|
||||
:Ubuntu GNU/Linux 11.10:
|
||||
- The following packages are pre-requisites for building the
|
||||
sources on Ubuntu GNU/Linux 11.10:
|
||||
|
||||
=================== =====================================
|
||||
**Package** **Description**
|
||||
=================== =====================================
|
||||
``bison`` Parser generator.
|
||||
``flex`` Lexical analyser.
|
||||
``gcc`` C compiler.
|
||||
``libarchive-dev`` Archive access library.
|
||||
``libexpat1-dev`` An XML processing library.
|
||||
``m4`` Macro processor.
|
||||
``pmake`` A ``make`` that uses BSD-make syntax.
|
||||
``python-yaml`` A YAML library for Python.
|
||||
``sharutils`` For ``uudecode``.
|
||||
=================== =====================================
|
||||
|
||||
The following command line may be used to install the necessary
|
||||
pre-requisites::
|
||||
|
||||
% sudo apt-get install bison flex gcc libarchive-dev \
|
||||
m4 pmake
|
||||
|
||||
- To build and run the test suite:
|
||||
|
||||
#. The current release of the `Test Execution Toolkit`_, needs
|
||||
to be downloaded and unpacked into the ``test/tet/``
|
||||
directory.
|
||||
|
||||
#. The following additional packages need to be installed, as
|
||||
listed in the example command line below::
|
||||
|
||||
% sudo apt-get install libexpat1-dev python-yaml sharutils
|
||||
|
||||
- Builds of additional documentation are not currently supported
|
||||
under Ubuntu GNU/Linux 11.10.
|
||||
|
||||
.. _Test Execution Toolkit: http://tetworks.opengroup.org/
|
||||
.. _OpenGroup: http://www.opengroup.org/
|
||||
|
||||
|
||||
Building the software
|
||||
---------------------
|
||||
|
||||
The software may be built by running **make**.
|
||||
|
||||
On `DragonFly BSD`_, FreeBSD_, Minix_, NetBSD_ and OpenBSD_, use::
|
||||
|
||||
% make
|
||||
|
||||
On Ubuntu GNU/Linux with the **pmake** package installed, use::
|
||||
|
||||
% pmake
|
||||
|
||||
|
||||
Testing the software
|
||||
---------------------
|
||||
|
||||
The ``run-tests`` target in the top-level Makefile will build and
|
||||
execute the test suites that are part of this software.
|
||||
|
||||
On `DragonFly BSD`_, FreeBSD_ and NetBSD_, use::
|
||||
|
||||
% make run-tests
|
||||
|
||||
On Ubuntu GNU/Linux with the **pmake** package installed, use::
|
||||
|
||||
% pmake run-tests
|
||||
|
||||
Installing the Software
|
||||
=======================
|
||||
|
||||
The software may be installed using the ``install`` target.
|
||||
|
||||
On `DragonFly BSD`_, FreeBSD_, Minix_, NetBSD_ and OpenBSD_ use::
|
||||
|
||||
% make install
|
||||
|
||||
On Ubuntu GNU/Linux with the **pmake** package installed, use::
|
||||
|
||||
% pmake install
|
||||
|
||||
|
||||
By default the ``install`` target will install utilities into
|
||||
``/usr/bin/``, libraries into ``/usr/lib/`` and manual pages into
|
||||
``/usr/share/man/man[0-9]/``.
|
||||
|
||||
The installation directory may be changed using the ``DESTDIR``
|
||||
variable. For example::
|
||||
|
||||
% pmake DESTDIR=$HOME/local install
|
||||
|
||||
|
||||
Additional Information
|
||||
======================
|
||||
|
||||
Additional information about the project may be found on the `project
|
||||
website`_.
|
||||
|
||||
.. _project website: http://elftoolchain.sourceforge.net/
|
||||
|
||||
.. $Id: INSTALL 2777 2012-12-12 17:21:36Z jkoshy $
|
||||
|
||||
.. Local Variables:
|
||||
.. mode: rst
|
||||
.. End:
|
54
Makefile
Normal file
54
Makefile
Normal file
|
@ -0,0 +1,54 @@
|
|||
# $Id: Makefile 2872 2013-01-07 13:57:54Z jkoshy $
|
||||
|
||||
TOP= .
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.os.mk"
|
||||
|
||||
# Build configuration information first.
|
||||
SUBDIR += common
|
||||
|
||||
# Build the base libraries next.
|
||||
SUBDIR += libelf
|
||||
SUBDIR += libdwarf
|
||||
|
||||
# Build additional APIs.
|
||||
SUBDIR += libelftc
|
||||
|
||||
# Build the tools needed for the rest of the build.
|
||||
SUBDIR += isa
|
||||
|
||||
# Build tools after the libraries.
|
||||
SUBDIR += addr2line
|
||||
SUBDIR += ar
|
||||
SUBDIR += brandelf
|
||||
SUBDIR += cxxfilt
|
||||
SUBDIR += elfcopy
|
||||
SUBDIR += elfdump
|
||||
SUBDIR += findtextrel
|
||||
SUBDIR += nm
|
||||
SUBDIR += readelf
|
||||
SUBDIR += size
|
||||
SUBDIR += strings
|
||||
SUBDIR += tools
|
||||
|
||||
# Build the test suites.
|
||||
.if exists(${.CURDIR}/test) && defined(MKTESTS) && ${MKTESTS} == "yes"
|
||||
SUBDIR += test
|
||||
.endif
|
||||
|
||||
# Build documentation at the end.
|
||||
.if exists(${.CURDIR}/documentation) && defined(MKDOC) && ${MKDOC} == "yes"
|
||||
SUBDIR += documentation
|
||||
.endif
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.subdir.mk"
|
||||
|
||||
#
|
||||
# Special top-level targets.
|
||||
#
|
||||
|
||||
# Run the test suites.
|
||||
.if exists(${.CURDIR}/test) && defined(MKTESTS) && ${MKTESTS} == "yes"
|
||||
run-tests: all .PHONY
|
||||
(cd ${.CURDIR}/test; ${MAKE} test)
|
||||
.endif
|
127
README
Normal file
127
README
Normal file
|
@ -0,0 +1,127 @@
|
|||
The Elftoolchain Project
|
||||
========================
|
||||
|
||||
.. contents::
|
||||
..
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
This software implements essential compilation tools and libraries for:
|
||||
|
||||
- managing program objects conforming to the ELF_ object format, and
|
||||
- for managing DWARF_ debugging information in ELF objects.
|
||||
|
||||
The project currently implements the following utilities and
|
||||
libraries:
|
||||
|
||||
=========== ============================================
|
||||
Name Description
|
||||
=========== ============================================
|
||||
ar Archive manager.
|
||||
addr2line Debug tool.
|
||||
brandelf Manage the ELF brand on executables.
|
||||
c++filt Translate encoded symbols.
|
||||
elfcopy Copy and translate between object formats.
|
||||
elfdump Diagnostic tool.
|
||||
findtextrel Find undesired text relocations.
|
||||
libdwarf DWARF access library.
|
||||
libelf ELF access library.
|
||||
mcs Manage comment sections.
|
||||
nm List symbols in an ELF object.
|
||||
ranlib Add archive symbol tables to an archive.
|
||||
readelf Display ELF information.
|
||||
size List object sizes.
|
||||
strings Extract printable strings.
|
||||
strip Discard information from ELF objects.
|
||||
=========== ============================================
|
||||
|
||||
.. _ELF: http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
.. _DWARF: http://www.dwarfstd.org/
|
||||
|
||||
|
||||
Project Documentation
|
||||
---------------------
|
||||
|
||||
- Release notes for released versions of this software are present in
|
||||
the file ``RELEASE-NOTES`` in the current directory.
|
||||
- The file ``INSTALL`` in the current directory contains instructions
|
||||
on building and installing this software.
|
||||
- Reference documentation in the form of manual pages is provided for
|
||||
the utilities and libraries developed by the project.
|
||||
- Additional tutorial documentation is present in the
|
||||
``documentation`` directory.
|
||||
|
||||
|
||||
Tracking Ongoing Development
|
||||
----------------------------
|
||||
|
||||
The project uses subversion_ for its version control system.
|
||||
|
||||
The subversion branch for the current set of sources may be accessed
|
||||
at the following URL:
|
||||
|
||||
https://elftoolchain.svn.sourceforge.net/svnroot/elftoolchain/trunk
|
||||
|
||||
The project's source tree may be checked out from its repository by
|
||||
using the ``svn checkout`` command::
|
||||
|
||||
% svn checkout https://elftoolchain.svn.sourceforge.net/svnroot/elftoolchain/trunk
|
||||
|
||||
Checked-out sources may be kept upto-date by running ``svn update``
|
||||
inside the source directory::
|
||||
|
||||
% svn update
|
||||
|
||||
|
||||
Instructions on building and installing the software are given in the
|
||||
file ``INSTALL`` in the current directory.
|
||||
|
||||
.. _Subversion:
|
||||
|
||||
Downloading Released Software
|
||||
-----------------------------
|
||||
|
||||
Released versions of the project's software may also be downloaded
|
||||
from SourceForge's `file release system`_.
|
||||
|
||||
.. _file release system: http://sourceforge.net/projects/elftoolchain/files/
|
||||
|
||||
Copyright and License
|
||||
---------------------
|
||||
|
||||
This code is copyright its authors, and is distributed under the `BSD
|
||||
License`_.
|
||||
|
||||
.. _BSD License: http://www.opensource.org/licenses/bsd-license.php
|
||||
|
||||
|
||||
Developer Community
|
||||
-------------------
|
||||
|
||||
The project's developers may be contacted using the mailing list:
|
||||
``<elftoolchain-developers@lists.sourceforge.net>``.
|
||||
|
||||
|
||||
Reporting Bugs
|
||||
--------------
|
||||
|
||||
Please use our `Trac instance`_ for viewing existing bug reports and
|
||||
for submitting new bug reports.
|
||||
|
||||
.. _`Trac instance`: http://sourceforge.net/apps/trac/elftoolchain/report
|
||||
|
||||
|
||||
Additional Information
|
||||
----------------------
|
||||
|
||||
Additional information about the project may be found on the `project
|
||||
website`_.
|
||||
|
||||
.. _project website: http://elftoolchain.sourceforge.net/
|
||||
|
||||
.. $Id: README 2146 2011-11-11 09:39:00Z jkoshy $
|
||||
|
||||
.. Local Variables:
|
||||
.. mode: rst
|
||||
.. End:
|
206
RELEASE-NOTES
Normal file
206
RELEASE-NOTES
Normal file
|
@ -0,0 +1,206 @@
|
|||
.. $Id: RELEASE-NOTES 2599 2012-09-25 06:25:51Z jkoshy $
|
||||
|
||||
.. This file contains a template for use when writing release notes.
|
||||
.. It needs to be updated with release-specific content prior to
|
||||
.. cutting a release. RST comments (such as this one) also need to be
|
||||
.. removed prior to the release.
|
||||
|
||||
.. The tokens '%.*%' need be replaced with actual content.
|
||||
|
||||
Release Notes for Elftoolchain Software Version %.%.%
|
||||
=====================================================
|
||||
|
||||
About The Project
|
||||
-----------------
|
||||
|
||||
The `Elftoolchain project`_ develops BSD-licensed implementations of
|
||||
essential compilation tools and libraries for handling ELF based program
|
||||
objects.
|
||||
|
||||
About The Release
|
||||
-----------------
|
||||
|
||||
.. Describe the rationale for the release (e.g. new features,
|
||||
.. significant bug fixes, etc.).
|
||||
|
||||
Libraries and Utilities
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This release comprises the following libraries and utilities.
|
||||
|
||||
================= ==========================================
|
||||
**Name** **Description**
|
||||
================= ==========================================
|
||||
**ar** Archive manager.
|
||||
**addr2line** Debug tool.
|
||||
**brandelf** Manage the ELF brand on executables.
|
||||
**c++filt** Translate encoded symbols.
|
||||
**elfcopy** Copy and translate between object formats.
|
||||
**elfdump** Diagnostic tool.
|
||||
**findtextrel** Find undesired text relocations.
|
||||
**libdwarf** DWARF access library.
|
||||
**libelf** ELF access library.
|
||||
**mcs** Manage comment sections.
|
||||
**nm** List symbols in an ELF object.
|
||||
**ranlib** Add archive symbol tables to an archive.
|
||||
**readelf** Display ELF information.
|
||||
**size** List object sizes.
|
||||
**strings** Extract printable strings.
|
||||
**strip** Discard information from ELF objects.
|
||||
================= ==========================================
|
||||
|
||||
Documentation
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Each public API and invocable utility has a reference manual entry.
|
||||
We currently offer %NENTRIES% manual entries, documented in %NFILES%
|
||||
manual pages.
|
||||
|
||||
Additionally, this release contains the following documentation:
|
||||
|
||||
================= ==========================================
|
||||
**Name** **Description**
|
||||
================= ==========================================
|
||||
libelf-by-example A tutorial introduction to **libelf**.
|
||||
================= ==========================================
|
||||
|
||||
Test Suites
|
||||
~~~~~~~~~~~
|
||||
|
||||
The release contains the following test suites:
|
||||
|
||||
================= ==========================================
|
||||
**Name** **Description**
|
||||
================= ==========================================
|
||||
ar Test the **ar** utility.
|
||||
elfcopy Test the **elfcopy** utility.
|
||||
elfdump Test the **elfdump** utility.
|
||||
libdwarf Test the **libdwarf** library.
|
||||
libelf Test the **libelf** library.
|
||||
nm Test the **nm** utility.
|
||||
================= ==========================================
|
||||
|
||||
|
||||
System Requirements
|
||||
-------------------
|
||||
|
||||
.. Hardware and software requirements for using this software.
|
||||
|
||||
This software is designed to run on Unix(TM)-like operating systems
|
||||
such as the BSD-family of operating systems and GNU/Linux.
|
||||
|
||||
This release has been built and tested on the following operating
|
||||
systems:
|
||||
|
||||
==================== =========== ===========================
|
||||
**Operating System** **Version** **Supported Architectures**
|
||||
-------------------- ----------- ---------------------------
|
||||
`DragonFly BSD`_ 2.10.1 i386
|
||||
FreeBSD_ v8.2 amd64 & i386
|
||||
Minix_ 3.2.0 i386
|
||||
NetBSD_ v5.0.2 i386
|
||||
OpenBSD_ v5.0 i386
|
||||
Ubuntu_ GNU/Linux 10.04LTS i386 & x86_64
|
||||
==================== =========== ===========================
|
||||
|
||||
|
||||
Installation and Upgrades
|
||||
=========================
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Instructions for building and installing this software from source are
|
||||
described in the file "INSTALL".
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
|
||||
.. Special notes about upgrading this software from a prior release.
|
||||
.. For example, if we introduce any backwards-incompatible behaviour,
|
||||
.. or if we deprecate existing behaviour.
|
||||
|
||||
|
||||
Release Information
|
||||
===================
|
||||
|
||||
Changes in this release
|
||||
-----------------------
|
||||
|
||||
.. A list of significant changes in the release.
|
||||
|
||||
Outstanding Issues
|
||||
------------------
|
||||
|
||||
.. Problems discovered when testing the release.
|
||||
|
||||
Known Limitations
|
||||
-----------------
|
||||
|
||||
.. Known limitations.
|
||||
|
||||
Test Statistics
|
||||
---------------
|
||||
|
||||
The test summary for this release is presented below:
|
||||
|
||||
========= ========= ================ =============== ================ ===================
|
||||
**Suite** **Tests** **DragonFlyBSD** **FreeBSD** **NetBSD** **Ubuntu 10.04LTS**
|
||||
========= ========= ================ =============== ================ ===================
|
||||
ar
|
||||
elfcopy
|
||||
elfdump
|
||||
libdwarf
|
||||
libelf
|
||||
nm
|
||||
========= ========= ================ =============== ================ ===================
|
||||
|
||||
Key:
|
||||
|
||||
:P:
|
||||
Test successes.
|
||||
:F:
|
||||
Test failures.
|
||||
:U:
|
||||
Unresolved tests.
|
||||
|
||||
Notes
|
||||
~~~~~
|
||||
|
||||
More Information
|
||||
================
|
||||
|
||||
The project's website is at http://elftoolchain.sourceforge.net/.
|
||||
|
||||
Developer Community
|
||||
-------------------
|
||||
|
||||
The project's developers may be contacted using the mailing list:
|
||||
``<elftoolchain-developers@lists.sourceforge.net>``.
|
||||
|
||||
Reporting Bugs
|
||||
--------------
|
||||
|
||||
Please use our `Trac instance`_ for viewing existing bug reports and
|
||||
for submitting new bug reports.
|
||||
|
||||
|
||||
Copyright and License
|
||||
=====================
|
||||
|
||||
This software is copyright its authors, and is distributed under the
|
||||
`BSD License`_.
|
||||
|
||||
.. _BSD License: http://www.opensource.org/licenses/bsd-license.php
|
||||
.. _DragonFly BSD: http://www.dragonflybsd.org/
|
||||
.. _Elftoolchain project: http://elftoolchain.sourceforge.net/
|
||||
.. _FreeBSD: http://www.freebsd.org/
|
||||
.. _Minix: http://www.minix3.org/
|
||||
.. _NetBSD: http://www.netbsd.org/
|
||||
.. _OpenBSD: http://www.openbsd.org/
|
||||
.. _`Trac instance`: http://sourceforge.net/apps/trac/elftoolchain/report
|
||||
.. _Ubuntu: http://www.ubuntu.com/
|
||||
|
||||
.. Local Variables:
|
||||
.. mode: rst
|
||||
.. End:
|
15
addr2line/Makefile
Normal file
15
addr2line/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $Id: Makefile 2066 2011-10-26 15:40:28Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= addr2line
|
||||
SRCS= addr2line.c
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
DPADD= ${LIBELF} ${LIBELFTC} ${LIBDWARF}
|
||||
LDADD= -lelftc -ldwarf -lelf
|
||||
|
||||
MAN1= addr2line.1
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
159
addr2line/addr2line.1
Normal file
159
addr2line/addr2line.1
Normal file
|
@ -0,0 +1,159 @@
|
|||
.\" Copyright (c) 2009,2010 Joseph Koshy <jkoshy@users.sourceforge.net>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer
|
||||
.\" in this position and unchanged.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: addr2line.1 2066 2011-10-26 15:40:28Z jkoshy $
|
||||
.\"
|
||||
.Dd July 25, 2010
|
||||
.Os
|
||||
.Dt ADDR2LINE 1
|
||||
.Sh NAME
|
||||
.Nm addr2line
|
||||
.Nd translate program addresses to source file names and line numbers
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl b Ar target | Fl -target Ns = Ns Ar target
|
||||
.Op Fl e Ar pathname | Fl -exe Ns = Ns Ar pathname
|
||||
.Op Fl f | Fl -functions
|
||||
.Op Fl j Ar sectionname | Fl -section Ns = Ns Ar sectionname
|
||||
.Op Fl s | Fl -basename
|
||||
.Op Fl C | Fl -demangle
|
||||
.Op Fl H | Fl -help
|
||||
.Op Fl V | Fl -version
|
||||
.Op Ar hexaddress Ns ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility translates program addresses specified by the command line
|
||||
arguments
|
||||
.Ar hexaddress
|
||||
to their corresponding source file names and line numbers.
|
||||
If no arguments are given to
|
||||
.Nm ,
|
||||
it will read these addresses from standard input.
|
||||
.Pp
|
||||
Program addresses specified by arguments
|
||||
.Ar hexaddress
|
||||
are encoded using the conventions accepted by
|
||||
.Xr strtoull 3 .
|
||||
.Pp
|
||||
By default,
|
||||
.Nm
|
||||
will use the executable
|
||||
.Dq Pa a.out .
|
||||
The
|
||||
.Fl e
|
||||
option may be used to specified a different ELF object.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility recognizes the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl b Ar target | Fl -target Ns = Ns Ar target
|
||||
This option is recognized by
|
||||
.Nm
|
||||
but is ignored.
|
||||
It is supported for compatibility with GNU binutils.
|
||||
.It Fl e Ar pathname | Fl -exe Ns = Ns Ar pathname
|
||||
Use the ELF object specified by argument
|
||||
.Ar pathname
|
||||
to translate addresses.
|
||||
If this option is not specified,
|
||||
.Nm
|
||||
will use the file
|
||||
.Dq Pa a.out .
|
||||
.It Fl f | Fl -functions
|
||||
Display function names in addition to file and line number information.
|
||||
.It Fl j Ar sectionname | Fl -section Ns = Ns Ar sectionname
|
||||
The values specified by arguments
|
||||
.Ar hexaddress
|
||||
are to be treated as offsets into the section named
|
||||
.Ar sectionname .
|
||||
.It Fl s | -basename
|
||||
Display only the base name for each file name.
|
||||
.It Fl C | Fl -demangle
|
||||
Demangle C++ names.
|
||||
.It Fl H | Fl -help
|
||||
Print a help message.
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier and exit.
|
||||
.El
|
||||
.Sh OUTPUT FORMAT
|
||||
If the
|
||||
.Fl f
|
||||
option was not specified,
|
||||
.Nm
|
||||
will print the file name and line number for each address specified
|
||||
on a separate line.
|
||||
.Pp
|
||||
If the
|
||||
.Fl f
|
||||
option was specified,
|
||||
.Nm
|
||||
will print a line containing the name of the function corresponding
|
||||
to program address
|
||||
.Ar hexaddress ,
|
||||
followed by a line with the file name and line number.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility prints the file name and line number using the format
|
||||
.Dq FILENAME:LINENUMBER .
|
||||
.Pp
|
||||
If a file or function name could not be determined,
|
||||
.Nm
|
||||
will print a question mark in their place.
|
||||
If the line number could not be determined,
|
||||
.Nm
|
||||
will print a zero in its place.
|
||||
.Sh EXAMPLES
|
||||
To map address 080483c4 in the default executable
|
||||
.Pa a.out
|
||||
to a source file name and line number use:
|
||||
.D1 "% addr2line 080483c4"
|
||||
.Pp
|
||||
To map address 080483c4 in executable
|
||||
.Pa helloworld ,
|
||||
use:
|
||||
.D1 "% addr2line -e helloworld 080483c4"
|
||||
.Pp
|
||||
To have
|
||||
.Nm
|
||||
act as a filter reading addresses from its standard input use:
|
||||
.D1 "% addr2line"
|
||||
.Pp
|
||||
To print the function name corresponding to an address in addition to
|
||||
its source file and line number use:
|
||||
.D1 "% addr2line -f 080483c4"
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr nm 1 ,
|
||||
.Xr elfdump 1 ,
|
||||
.Xr elfcopy 1 ,
|
||||
.Xr strtoull 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
410
addr2line/addr2line.c
Normal file
410
addr2line/addr2line.c
Normal file
|
@ -0,0 +1,410 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <dwarf.h>
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h>
|
||||
#include <getopt.h>
|
||||
#include <libdwarf.h>
|
||||
#include <libelftc.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
ELFTC_VCSID("$Id: addr2line.c 2185 2011-11-19 16:07:16Z jkoshy $");
|
||||
|
||||
static struct option longopts[] = {
|
||||
{"target" , required_argument, NULL, 'b'},
|
||||
{"demangle", no_argument, NULL, 'C'},
|
||||
{"exe", required_argument, NULL, 'e'},
|
||||
{"functions", no_argument, NULL, 'f'},
|
||||
{"section", required_argument, NULL, 'j'},
|
||||
{"basename", no_argument, NULL, 's'},
|
||||
{"help", no_argument, NULL, 'H'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
static int demangle, func, base;
|
||||
static char unknown[] = { '?', '?', '\0' };
|
||||
static Dwarf_Addr section_base;
|
||||
|
||||
#define USAGE_MESSAGE "\
|
||||
Usage: %s [options] hexaddress...\n\
|
||||
Map program addresses to source file names and line numbers.\n\n\
|
||||
Options:\n\
|
||||
-b TGT | --target=TGT (Accepted but ignored).\n\
|
||||
-e EXE | --exec=EXE Use program \"EXE\" to translate addresses.\n\
|
||||
-f | --functions Display function names.\n\
|
||||
-j NAME | --section=NAME Values are offsets into section \"NAME\".\n\
|
||||
-s | --basename Only show the base name for each file name.\n\
|
||||
-C | --demangle Demangle C++ names.\n\
|
||||
-H | --help Print a help message.\n\
|
||||
-V | --version Print a version identifier and exit.\n"
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
version(void)
|
||||
{
|
||||
|
||||
fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
search_func(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Addr addr,
|
||||
const char **rlt_func)
|
||||
{
|
||||
Dwarf_Die ret_die, spec_die;
|
||||
Dwarf_Error de;
|
||||
Dwarf_Half tag;
|
||||
Dwarf_Unsigned lopc, hipc;
|
||||
Dwarf_Off ref;
|
||||
Dwarf_Attribute sub_at, spec_at;
|
||||
char *func0;
|
||||
int ret;
|
||||
|
||||
if (*rlt_func != NULL)
|
||||
return;
|
||||
|
||||
if (dwarf_tag(die, &tag, &de)) {
|
||||
warnx("dwarf_tag: %s", dwarf_errmsg(de));
|
||||
goto cont_search;
|
||||
}
|
||||
if (tag == DW_TAG_subprogram) {
|
||||
if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) ||
|
||||
dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de))
|
||||
goto cont_search;
|
||||
if (addr < lopc || addr >= hipc)
|
||||
goto cont_search;
|
||||
|
||||
/* Found it! */
|
||||
|
||||
*rlt_func = unknown;
|
||||
ret = dwarf_attr(die, DW_AT_name, &sub_at, &de);
|
||||
if (ret == DW_DLV_ERROR)
|
||||
return;
|
||||
if (ret == DW_DLV_OK) {
|
||||
if (dwarf_formstring(sub_at, &func0, &de))
|
||||
*rlt_func = unknown;
|
||||
else
|
||||
*rlt_func = func0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If DW_AT_name is not present, but DW_AT_specification is
|
||||
* present, then probably the actual name is in the DIE
|
||||
* referenced by DW_AT_specification.
|
||||
*/
|
||||
if (dwarf_attr(die, DW_AT_specification, &spec_at, &de))
|
||||
return;
|
||||
if (dwarf_global_formref(spec_at, &ref, &de))
|
||||
return;
|
||||
if (dwarf_offdie(dbg, ref, &spec_die, &de))
|
||||
return;
|
||||
if (dwarf_attrval_string(spec_die, DW_AT_name, rlt_func, &de))
|
||||
*rlt_func = unknown;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cont_search:
|
||||
|
||||
/* Search children. */
|
||||
ret = dwarf_child(die, &ret_die, &de);
|
||||
if (ret == DW_DLV_ERROR)
|
||||
errx(EXIT_FAILURE, "dwarf_child: %s", dwarf_errmsg(de));
|
||||
else if (ret == DW_DLV_OK)
|
||||
search_func(dbg, ret_die, addr, rlt_func);
|
||||
|
||||
/* Search sibling. */
|
||||
ret = dwarf_siblingof(dbg, die, &ret_die, &de);
|
||||
if (ret == DW_DLV_ERROR)
|
||||
errx(EXIT_FAILURE, "dwarf_siblingof: %s", dwarf_errmsg(de));
|
||||
else if (ret == DW_DLV_OK)
|
||||
search_func(dbg, ret_die, addr, rlt_func);
|
||||
}
|
||||
|
||||
static void
|
||||
translate(Dwarf_Debug dbg, const char* addrstr)
|
||||
{
|
||||
Dwarf_Die die;
|
||||
Dwarf_Line *lbuf;
|
||||
Dwarf_Error de;
|
||||
Dwarf_Half tag;
|
||||
Dwarf_Unsigned lopc, hipc, addr, lineno, plineno;
|
||||
Dwarf_Signed lcount;
|
||||
Dwarf_Addr lineaddr, plineaddr;
|
||||
const char *funcname;
|
||||
char *file, *file0, *pfile;
|
||||
char demangled[1024];
|
||||
int i, ret;
|
||||
|
||||
addr = strtoull(addrstr, NULL, 16);
|
||||
addr += section_base;
|
||||
lineno = 0;
|
||||
file = unknown;
|
||||
|
||||
while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
|
||||
&de)) == DW_DLV_OK) {
|
||||
die = NULL;
|
||||
while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
|
||||
if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
|
||||
warnx("dwarf_tag failed: %s",
|
||||
dwarf_errmsg(de));
|
||||
goto out;
|
||||
}
|
||||
/* XXX: What about DW_TAG_partial_unit? */
|
||||
if (tag == DW_TAG_compile_unit)
|
||||
break;
|
||||
}
|
||||
if (die == NULL) {
|
||||
warnx("could not find DW_TAG_compile_unit die");
|
||||
goto out;
|
||||
}
|
||||
if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) &&
|
||||
!dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) {
|
||||
/*
|
||||
* Check if the address falls into the PC range of
|
||||
* this CU.
|
||||
*/
|
||||
if (addr < lopc || addr >= hipc)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK) {
|
||||
warnx("dwarf_srclines: %s", dwarf_errmsg(de));
|
||||
goto out;
|
||||
}
|
||||
|
||||
plineaddr = ~0ULL;
|
||||
plineno = 0;
|
||||
pfile = unknown;
|
||||
for (i = 0; i < lcount; i++) {
|
||||
if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
|
||||
warnx("dwarf_lineaddr: %s",
|
||||
dwarf_errmsg(de));
|
||||
goto out;
|
||||
}
|
||||
if (dwarf_lineno(lbuf[i], &lineno, &de)) {
|
||||
warnx("dwarf_lineno: %s",
|
||||
dwarf_errmsg(de));
|
||||
goto out;
|
||||
}
|
||||
if (dwarf_linesrc(lbuf[i], &file0, &de)) {
|
||||
warnx("dwarf_linesrc: %s",
|
||||
dwarf_errmsg(de));
|
||||
} else
|
||||
file = file0;
|
||||
if (addr == lineaddr)
|
||||
goto out;
|
||||
else if (addr < lineaddr && addr > plineaddr) {
|
||||
lineno = plineno;
|
||||
file = pfile;
|
||||
goto out;
|
||||
}
|
||||
plineaddr = lineaddr;
|
||||
plineno = lineno;
|
||||
pfile = file;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
funcname = NULL;
|
||||
if (ret == DW_DLV_OK && func)
|
||||
search_func(dbg, die, addr, &funcname);
|
||||
|
||||
if (func) {
|
||||
if (funcname == NULL)
|
||||
funcname = unknown;
|
||||
if (demangle &&
|
||||
!elftc_demangle(funcname, demangled, sizeof(demangled), 0))
|
||||
printf("%s\n", demangled);
|
||||
else
|
||||
printf("%s\n", funcname);
|
||||
}
|
||||
|
||||
(void) printf("%s:%ju\n", base ? basename(file) : file, lineno);
|
||||
|
||||
/*
|
||||
* Reset internal CU pointer, so we will start from the first CU
|
||||
* next round.
|
||||
*/
|
||||
while (ret != DW_DLV_NO_ENTRY) {
|
||||
if (ret == DW_DLV_ERROR)
|
||||
errx(EXIT_FAILURE, "dwarf_next_cu_header: %s",
|
||||
dwarf_errmsg(de));
|
||||
ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
|
||||
&de);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_section_base(const char *exe, Elf *e, const char *section)
|
||||
{
|
||||
Dwarf_Addr off;
|
||||
Elf_Scn *scn;
|
||||
GElf_Ehdr eh;
|
||||
GElf_Shdr sh;
|
||||
size_t shstrndx;
|
||||
int elferr;
|
||||
const char *name;
|
||||
|
||||
if (gelf_getehdr(e, &eh) != &eh) {
|
||||
warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!elf_getshstrndx(e, &shstrndx)) {
|
||||
warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
(void) elf_errno();
|
||||
off = 0;
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
|
||||
goto next;
|
||||
if (!strcmp(section, name)) {
|
||||
if (eh.e_type == ET_EXEC || eh.e_type == ET_DYN) {
|
||||
/*
|
||||
* For executables, section base is the virtual
|
||||
* address of the specified section.
|
||||
*/
|
||||
section_base = sh.sh_addr;
|
||||
} else if (eh.e_type == ET_REL) {
|
||||
/*
|
||||
* For relocatables, section base is the
|
||||
* relative offset of the specified section
|
||||
* to the start of the first section.
|
||||
*/
|
||||
section_base = off;
|
||||
} else
|
||||
warnx("unknown e_type %u", eh.e_type);
|
||||
return;
|
||||
}
|
||||
next:
|
||||
off += sh.sh_size;
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||
|
||||
errx(EXIT_FAILURE, "%s: cannot find section %s", exe, section);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Elf *e;
|
||||
Dwarf_Debug dbg;
|
||||
Dwarf_Error de;
|
||||
const char *exe, *section;
|
||||
char line[1024];
|
||||
int fd, i, opt;
|
||||
|
||||
exe = NULL;
|
||||
section = NULL;
|
||||
while ((opt = getopt_long(argc, argv, "b:Ce:fj:sHV", longopts, NULL)) !=
|
||||
-1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
/* ignored */
|
||||
break;
|
||||
case 'C':
|
||||
demangle = 1;
|
||||
break;
|
||||
case 'e':
|
||||
exe = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
func = 1;
|
||||
break;
|
||||
case 'j':
|
||||
section = optarg;
|
||||
break;
|
||||
case 's':
|
||||
base = 1;
|
||||
break;
|
||||
case 'H':
|
||||
usage();
|
||||
case 'V':
|
||||
version();
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (exe == NULL)
|
||||
exe = "a.out";
|
||||
|
||||
if ((fd = open(exe, O_RDONLY)) < 0)
|
||||
err(EXIT_FAILURE, "%s", exe);
|
||||
|
||||
if (dwarf_init(fd, DW_DLC_READ, NULL, NULL, &dbg, &de))
|
||||
errx(EXIT_FAILURE, "dwarf_init: %s", dwarf_errmsg(de));
|
||||
|
||||
if (dwarf_get_elf(dbg, &e, &de) != DW_DLV_OK)
|
||||
errx(EXIT_FAILURE, "dwarf_get_elf: %s", dwarf_errmsg(de));
|
||||
|
||||
if (section)
|
||||
find_section_base(exe, e, section);
|
||||
else
|
||||
section_base = 0;
|
||||
|
||||
if (argc > 0)
|
||||
for (i = 0; i < argc; i++)
|
||||
translate(dbg, argv[i]);
|
||||
else
|
||||
while (fgets(line, sizeof(line), stdin) != NULL)
|
||||
translate(dbg, line);
|
||||
|
||||
dwarf_finish(dbg, &de);
|
||||
|
||||
(void) elf_end(e);
|
||||
|
||||
exit(0);
|
||||
}
|
35
ar/Makefile
Normal file
35
ar/Makefile
Normal file
|
@ -0,0 +1,35 @@
|
|||
# $Id: Makefile 2741 2012-12-10 18:47:00Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= ar
|
||||
SRCS= ar.c read.c util.c write.c
|
||||
LSRC= acplex.l
|
||||
YSRC= acpyacc.y
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
DPADD= ${LIBARCHIVE} ${LIBELFTC} ${LIBELF}
|
||||
LDADD= -larchive -lelftc -lelf
|
||||
|
||||
CFLAGS+=-I. -I${.CURDIR}
|
||||
|
||||
LINKS= ${BINDIR}/ar ${BINDIR}/ranlib
|
||||
|
||||
EXTRA_TARGETS= ranlib
|
||||
|
||||
CLEANFILES+= ${EXTRA_TARGETS}
|
||||
|
||||
MAN= ar.1 ranlib.1 ar.5
|
||||
|
||||
all: ${EXTRA_TARGETS}
|
||||
|
||||
${EXTRA_TARGETS}: ${PROG}
|
||||
ln -s ${PROG} ${.TARGET}
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
||||
|
||||
.if ${OS_HOST} == "OpenBSD"
|
||||
CFLAGS+= -I/usr/local/include
|
||||
LDFLAGS+= -L/usr/local/lib
|
||||
.endif
|
84
ar/acplex.l
Normal file
84
ar/acplex.l
Normal file
|
@ -0,0 +1,84 @@
|
|||
%{
|
||||
/*-
|
||||
* Copyright (c) 2008 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
ELFTC_VCSID("$Id: acplex.l 2130 2011-11-10 06:56:46Z jkoshy $");
|
||||
|
||||
#include "acpyacc.h"
|
||||
|
||||
#define YY_NO_UNPUT
|
||||
#if !defined(ELFTC_BROKEN_YY_NO_INPUT)
|
||||
#define YY_NO_INPUT
|
||||
#endif
|
||||
|
||||
int lineno = 1;
|
||||
|
||||
int yylex(void);
|
||||
|
||||
%}
|
||||
|
||||
%option noyywrap
|
||||
|
||||
%%
|
||||
|
||||
ADDLIB|addlib { return (ADDLIB); }
|
||||
ADDMOD|addmod { return (ADDMOD); }
|
||||
CLEAR|clear { return (CLEAR); }
|
||||
CREATE|create { return (CREATE); }
|
||||
DELETE|delete { return (DELETE); }
|
||||
DIRECTORY|directory { return (DIRECTORY); }
|
||||
END|end { return (END); }
|
||||
EXTRACT|extract { return (EXTRACT); }
|
||||
LIST|list { return (LIST); }
|
||||
OPEN|open { return (OPEN); }
|
||||
REPLACE|replace { return (REPLACE); }
|
||||
VERBOSE|verbose { return (VERBOSE); }
|
||||
SAVE|save { return (SAVE); }
|
||||
"(" { return (LP); }
|
||||
")" { return (RP); }
|
||||
"," { return (COMMA); }
|
||||
|
||||
[-_A-Za-z0-9/:$.\\]+ {
|
||||
yylval.str = strdup(yytext);
|
||||
if (yylval.str == NULL)
|
||||
err(EXIT_FAILURE, "strdup failed");
|
||||
return (FNAME);
|
||||
}
|
||||
|
||||
[ \t] /* whitespace */
|
||||
"*".* /* comment */
|
||||
";".* /* comment */
|
||||
"+\n" { lineno++; /* '+' is line continuation char */ }
|
||||
"\n" { lineno++; return (EOL); }
|
661
ar/acpyacc.y
Normal file
661
ar/acpyacc.y
Normal file
|
@ -0,0 +1,661 @@
|
|||
%{
|
||||
/*-
|
||||
* Copyright (c) 2008 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "libelftc.h"
|
||||
|
||||
#include "ar.h"
|
||||
|
||||
ELFTC_VCSID("$Id");
|
||||
|
||||
|
||||
#define TEMPLATE "arscp.XXXXXXXX"
|
||||
|
||||
struct list {
|
||||
char *str;
|
||||
struct list *next;
|
||||
};
|
||||
|
||||
|
||||
extern int yylex(void);
|
||||
extern int yyparse(void);
|
||||
|
||||
static void yyerror(const char *);
|
||||
static void arscp_addlib(char *archive, struct list *list);
|
||||
static void arscp_addmod(struct list *list);
|
||||
static void arscp_clear(void);
|
||||
static void arscp_create(char *in, char *out);
|
||||
static void arscp_delete(struct list *list);
|
||||
static void arscp_dir(char *archive, struct list *list, char *rlt);
|
||||
static void arscp_end(int eval);
|
||||
static void arscp_extract(struct list *list);
|
||||
static void arscp_free_argv(void);
|
||||
static void arscp_free_mlist(struct list *list);
|
||||
static void arscp_list(void);
|
||||
static struct list *arscp_mlist(struct list *list, char *str);
|
||||
static void arscp_mlist2argv(struct list *list);
|
||||
static int arscp_mlist_len(struct list *list);
|
||||
static void arscp_open(char *fname);
|
||||
static void arscp_prompt(void);
|
||||
static void arscp_replace(struct list *list);
|
||||
static void arscp_save(void);
|
||||
static int arscp_target_exist(void);
|
||||
|
||||
extern int lineno;
|
||||
|
||||
static struct bsdar *bsdar;
|
||||
static char *target;
|
||||
static char *tmpac;
|
||||
static int interactive;
|
||||
static int verbose;
|
||||
|
||||
%}
|
||||
|
||||
%token ADDLIB
|
||||
%token ADDMOD
|
||||
%token CLEAR
|
||||
%token CREATE
|
||||
%token DELETE
|
||||
%token DIRECTORY
|
||||
%token END
|
||||
%token EXTRACT
|
||||
%token LIST
|
||||
%token OPEN
|
||||
%token REPLACE
|
||||
%token VERBOSE
|
||||
%token SAVE
|
||||
%token LP
|
||||
%token RP
|
||||
%token COMMA
|
||||
%token EOL
|
||||
%token <str> FNAME
|
||||
%type <list> mod_list
|
||||
|
||||
%union {
|
||||
char *str;
|
||||
struct list *list;
|
||||
}
|
||||
|
||||
%%
|
||||
|
||||
begin
|
||||
: { arscp_prompt(); } ar_script
|
||||
;
|
||||
|
||||
ar_script
|
||||
: cmd_list
|
||||
|
|
||||
;
|
||||
|
||||
mod_list
|
||||
: FNAME { $$ = arscp_mlist(NULL, $1); }
|
||||
| mod_list separator FNAME { $$ = arscp_mlist($1, $3); }
|
||||
;
|
||||
|
||||
separator
|
||||
: COMMA
|
||||
|
|
||||
;
|
||||
|
||||
cmd_list
|
||||
: rawcmd
|
||||
| cmd_list rawcmd
|
||||
;
|
||||
|
||||
rawcmd
|
||||
: cmd EOL { arscp_prompt(); }
|
||||
;
|
||||
|
||||
cmd
|
||||
: addlib_cmd
|
||||
| addmod_cmd
|
||||
| clear_cmd
|
||||
| create_cmd
|
||||
| delete_cmd
|
||||
| directory_cmd
|
||||
| end_cmd
|
||||
| extract_cmd
|
||||
| list_cmd
|
||||
| open_cmd
|
||||
| replace_cmd
|
||||
| verbose_cmd
|
||||
| save_cmd
|
||||
| invalid_cmd
|
||||
| empty_cmd
|
||||
| error
|
||||
;
|
||||
|
||||
addlib_cmd
|
||||
: ADDLIB FNAME LP mod_list RP { arscp_addlib($2, $4); }
|
||||
| ADDLIB FNAME { arscp_addlib($2, NULL); }
|
||||
;
|
||||
|
||||
addmod_cmd
|
||||
: ADDMOD mod_list { arscp_addmod($2); }
|
||||
;
|
||||
|
||||
clear_cmd
|
||||
: CLEAR { arscp_clear(); }
|
||||
;
|
||||
|
||||
create_cmd
|
||||
: CREATE FNAME { arscp_create(NULL, $2); }
|
||||
;
|
||||
|
||||
delete_cmd
|
||||
: DELETE mod_list { arscp_delete($2); }
|
||||
;
|
||||
|
||||
directory_cmd
|
||||
: DIRECTORY FNAME { arscp_dir($2, NULL, NULL); }
|
||||
| DIRECTORY FNAME LP mod_list RP { arscp_dir($2, $4, NULL); }
|
||||
| DIRECTORY FNAME LP mod_list RP FNAME { arscp_dir($2, $4, $6); }
|
||||
;
|
||||
|
||||
end_cmd
|
||||
: END { arscp_end(EXIT_SUCCESS); }
|
||||
;
|
||||
|
||||
extract_cmd
|
||||
: EXTRACT mod_list { arscp_extract($2); }
|
||||
;
|
||||
|
||||
list_cmd
|
||||
: LIST { arscp_list(); }
|
||||
;
|
||||
|
||||
open_cmd
|
||||
: OPEN FNAME { arscp_open($2); }
|
||||
;
|
||||
|
||||
replace_cmd
|
||||
: REPLACE mod_list { arscp_replace($2); }
|
||||
;
|
||||
|
||||
save_cmd
|
||||
: SAVE { arscp_save(); }
|
||||
;
|
||||
|
||||
verbose_cmd
|
||||
: VERBOSE { verbose = !verbose; }
|
||||
;
|
||||
|
||||
empty_cmd
|
||||
:
|
||||
;
|
||||
|
||||
invalid_cmd
|
||||
: FNAME { yyerror(NULL); }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
yyerror(const char *s)
|
||||
{
|
||||
|
||||
(void) s;
|
||||
printf("Syntax error in archive script, line %d\n", lineno);
|
||||
}
|
||||
|
||||
/*
|
||||
* The arscp_open() function will first open an archive and check its
|
||||
* validity. If the archive format is valid, it will call
|
||||
* arscp_create() to create a temporary copy of the archive.
|
||||
*/
|
||||
static void
|
||||
arscp_open(char *fname)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
int r;
|
||||
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
bsdar_errc(bsdar, 0, "archive_read_new failed");
|
||||
archive_read_support_compression_none(a);
|
||||
archive_read_support_format_ar(a);
|
||||
AC(archive_read_open_file(a, fname, DEF_BLKSZ));
|
||||
if ((r = archive_read_next_header(a, &entry)))
|
||||
bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
|
||||
AC(archive_read_close(a));
|
||||
ACV(archive_read_finish(a));
|
||||
if (r != ARCHIVE_OK)
|
||||
return;
|
||||
arscp_create(fname, fname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an archive.
|
||||
*
|
||||
* If the parameter 'in' is NULL (the 'CREATE' command), a new empty
|
||||
* archive will be created. If the parameter 'in' is not NULL (the
|
||||
* 'OPEN' command), the resulting archive will be a modified version
|
||||
* of the existing archive.
|
||||
*/
|
||||
static void
|
||||
arscp_create(char *in, char *out)
|
||||
{
|
||||
struct archive *a;
|
||||
int ifd, ofd;
|
||||
|
||||
/* Delete the previously created temporary archive, if any. */
|
||||
if (tmpac) {
|
||||
if (unlink(tmpac) < 0)
|
||||
bsdar_errc(bsdar, errno, "unlink failed");
|
||||
free(tmpac);
|
||||
}
|
||||
|
||||
tmpac = strdup(TEMPLATE);
|
||||
if (tmpac == NULL)
|
||||
bsdar_errc(bsdar, errno, "strdup failed");
|
||||
if ((ofd = mkstemp(tmpac)) < 0)
|
||||
bsdar_errc(bsdar, errno, "mkstemp failed");
|
||||
|
||||
if (in) {
|
||||
/*
|
||||
* The 'OPEN' command creates a temporary copy of the
|
||||
* input archive.
|
||||
*/
|
||||
if ((ifd = open(in, O_RDONLY)) < 0 ||
|
||||
elftc_copyfile(ifd, ofd) < 0) {
|
||||
bsdar_warnc(bsdar, errno, "'OPEN' failed");
|
||||
(void) close(ofd);
|
||||
if (ifd != -1)
|
||||
(void) close(ifd);
|
||||
return;
|
||||
}
|
||||
(void) close(ifd);
|
||||
(void) close(ofd);
|
||||
} else {
|
||||
/*
|
||||
* The 'CREATE' command creates an "empty" archive (an
|
||||
* archive consisting only of the archive header).
|
||||
*/
|
||||
if ((a = archive_write_new()) == NULL)
|
||||
bsdar_errc(bsdar, 0, "archive_write_new failed");
|
||||
archive_write_set_format_ar_svr4(a);
|
||||
AC(archive_write_open_fd(a, ofd));
|
||||
AC(archive_write_close(a));
|
||||
ACV(archive_write_finish(a));
|
||||
}
|
||||
|
||||
/* Override the previous target, if any. */
|
||||
if (target)
|
||||
free(target);
|
||||
|
||||
target = out;
|
||||
bsdar->filename = tmpac;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add all modules of an archive to the current archive. If the
|
||||
* parameter 'list' is not NULL, only those modules specified by
|
||||
* 'list' will be added.
|
||||
*/
|
||||
static void
|
||||
arscp_addlib(char *archive, struct list *list)
|
||||
{
|
||||
|
||||
if (!arscp_target_exist())
|
||||
return;
|
||||
arscp_mlist2argv(list);
|
||||
bsdar->addlib = archive;
|
||||
ar_write_archive(bsdar, 'A');
|
||||
arscp_free_argv();
|
||||
arscp_free_mlist(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add modules to the current archive.
|
||||
*/
|
||||
static void
|
||||
arscp_addmod(struct list *list)
|
||||
{
|
||||
|
||||
if (!arscp_target_exist())
|
||||
return;
|
||||
arscp_mlist2argv(list);
|
||||
ar_write_archive(bsdar, 'q');
|
||||
arscp_free_argv();
|
||||
arscp_free_mlist(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete modules from the current archive.
|
||||
*/
|
||||
static void
|
||||
arscp_delete(struct list *list)
|
||||
{
|
||||
|
||||
if (!arscp_target_exist())
|
||||
return;
|
||||
arscp_mlist2argv(list);
|
||||
ar_write_archive(bsdar, 'd');
|
||||
arscp_free_argv();
|
||||
arscp_free_mlist(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract modules from the current archive.
|
||||
*/
|
||||
static void
|
||||
arscp_extract(struct list *list)
|
||||
{
|
||||
|
||||
if (!arscp_target_exist())
|
||||
return;
|
||||
arscp_mlist2argv(list);
|
||||
ar_read_archive(bsdar, 'x');
|
||||
arscp_free_argv();
|
||||
arscp_free_mlist(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* List the contents of an archive (simple mode).
|
||||
*/
|
||||
static void
|
||||
arscp_list(void)
|
||||
{
|
||||
|
||||
if (!arscp_target_exist())
|
||||
return;
|
||||
bsdar->argc = 0;
|
||||
bsdar->argv = NULL;
|
||||
/* Always verbose. */
|
||||
bsdar->options |= AR_V;
|
||||
ar_read_archive(bsdar, 't');
|
||||
bsdar->options &= ~AR_V;
|
||||
}
|
||||
|
||||
/*
|
||||
* List the contents of an archive (advanced mode).
|
||||
*/
|
||||
static void
|
||||
arscp_dir(char *archive, struct list *list, char *rlt)
|
||||
{
|
||||
FILE *out;
|
||||
|
||||
/* If rlt != NULL, redirect the output to it. */
|
||||
out = NULL;
|
||||
if (rlt) {
|
||||
out = bsdar->output;
|
||||
if ((bsdar->output = fopen(rlt, "w")) == NULL)
|
||||
bsdar_errc(bsdar, errno, "fopen %s failed", rlt);
|
||||
}
|
||||
|
||||
bsdar->filename = archive;
|
||||
if (list)
|
||||
arscp_mlist2argv(list);
|
||||
else {
|
||||
bsdar->argc = 0;
|
||||
bsdar->argv = NULL;
|
||||
}
|
||||
if (verbose)
|
||||
bsdar->options |= AR_V;
|
||||
ar_read_archive(bsdar, 't');
|
||||
bsdar->options &= ~AR_V;
|
||||
|
||||
if (rlt) {
|
||||
if (fclose(bsdar->output) == EOF)
|
||||
bsdar_errc(bsdar, errno, "fclose %s failed", rlt);
|
||||
bsdar->output = out;
|
||||
free(rlt);
|
||||
}
|
||||
free(archive);
|
||||
bsdar->filename = tmpac;
|
||||
arscp_free_argv();
|
||||
arscp_free_mlist(list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Replace modules in the current archive.
|
||||
*/
|
||||
static void
|
||||
arscp_replace(struct list *list)
|
||||
{
|
||||
|
||||
if (!arscp_target_exist())
|
||||
return;
|
||||
arscp_mlist2argv(list);
|
||||
ar_write_archive(bsdar, 'r');
|
||||
arscp_free_argv();
|
||||
arscp_free_mlist(list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename the temporary archive to the target archive.
|
||||
*/
|
||||
static void
|
||||
arscp_save(void)
|
||||
{
|
||||
mode_t mask;
|
||||
|
||||
if (target) {
|
||||
if (rename(tmpac, target) < 0)
|
||||
bsdar_errc(bsdar, errno, "rename failed");
|
||||
/*
|
||||
* Because mkstemp() creates temporary files with mode
|
||||
* 0600, we set target archive's mode as per the
|
||||
* process umask.
|
||||
*/
|
||||
mask = umask(0);
|
||||
umask(mask);
|
||||
if (chmod(target, 0666 & ~mask) < 0)
|
||||
bsdar_errc(bsdar, errno, "chmod failed");
|
||||
free(tmpac);
|
||||
free(target);
|
||||
tmpac = NULL;
|
||||
target= NULL;
|
||||
bsdar->filename = NULL;
|
||||
} else
|
||||
bsdar_warnc(bsdar, 0, "no open output archive");
|
||||
}
|
||||
|
||||
/*
|
||||
* Discard the contents of the current archive. This is achieved by
|
||||
* invoking the 'CREATE' cmd on the current archive.
|
||||
*/
|
||||
static void
|
||||
arscp_clear(void)
|
||||
{
|
||||
char *new_target;
|
||||
|
||||
if (target) {
|
||||
new_target = strdup(target);
|
||||
if (new_target == NULL)
|
||||
bsdar_errc(bsdar, errno, "strdup failed");
|
||||
arscp_create(NULL, new_target);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Quit ar(1). Note that the 'END' cmd will not 'SAVE' the current
|
||||
* archive before exiting.
|
||||
*/
|
||||
static void
|
||||
arscp_end(int eval)
|
||||
{
|
||||
|
||||
if (target)
|
||||
free(target);
|
||||
if (tmpac) {
|
||||
if (unlink(tmpac) == -1)
|
||||
bsdar_errc(bsdar, errno, "unlink %s failed", tmpac);
|
||||
free(tmpac);
|
||||
}
|
||||
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a target was specified, i.e, whether an 'OPEN' or 'CREATE'
|
||||
* had been issued by the user.
|
||||
*/
|
||||
static int
|
||||
arscp_target_exist(void)
|
||||
{
|
||||
|
||||
if (target)
|
||||
return (1);
|
||||
|
||||
bsdar_warnc(bsdar, 0, "no open output archive");
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct the list of modules.
|
||||
*/
|
||||
static struct list *
|
||||
arscp_mlist(struct list *list, char *str)
|
||||
{
|
||||
struct list *l;
|
||||
|
||||
l = malloc(sizeof(*l));
|
||||
if (l == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
l->str = str;
|
||||
l->next = list;
|
||||
|
||||
return (l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the length of an mlist.
|
||||
*/
|
||||
static int
|
||||
arscp_mlist_len(struct list *list)
|
||||
{
|
||||
int len;
|
||||
|
||||
for(len = 0; list; list = list->next)
|
||||
len++;
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the space allocated for a module list.
|
||||
*/
|
||||
static void
|
||||
arscp_free_mlist(struct list *list)
|
||||
{
|
||||
struct list *l;
|
||||
|
||||
/* Note: list->str was freed in arscp_free_argv(). */
|
||||
for(; list; list = l) {
|
||||
l = list->next;
|
||||
free(list);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a module list to an 'argv' array.
|
||||
*/
|
||||
static void
|
||||
arscp_mlist2argv(struct list *list)
|
||||
{
|
||||
char **argv;
|
||||
int i, n;
|
||||
|
||||
n = arscp_mlist_len(list);
|
||||
argv = malloc(n * sizeof(*argv));
|
||||
if (argv == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
|
||||
/* Note that module names are stored in reverse order. */
|
||||
for(i = n - 1; i >= 0; i--, list = list->next) {
|
||||
if (list == NULL)
|
||||
bsdar_errc(bsdar, errno, "invalid mlist");
|
||||
argv[i] = list->str;
|
||||
}
|
||||
|
||||
bsdar->argc = n;
|
||||
bsdar->argv = argv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the space allocated for an argv array and its elements.
|
||||
*/
|
||||
static void
|
||||
arscp_free_argv(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < bsdar->argc; i++)
|
||||
free(bsdar->argv[i]);
|
||||
|
||||
free(bsdar->argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Show a prompt if we are in interactive mode.
|
||||
*/
|
||||
static void
|
||||
arscp_prompt(void)
|
||||
{
|
||||
|
||||
if (interactive) {
|
||||
printf("AR >");
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The main function implementing script mode.
|
||||
*/
|
||||
void
|
||||
ar_mode_script(struct bsdar *ar)
|
||||
{
|
||||
|
||||
bsdar = ar;
|
||||
interactive = isatty(fileno(stdin));
|
||||
while(yyparse()) {
|
||||
if (!interactive)
|
||||
arscp_end(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Script ends without END */
|
||||
arscp_end(EXIT_SUCCESS);
|
||||
}
|
603
ar/ar.1
Normal file
603
ar/ar.1
Normal file
|
@ -0,0 +1,603 @@
|
|||
.\" Copyright (c) 2007,2009-2012 Joseph Koshy. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" This software is provided by Joseph Koshy ``as is'' and
|
||||
.\" any express or implied warranties, including, but not limited to, the
|
||||
.\" implied warranties of merchantability and fitness for a particular purpose
|
||||
.\" are disclaimed. in no event shall Joseph Koshy be liable
|
||||
.\" for any direct, indirect, incidental, special, exemplary, or consequential
|
||||
.\" damages (including, but not limited to, procurement of substitute goods
|
||||
.\" or services; loss of use, data, or profits; or business interruption)
|
||||
.\" however caused and on any theory of liability, whether in contract, strict
|
||||
.\" liability, or tort (including negligence or otherwise) arising in any way
|
||||
.\" out of the use of this software, even if advised of the possibility of
|
||||
.\" such damage.
|
||||
.\"
|
||||
.\" $Id: ar.1 2742 2012-12-10 18:47:36Z jkoshy $
|
||||
.\"
|
||||
.Dd December 10, 2012
|
||||
.Os
|
||||
.Dt AR 1
|
||||
.Sh NAME
|
||||
.Nm ar
|
||||
.Nd manage archives
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Fl d
|
||||
.Op Fl T
|
||||
.Op Fl f
|
||||
.Op Fl j
|
||||
.Op Fl v
|
||||
.Op Fl z
|
||||
.Ar archive
|
||||
.Ar
|
||||
.Nm
|
||||
.Fl m
|
||||
.Op Fl T
|
||||
.Op Fl a Ar position-after
|
||||
.Op Fl b Ar position-before
|
||||
.Op Fl f
|
||||
.Op Fl i Ar position-before
|
||||
.Op Fl j
|
||||
.Op Fl s | Fl S
|
||||
.Op Fl z
|
||||
.Ar archive
|
||||
.Ar
|
||||
.Nm
|
||||
.Fl p
|
||||
.Op Fl T
|
||||
.Op Fl f
|
||||
.Op Fl v
|
||||
.Ar archive
|
||||
.Op Ar
|
||||
.Nm
|
||||
.Fl q
|
||||
.Op Fl T
|
||||
.Op Fl c
|
||||
.Op Fl D
|
||||
.Op Fl f
|
||||
.Op Fl F Ar flavor | Fl -flavor Ar flavor
|
||||
.Op Fl s | Fl S
|
||||
.Op Fl v
|
||||
.Op Fl z
|
||||
.Ar archive
|
||||
.Ar
|
||||
.Nm
|
||||
.Fl r
|
||||
.Op Fl T
|
||||
.Op Fl a Ar position-after
|
||||
.Op Fl b Ar position-before
|
||||
.Op Fl c
|
||||
.Op Fl D
|
||||
.Op Fl f
|
||||
.Op Fl F Ar flavor | Fl -flavor Ar flavor
|
||||
.Op Fl i Ar position-before
|
||||
.Op Fl j
|
||||
.Op Fl s | Fl S
|
||||
.Op Fl u
|
||||
.Op Fl v
|
||||
.Op Fl z
|
||||
.Ar archive
|
||||
.Ar
|
||||
.Nm
|
||||
.Fl s
|
||||
.Op Fl D
|
||||
.Op Fl j
|
||||
.Op Fl z
|
||||
.Ar archive
|
||||
.Nm
|
||||
.Fl t
|
||||
.Op Fl f
|
||||
.Op Fl T
|
||||
.Op Fl v
|
||||
.Ar archive
|
||||
.Op Ar
|
||||
.Nm
|
||||
.Fl x
|
||||
.Op Fl C
|
||||
.Op Fl T
|
||||
.Op Fl f
|
||||
.Op Fl o
|
||||
.Op Fl u
|
||||
.Op Fl v
|
||||
.Ar archive
|
||||
.Op Ar
|
||||
.Nm
|
||||
.Fl M
|
||||
.Nm
|
||||
.Fl V
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility creates and maintains groups of files combined into an
|
||||
archive.
|
||||
Once an archive has been created, new files can be added to it, and
|
||||
existing files can be extracted, deleted or replaced.
|
||||
.Pp
|
||||
Files are named in the archive by their last file name component,
|
||||
so if a file referenced by a path containing a
|
||||
.Dq /
|
||||
is archived, it will be named by the last component of the path.
|
||||
Similarly when matching paths listed on the command line against
|
||||
file names stored in the archive, only the last component of the
|
||||
path will be compared.
|
||||
.Pp
|
||||
The normal use of
|
||||
.Nm
|
||||
is for the creation and maintenance of libraries suitable for use
|
||||
with the link editor
|
||||
.Xr ld 1 ,
|
||||
although it is not restricted to this purpose.
|
||||
The
|
||||
.Nm
|
||||
utility can create and manage an archive symbol table (see
|
||||
.Xr ar 5 )
|
||||
used to speed up link editing operations.
|
||||
If a symbol table is present in an archive, it will be
|
||||
kept up-to-date by subsequent operations on the archive.
|
||||
.Sh OPTIONS
|
||||
The
|
||||
.Nm
|
||||
utility supports the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a Ar member-after
|
||||
When used with option
|
||||
.Fl m
|
||||
this option specifies that the archive members specified by
|
||||
arguments
|
||||
.Ar
|
||||
are moved to after the archive member named by argument
|
||||
.Ar member-after .
|
||||
When used with option
|
||||
.Fl r
|
||||
this option specifies that the files specified by arguments
|
||||
.Ar
|
||||
are added after the archive member named by argument
|
||||
.Ar member-after .
|
||||
.It Fl b Ar member-before
|
||||
When used with option
|
||||
.Fl m
|
||||
this option specifies that the archive members specified by
|
||||
arguments
|
||||
.Ar
|
||||
are moved to before the archive member named by argument
|
||||
.Ar member-before .
|
||||
When used with option
|
||||
.Fl r
|
||||
this option specifies that the files specified by arguments
|
||||
.Ar
|
||||
are added before the archive member named by argument
|
||||
.Ar member-before .
|
||||
.It Fl c
|
||||
Suppress the informational message printed when a new archive is
|
||||
created using the
|
||||
.Fl r
|
||||
and
|
||||
.Fl q
|
||||
options.
|
||||
.It Fl C
|
||||
Prevent extracted files from replacing like-named files
|
||||
in the file system.
|
||||
.It Fl d
|
||||
Delete the members named by arguments
|
||||
.Ar
|
||||
from the archive specified by argument
|
||||
.Ar archive .
|
||||
The archive's symbol table, if present, is updated to reflect
|
||||
the new contents of the archive.
|
||||
.It Fl D
|
||||
When used in combination with the
|
||||
.Fl r
|
||||
or
|
||||
.Fl q
|
||||
option, insert 0's instead of the real mtime, uid and gid values
|
||||
and 0644 instead of file mode from the members named by arguments
|
||||
.Ar .
|
||||
This ensures that checksums on the resulting archives are reproducible
|
||||
when member contents are identical.
|
||||
.It Fl f
|
||||
Synonymous with option
|
||||
.Fl T .
|
||||
.It Fl F Ar flavor | Fl -flavor Ar flavor
|
||||
Create archives with the specified archive format.
|
||||
Legal values for argument
|
||||
.Ar flavor
|
||||
are:
|
||||
.Bl -tag -width indent -compact
|
||||
.It Ar bsd
|
||||
Create BSD format archives.
|
||||
.It Ar gnu
|
||||
An alias for
|
||||
.Ar svr4 .
|
||||
.It Ar svr4
|
||||
Create SVR4 format archives.
|
||||
.El
|
||||
If this option is not specified,
|
||||
.Nm
|
||||
will create archives using the SVR4 format.
|
||||
.It Fl i Ar member-before
|
||||
Synonymous with option
|
||||
.Fl b .
|
||||
.It Fl j
|
||||
This option is accepted for compatibility with the
|
||||
.Tn FreeBSD
|
||||
version of the
|
||||
.Nm
|
||||
utility, but is ignored.
|
||||
.It Fl l
|
||||
This option is accepted for compatibility with GNU
|
||||
.Xr ar 1 ,
|
||||
but is ignored.
|
||||
.It Fl m
|
||||
Move archive members specified by arguments
|
||||
.Ar
|
||||
within the archive.
|
||||
If a position has been specified by one of the
|
||||
.Fl a ,
|
||||
.Fl b
|
||||
or
|
||||
.Fl i
|
||||
options, the members are moved to before or after the specified
|
||||
position.
|
||||
If no position has been specified, the specified members are moved
|
||||
to the end of the archive.
|
||||
If the archive has a symbol table, it is updated to reflect the
|
||||
new contents of the archive.
|
||||
.It Fl M
|
||||
Read and execute MRI librarian commands from standard input.
|
||||
The commands understood by the
|
||||
.Nm
|
||||
utility are described in the section
|
||||
.Sx "MRI Librarian Commands" .
|
||||
.It Fl o
|
||||
Preserve the original modification times of members when extracting
|
||||
them.
|
||||
.It Fl p
|
||||
Write the contents of the specified archive members named by
|
||||
arguments
|
||||
.Ar
|
||||
to standard output.
|
||||
If no members were specified, the contents of all the files in the
|
||||
archive are written in the order they appear in the archive.
|
||||
.It Fl q
|
||||
Append the files specified by arguments
|
||||
.Ar
|
||||
to the archive specified by argument
|
||||
.Ar archive
|
||||
without checking if the files already exist in the archive.
|
||||
The archive symbol table will be updated as needed.
|
||||
If the file specified by the argument
|
||||
.Ar archive
|
||||
does not already exist, a new archive will be created.
|
||||
.It Fl r
|
||||
Replace (add) the files specified by arguments
|
||||
.Ar
|
||||
in the archive specified by argument
|
||||
.Ar archive ,
|
||||
creating the archive if necessary.
|
||||
Replacing existing members will not change the order of members within
|
||||
the archive.
|
||||
If a file named in arguments
|
||||
.Ar
|
||||
does not exist, existing members in the archive that match that
|
||||
name are not changed.
|
||||
New files are added to the end of the archive unless one of the
|
||||
positioning options
|
||||
.Fl a ,
|
||||
.Fl b
|
||||
or
|
||||
.Fl i
|
||||
is specified.
|
||||
The archive symbol table, if it exists, is updated to reflect the
|
||||
new state of the archive.
|
||||
.It Fl s
|
||||
Add an archive symbol table (see
|
||||
.Xr ar 5 )
|
||||
to the archive specified by argument
|
||||
.Ar archive .
|
||||
Invoking
|
||||
.Nm
|
||||
with the
|
||||
.Fl s
|
||||
option alone is equivalent to invoking
|
||||
.Xr ranlib 1 .
|
||||
.It Fl S
|
||||
Do not generate an archive symbol table.
|
||||
.It Fl t
|
||||
For
|
||||
.Nm ,
|
||||
list the files specified by arguments
|
||||
.Ar
|
||||
in the order in which they appear in the archive, one per line.
|
||||
If no files are specified, all files in the archive are listed.
|
||||
.It Fl T
|
||||
Use only the first fifteen characters of the archive member name or
|
||||
command line file name argument when naming archive members.
|
||||
.It Fl u
|
||||
Conditionally update the archive or extract members.
|
||||
When used with the
|
||||
.Fl r
|
||||
option, files named by arguments
|
||||
.Ar
|
||||
will be replaced in the archive if they are newer than their
|
||||
archived versions.
|
||||
When used with the
|
||||
.Fl x
|
||||
option, the members specified by arguments
|
||||
.Ar
|
||||
will be extracted only if they are newer than the corresponding
|
||||
files in the file system.
|
||||
.It Fl v
|
||||
Provide verbose output.
|
||||
When used with the
|
||||
.Fl d ,
|
||||
.Fl m ,
|
||||
.Fl q
|
||||
or
|
||||
.Fl x
|
||||
options,
|
||||
.Nm
|
||||
gives a file-by-file description of the archive modification being
|
||||
performed, which consists of three white-space seperated fields:
|
||||
the option letter, a dash
|
||||
.Dq "-" ,
|
||||
and the file name.
|
||||
When used with the
|
||||
.Fl r
|
||||
option,
|
||||
.Nm
|
||||
displays the description as above, but the initial letter is an
|
||||
.Dq a
|
||||
if the file is added to the archive, or an
|
||||
.Dq r
|
||||
if the file replaces a file already in the archive.
|
||||
When used with the
|
||||
.Fl p
|
||||
option, the name of the file enclosed in
|
||||
.Dq <
|
||||
and
|
||||
.Dq >
|
||||
characters is written to standard output preceded by a single newline
|
||||
character and followed by two newline characters.
|
||||
The contents of the named file follow the file name.
|
||||
When used with the
|
||||
.Fl t
|
||||
option,
|
||||
.Nm
|
||||
displays eight whitespace separated fields:
|
||||
the file permissions as displayed by
|
||||
.Xr strmode 3 ,
|
||||
decimal user and group IDs separated by a slash (
|
||||
.Dq / Ns ) ,
|
||||
the file size in bytes, the file modification time in
|
||||
.Xr strftime 3
|
||||
format
|
||||
.Dq "%b %e %H:%M %Y" ,
|
||||
and the name of the file.
|
||||
.It Fl V
|
||||
Print a version identifier and exit.
|
||||
.It Fl x
|
||||
Extract archive members specified by arguments
|
||||
.Ar
|
||||
into the current directory.
|
||||
If no members have been specified, extract all members of the archive.
|
||||
If the file corresponding to an extracted member does not exist it
|
||||
will be created.
|
||||
If the file corresponding to an extracted member does exist, its owner
|
||||
and group will not be changed while its contents will be overwritten
|
||||
and its permissions will set to that entered in the archive.
|
||||
The file's access and modification time would be that of the time
|
||||
of extraction unless the
|
||||
.Fl o
|
||||
option was specified.
|
||||
.It Fl z
|
||||
This option is accepted for compatibility with the
|
||||
.Tn FreeBSD
|
||||
version of the
|
||||
.Nm
|
||||
utility, but is ignored.
|
||||
.El
|
||||
.Ss "MRI Librarian Commands"
|
||||
If the
|
||||
.Fl M
|
||||
option is specified, the
|
||||
.Nm
|
||||
utility will read and execute commands from its standard input.
|
||||
If standard input is a terminal, the
|
||||
.Nm
|
||||
utility will display the prompt
|
||||
.Dq Li "AR >"
|
||||
before reading a line, and will continue operation even if errors are
|
||||
encountered.
|
||||
If standard input is not a terminal, the
|
||||
.Nm
|
||||
utility will not display a prompt and will terminate execution on
|
||||
encountering an error.
|
||||
.Pp
|
||||
Each input line contains a single command.
|
||||
Words in an input line are separated by whitespace characters.
|
||||
The first word of the line is the command, the remaining words are
|
||||
the arguments to the command.
|
||||
The command word may be specified in either case.
|
||||
Arguments may be separated by commas or blanks.
|
||||
.Pp
|
||||
Empty lines are allowed and are ignored.
|
||||
Long lines are continued by ending them with the
|
||||
.Dq Li +
|
||||
character.
|
||||
.Pp
|
||||
The
|
||||
.Dq Li *
|
||||
and
|
||||
.Dq Li "\;"
|
||||
characters start a comment.
|
||||
Comments extend till the end of the line.
|
||||
.Pp
|
||||
When executing an MRI librarian script the
|
||||
.Nm
|
||||
utility works on a temporary copy of an archive.
|
||||
Changes to the copy are made permanent using the
|
||||
.Ic save
|
||||
command.
|
||||
.Pp
|
||||
Commands understood by the
|
||||
.Nm
|
||||
utility are:
|
||||
.Bl -tag -width indent
|
||||
.It Ic addlib Ar archive | Ic addlib Ar archive Pq Ar member Oo Li , Ar member Oc Ns ...
|
||||
Add the contents of the archive named by argument
|
||||
.Ar archive
|
||||
to the current archive.
|
||||
If specific members are named using the arguments
|
||||
.Ar member ,
|
||||
then those members are added to the current archive.
|
||||
If no members are specified, the entire contents of the archive
|
||||
are added to the current archive.
|
||||
.It Ic addmod Ar member Oo Li , Ar member Oc Ns ...
|
||||
Add the files named by arguments
|
||||
.Ar member
|
||||
to the current archive.
|
||||
.It Ic clear
|
||||
Discard all the contents of the current archive.
|
||||
.It Ic create Ar archive
|
||||
Create a new archive named by the argument
|
||||
.Ar archive ,
|
||||
and makes it the current archive.
|
||||
If the named archive already exists, it will be overwritten
|
||||
when the
|
||||
.Ic save
|
||||
command is issued.
|
||||
.It Ic delete Ar module Oo Li , Ar member Oc Ns ...
|
||||
Delete the modules named by the arguments
|
||||
.Ar member
|
||||
from the current archive.
|
||||
.It Ic directory Ar archive Po Ar member Oo Li , Ar member Oc Ns ... Pc Op Ar outputfile
|
||||
List each named module in the archive.
|
||||
The format of the output depends on the verbosity setting set using
|
||||
the
|
||||
.Ic verbose
|
||||
command.
|
||||
Output is sent to standard output, or to the file specified by
|
||||
argument
|
||||
.Ar outputfile .
|
||||
.It Ic end
|
||||
Exit successfully from the
|
||||
.Nm
|
||||
utility.
|
||||
Any unsaved changes to the current archive will be discarded.
|
||||
.It Ic extract Ar member Oo Li , Ar member Oc Ns ...
|
||||
Extract the members named by the arguments
|
||||
.Ar member
|
||||
from the current archive.
|
||||
.It Ic list
|
||||
Display the contents of the current archive in verbose style.
|
||||
.It Ic open Ar archive
|
||||
Open the archive named by argument
|
||||
.Ar archive
|
||||
and make it the current archive.
|
||||
.It Ic replace Ar member Oo Li , Ar member Oc Ns ...
|
||||
Replace named members in the current archive with the files specified
|
||||
by arguments
|
||||
.Ar member .
|
||||
The files must be present in the current directory and the named
|
||||
modules must already exist in the current archive.
|
||||
.It Ic save
|
||||
Commit all changes to the current archive.
|
||||
.It Ic verbose
|
||||
Toggle the verbosity of the
|
||||
.Ic directory
|
||||
command.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
To create a new archive
|
||||
.Pa ex.a
|
||||
containing three files
|
||||
.Pa ex1.o ,
|
||||
.Pa ex2.o
|
||||
and
|
||||
.Pa ex3.o ,
|
||||
use:
|
||||
.Dl "ar -rc ex.a ex1.o ex2.o ex3.o"
|
||||
.Pp
|
||||
To add an archive symbol table to an existing archive
|
||||
.Pa ex.a ,
|
||||
use:
|
||||
.Dl "ar -s ex.a"
|
||||
.Pp
|
||||
To delete file
|
||||
.Pa ex1.o
|
||||
from archive
|
||||
.Pa ex.a ,
|
||||
use:
|
||||
.D1 "ar -d ex.a ex1.o"
|
||||
.Pp
|
||||
To verbosely list the contents of archive
|
||||
.Pa ex.a ,
|
||||
use:
|
||||
.D1 "ar -tv ex.a"
|
||||
.Pp
|
||||
To create a new archive
|
||||
.Pa ex.a
|
||||
containing the files
|
||||
.Pa ex1.o ,
|
||||
and
|
||||
.Pa ex2.o ,
|
||||
using MRI librarian commands, use the following script:
|
||||
.Bd -literal -offset indent
|
||||
create ex.a * specify the output archive
|
||||
addmod ex1.o ex2.o * add modules
|
||||
save * save pending changes
|
||||
end * exit the utility
|
||||
.Ed
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr ld 1 ,
|
||||
.Xr ranlib 1 ,
|
||||
.Xr archive 3 ,
|
||||
.Xr elf 3 ,
|
||||
.Xr strftime 3 ,
|
||||
.Xr strmode 3 ,
|
||||
.Xr ar 5
|
||||
.Sh STANDARDS COMPLIANCE
|
||||
The
|
||||
.Nm
|
||||
utility's support for the
|
||||
.Fl a ,
|
||||
.Fl b ,
|
||||
.Fl c ,
|
||||
.Fl i ,
|
||||
.Fl m ,
|
||||
.Fl p ,
|
||||
.Fl q ,
|
||||
.Fl r ,
|
||||
.Fl s ,
|
||||
.Fl t ,
|
||||
.Fl u ,
|
||||
.Fl v ,
|
||||
.Fl C
|
||||
and
|
||||
.Fl T
|
||||
options is believed to be compliant with
|
||||
.St -p1003.2 .
|
||||
.Sh HISTORY
|
||||
An
|
||||
.Nm
|
||||
command first appeared in AT&T UNIX Version 1.
|
||||
In
|
||||
.Fx 8.0 ,
|
||||
.An "Kai Wang" Aq kaiw@FreeBSD.org
|
||||
reimplemented
|
||||
.Nm
|
||||
using the
|
||||
.Lb libarchive
|
||||
and the
|
||||
.Lb libelf .
|
327
ar/ar.5
Normal file
327
ar/ar.5
Normal file
|
@ -0,0 +1,327 @@
|
|||
.\" Copyright (c) 2010 Joseph Koshy. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: ar.5 2066 2011-10-26 15:40:28Z jkoshy $
|
||||
.\"
|
||||
.Dd November 28, 2010
|
||||
.Os
|
||||
.Dt AR 5
|
||||
.Sh NAME
|
||||
.Nm ar
|
||||
.Nd archive file format for
|
||||
.Xr ar 1
|
||||
and
|
||||
.Xr ranlib 1
|
||||
.Sh SYNOPSIS
|
||||
.In ar.h
|
||||
.Sh DESCRIPTION
|
||||
.Xr ar 1
|
||||
archives are created and managed by the
|
||||
.Xr ar 1
|
||||
and
|
||||
.Xr ranlib 1
|
||||
utilities.
|
||||
These archives are typically used during program development to
|
||||
hold libraries of program objects.
|
||||
An
|
||||
.Xr ar 1
|
||||
archive is contained in a single operating system file.
|
||||
.Pp
|
||||
This manual page documents two variants of the
|
||||
.Xr ar 1
|
||||
archive format: the BSD archive format, and the SVR4/GNU archive
|
||||
format.
|
||||
.Pp
|
||||
In both variants the archive file starts with an identifying byte
|
||||
sequence of the seven ASCII characters
|
||||
.Sq Li "!<arch>"
|
||||
followed by a ASCII linefeed character
|
||||
.Po
|
||||
see the constant
|
||||
.Dq ARMAG
|
||||
in the header file
|
||||
.In ar.h
|
||||
.Pc .
|
||||
.Pp
|
||||
Archive members follow the initial identifying byte sequence.
|
||||
Each archive member is prefixed by a fixed size header describing the
|
||||
file attributes associated with the member.
|
||||
.Ss "Archive Headers"
|
||||
An archive header describes the file attributes for the archive member that
|
||||
follows it.
|
||||
The
|
||||
.Xr ar 5
|
||||
format only supports a limited number of attributes: the file name,
|
||||
the file creation time stamp, the uid and gid of the creator, the file
|
||||
mode and the file size.
|
||||
.Pp
|
||||
Archive headers are placed at an even byte offset in the archive file.
|
||||
If the data for an archive member ends at an odd byte offset, then a
|
||||
padding byte with value 0x0A is used to position the next archive
|
||||
header on an even byte offset.
|
||||
.Pp
|
||||
An archive header comprises the following fixed sized fields:
|
||||
.Bl -tag -width "Li ar_name"
|
||||
.It Ar ar_name
|
||||
(16 bytes) The file name of the archive member.
|
||||
The format of this field varies between the BSD and SVR4/GNU formats and
|
||||
is described in more detail in the section
|
||||
.Sx "Representing File Names"
|
||||
below.
|
||||
.It Ar ar_date
|
||||
(12 bytes) The file modification time for the member in seconds since the
|
||||
epoch, encoded as a decimal number.
|
||||
.It Ar ar_uid
|
||||
(6 bytes) The uid associated with the archive member, encoded as a
|
||||
decimal number.
|
||||
.It Ar ar_gid
|
||||
(6 bytes) The gid associated with the archive member, encoded as a
|
||||
decimal number.
|
||||
.It Ar ar_mode
|
||||
(8 bytes) The file mode for the archive member, encoded as an octal
|
||||
number.
|
||||
.It Ar ar_size
|
||||
(10 bytes) In the SVR4/GNU archive format this field holds the size in
|
||||
bytes of the archive member, encoded as a decimal number.
|
||||
In the BSD archive format, for short file names, this field
|
||||
holds the size in bytes of the archive member, encoded as a decimal
|
||||
number.
|
||||
For long file names
|
||||
.Po
|
||||
see
|
||||
.Sx "Representing File Names"
|
||||
below
|
||||
.Pc ,
|
||||
the field contains the combined size of the
|
||||
archive member and its file name, encoded as a decimal number.
|
||||
.It Ar ar_fmag
|
||||
(2 bytes) This field holds 2 bytes with values 0x96 and 0x0A
|
||||
respectively, marking the end of the header.
|
||||
.El
|
||||
.Pp
|
||||
Unused bytes in the fields of an archive header are set to the value
|
||||
0x20.
|
||||
.Ss "Representing File Names"
|
||||
The BSD and SVR4/GNU variants use different schemes for encoding file
|
||||
names for members.
|
||||
.Bl -tag -width "SVR4/GNU"
|
||||
.It "BSD"
|
||||
File names that are upto 16 bytes long and which do not contain
|
||||
embedded spaces are stored directly in the
|
||||
.Ar ar_name
|
||||
field of the archive header.
|
||||
File names that are either longer than 16 bytes or which contain
|
||||
embedded spaces are stored immediately after the archive header
|
||||
and the
|
||||
.Ar ar_name
|
||||
field of the archive header is set to the string
|
||||
.Dq "#1/"
|
||||
followed by a decimal representation of the number of bytes needed for
|
||||
the file name.
|
||||
In addition, the
|
||||
.Ar ar_size
|
||||
field of the archive header is set to the decimal representation of
|
||||
the combined sizes of the archive member and the file name.
|
||||
The file contents of the member follows the file name without further
|
||||
padding.
|
||||
.Pp
|
||||
As an example, if the file name for a member was
|
||||
.Dq "A B"
|
||||
and its contents was the string
|
||||
.Dq "C D" ,
|
||||
then the
|
||||
.Ar ar_name
|
||||
field of the header would contain
|
||||
.Dq Li "#1/3" ,
|
||||
the
|
||||
.Ar ar_size
|
||||
field of the header would contain
|
||||
.Dq Li 6 ,
|
||||
and the bytes immediately following the header would be 0x41, 0x20,
|
||||
0x42, 0x43, 0x20 and 0x44
|
||||
.Po
|
||||
ASCII
|
||||
.Dq "A BC D"
|
||||
.Pc .
|
||||
.It "SVR4/GNU"
|
||||
File names that are upto 15 characters long are stored directly in the
|
||||
.Ar ar_name
|
||||
field of the header, terminated by a
|
||||
.Dq Li /
|
||||
character.
|
||||
.Pp
|
||||
If the file name is larger than would fit in space for the
|
||||
.Ar ar_name
|
||||
field, then the actual file name is kept in the archive
|
||||
string table
|
||||
.Po
|
||||
see
|
||||
.Sx "Archive String Tables"
|
||||
below
|
||||
.Pc ,
|
||||
and the decimal offset of the file name in the string table is stored
|
||||
in the
|
||||
.Ar ar_name
|
||||
field, prefixed by a
|
||||
.Dq Li /
|
||||
character.
|
||||
.Pp
|
||||
As an example, if the real file name has been stored at offset 768 in
|
||||
the archive string table, the
|
||||
.Ar ar_name
|
||||
field of the header will contain the string
|
||||
.Dq /768 .
|
||||
.El
|
||||
.Ss "Special Archive Members"
|
||||
The following archive members are special.
|
||||
.Bl -tag -width indent
|
||||
.It Dq Li /
|
||||
In the SVR4/GNU variant of the archive format, the archive member with
|
||||
name
|
||||
.Dq Li /
|
||||
denotes an archive symbol table.
|
||||
If present, this member will be the very first member in the
|
||||
archive.
|
||||
.It Dq Li //
|
||||
In the SVR4/GNU variant of the archive format, the archive member with
|
||||
name
|
||||
.Dq Li //
|
||||
denotes the archive string table.
|
||||
This special member is used to hold filenames that do not fit in the
|
||||
file name field of the header
|
||||
.Po
|
||||
see
|
||||
.Sx "Representing File Names"
|
||||
above
|
||||
.Pc .
|
||||
If present, this member immediately follows the archive symbol table
|
||||
if an archive symbol table is present, or is the first member otherwise.
|
||||
.It Dq Li "__.SYMDEF"
|
||||
This special member contains the archive symbol table in the BSD
|
||||
variant of the archive format.
|
||||
If present, this member will be the very first member in the
|
||||
archive.
|
||||
.El
|
||||
.Ss "Archive String Tables"
|
||||
An archive string table is used in the SVR4/GNU archive format to hold
|
||||
file names that are too large to fit into the constraints of the
|
||||
.Ar ar_name
|
||||
field of the archive header.
|
||||
An archive string table contains a sequence of file names.
|
||||
Each file name in the archive string table is terminated by the
|
||||
byte sequence 0x2F, 0x0A
|
||||
.Po
|
||||
the ASCII string
|
||||
.Dq "/\en"
|
||||
.Pc .
|
||||
No padding is used to separate adjacent file names.
|
||||
.Ss "Archive Symbol Tables"
|
||||
Archive symbol tables are used to speed up link editing by providing a
|
||||
mapping between the program symbols defined in the archive
|
||||
and the corresponding archive members.
|
||||
Archive symbol tables are managed by the
|
||||
.Xr ranlib 1
|
||||
utility.
|
||||
.Pp
|
||||
The format of archive symbol tables is as follows:
|
||||
.Bl -tag -width "SVR4/GNU"
|
||||
.It BSD
|
||||
In the BSD archive format, the archive symbol table comprises
|
||||
of two parts: a part containing an array of
|
||||
.Vt "struct ranlib"
|
||||
descriptors, followed by a part containing a symbol string table.
|
||||
The sizes and layout of the structures that make up a BSD format
|
||||
archive symbol table are machine dependent.
|
||||
.Pp
|
||||
The part containing
|
||||
.Vt "struct ranlib"
|
||||
descriptors begins with a field containing the size in bytes of the
|
||||
array of
|
||||
.Vt "struct ranlib"
|
||||
descriptors encoded as a C
|
||||
.Vt long
|
||||
value.
|
||||
.Pp
|
||||
The array of
|
||||
.Vt "struct ranlib"
|
||||
descriptors follows the size field.
|
||||
Each
|
||||
.Vt "struct ranlib"
|
||||
descriptor describes one symbol.
|
||||
.Pp
|
||||
A
|
||||
.Vt "struct ranlib"
|
||||
descriptor comprises two fields:
|
||||
.Bl -tag -width "Ar ran_strx" -compact
|
||||
.It Ar ran_strx
|
||||
.Pq C Vt long
|
||||
This field contains the zero-based offset of the symbol name in the
|
||||
symbol string table.
|
||||
.It Ar ran_off
|
||||
.Pq C Vt long
|
||||
This field is the file offset to the archive header for the archive
|
||||
member defining the symbol.
|
||||
.El
|
||||
.Pp
|
||||
The part containing the symbol string table begins with a field
|
||||
containing the size in bytes of the string table, encoded as a C
|
||||
.Vt long
|
||||
value.
|
||||
This string table follows the size field, and contains
|
||||
NUL-terminated strings for the symbols in the symbol table.
|
||||
.It SVR4/GNU
|
||||
In the SVR4/GNU archive format, the archive symbol table starts with a
|
||||
4-byte binary value containing the number of entries contained in the
|
||||
archive symbol table.
|
||||
This count of entries is stored most significant byte first.
|
||||
.Pp
|
||||
Next, there are
|
||||
.Ar count
|
||||
4-byte numbers, each stored most significant byte first.
|
||||
Each number is a binary offset to the archive header for the member in
|
||||
the archive file for the corresponding symbol table entry.
|
||||
.Pp
|
||||
After the binary offset values, there are
|
||||
.Ar count
|
||||
NUL-terminated strings in sequence, holding the symbol names for
|
||||
the corresponding symbol table entries.
|
||||
.El
|
||||
.Sh STANDARDS COMPLIANCE
|
||||
The
|
||||
.Xr ar 1
|
||||
archive format is not currently specified by a standard.
|
||||
.Pp
|
||||
This manual page documents the
|
||||
.Xr ar 1
|
||||
archive formats used by the
|
||||
.Bx 4.4
|
||||
and
|
||||
.Ux SVR4
|
||||
operating system releases.
|
||||
.Sh SEE ALSO
|
||||
.Xr ar 1 ,
|
||||
.Xr ld 1 ,
|
||||
.Xr ranlib 1 ,
|
||||
.Xr elf 3 ,
|
||||
.Xr elf_getarsym 3 ,
|
||||
.Xr elf_rand 3
|
435
ar/ar.c
Normal file
435
ar/ar.c
Normal file
|
@ -0,0 +1,435 @@
|
|||
/*-
|
||||
* Copyright (c) 2007 Kai Wang
|
||||
* Copyright (c) 2007 Tim Kientzle
|
||||
* Copyright (c) 2007 Joseph Koshy
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Hugh Smith at The University of Guelph.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <archive.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <libelftc.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ar.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ar.c 2485 2012-04-07 15:54:59Z kaiwang27 $");
|
||||
|
||||
enum options
|
||||
{
|
||||
OPTION_HELP
|
||||
};
|
||||
|
||||
static struct option longopts[] =
|
||||
{
|
||||
{"flavor", required_argument, NULL, 'F'},
|
||||
{"help", no_argument, NULL, OPTION_HELP},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static void bsdar_usage(void);
|
||||
static void ranlib_usage(void);
|
||||
static void set_mode(struct bsdar *bsdar, char opt);
|
||||
static void only_mode(struct bsdar *bsdar, const char *opt,
|
||||
const char *valid_modes);
|
||||
static void bsdar_version(void);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct bsdar *bsdar, bsdar_storage;
|
||||
char *arcmd, *argv1_saved;
|
||||
size_t len;
|
||||
int i, opt;
|
||||
|
||||
bsdar = &bsdar_storage;
|
||||
memset(bsdar, 0, sizeof(*bsdar));
|
||||
|
||||
arcmd = argv1_saved = NULL;
|
||||
bsdar->output = stdout;
|
||||
|
||||
if ((bsdar->progname = ELFTC_GETPROGNAME()) == NULL)
|
||||
bsdar->progname = "ar";
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
bsdar_errc(bsdar, 0, "ELF library initialization failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/*
|
||||
* Act like ranlib if our name ends in "ranlib"; this
|
||||
* accomodates names like "arm-freebsd7.1-ranlib",
|
||||
* "bsdranlib", etc.
|
||||
*/
|
||||
len = strlen(bsdar->progname);
|
||||
if (len >= strlen("ranlib") &&
|
||||
strcmp(bsdar->progname + len - strlen("ranlib"), "ranlib") == 0) {
|
||||
while ((opt = getopt_long(argc, argv, "tDV", longopts,
|
||||
NULL)) != -1) {
|
||||
switch(opt) {
|
||||
case 't':
|
||||
/* Ignored. */
|
||||
break;
|
||||
case 'D':
|
||||
bsdar->options |= AR_D;
|
||||
break;
|
||||
case 'V':
|
||||
bsdar_version();
|
||||
break;
|
||||
case OPTION_HELP:
|
||||
ranlib_usage();
|
||||
default:
|
||||
ranlib_usage();
|
||||
}
|
||||
}
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (*argv == NULL)
|
||||
ranlib_usage();
|
||||
|
||||
bsdar->options |= AR_S;
|
||||
for (;(bsdar->filename = *argv++) != NULL;)
|
||||
ar_write_archive(bsdar, 's');
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
} else {
|
||||
if (argc < 2)
|
||||
bsdar_usage();
|
||||
|
||||
/*
|
||||
* Tack on a leading '-', for old-style usage.
|
||||
*/
|
||||
if (*argv[1] != '-') {
|
||||
argv1_saved = argv[1];
|
||||
len = strlen(argv[1]) + 2;
|
||||
if ((arcmd = malloc(len)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
(void) snprintf(arcmd, len, "-%s", argv[1]);
|
||||
argv[1] = arcmd;
|
||||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "abCcdDfF:ijlMmopqrSsTtuVvxz",
|
||||
longopts, NULL)) != -1) {
|
||||
switch(opt) {
|
||||
case 'a':
|
||||
bsdar->options |= AR_A;
|
||||
break;
|
||||
case 'b':
|
||||
case 'i':
|
||||
bsdar->options |= AR_B;
|
||||
break;
|
||||
case 'C':
|
||||
bsdar->options |= AR_CC;
|
||||
break;
|
||||
case 'c':
|
||||
bsdar->options |= AR_C;
|
||||
break;
|
||||
case 'd':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'D':
|
||||
bsdar->options |= AR_D;
|
||||
break;
|
||||
case 'F':
|
||||
if (!strcasecmp(optarg, "svr4") ||
|
||||
!strcasecmp(optarg, "gnu"))
|
||||
bsdar->options &= ~AR_BSD;
|
||||
else if (!strcasecmp(optarg, "bsd"))
|
||||
bsdar->options |= AR_BSD;
|
||||
else
|
||||
bsdar_usage();
|
||||
break;
|
||||
case 'f':
|
||||
case 'T':
|
||||
bsdar->options |= AR_TR;
|
||||
break;
|
||||
case 'j':
|
||||
/* ignored */
|
||||
break;
|
||||
case 'l':
|
||||
/* ignored, for GNU ar comptibility */
|
||||
break;
|
||||
case 'M':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'm':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'o':
|
||||
bsdar->options |= AR_O;
|
||||
break;
|
||||
case 'p':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'q':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'r':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'S':
|
||||
bsdar->options |= AR_SS;
|
||||
break;
|
||||
case 's':
|
||||
bsdar->options |= AR_S;
|
||||
break;
|
||||
case 't':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'u':
|
||||
bsdar->options |= AR_U;
|
||||
break;
|
||||
case 'V':
|
||||
bsdar_version();
|
||||
break;
|
||||
case 'v':
|
||||
bsdar->options |= AR_V;
|
||||
break;
|
||||
case 'x':
|
||||
set_mode(bsdar, opt);
|
||||
break;
|
||||
case 'z':
|
||||
/* ignored */
|
||||
break;
|
||||
case OPTION_HELP:
|
||||
bsdar_usage();
|
||||
default:
|
||||
bsdar_usage();
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore argv[1] if we had modified it. */
|
||||
if (arcmd != NULL) {
|
||||
argv[1] = argv1_saved;
|
||||
free(arcmd);
|
||||
arcmd = argv1_saved = NULL;
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (*argv == NULL && bsdar->mode != 'M')
|
||||
bsdar_usage();
|
||||
|
||||
if (bsdar->options & AR_A && bsdar->options & AR_B)
|
||||
bsdar_errc(bsdar, 0,
|
||||
"only one of -a and -[bi] options allowed");
|
||||
|
||||
if (bsdar->options & AR_J && bsdar->options & AR_Z)
|
||||
bsdar_errc(bsdar, 0,
|
||||
"only one of -j and -z options allowed");
|
||||
|
||||
if (bsdar->options & AR_S && bsdar->options & AR_SS)
|
||||
bsdar_errc(bsdar, 0,
|
||||
"only one of -s and -S options allowed");
|
||||
|
||||
if (bsdar->options & (AR_A | AR_B)) {
|
||||
if (*argv == NULL)
|
||||
bsdar_errc(bsdar, 0,
|
||||
"no position operand specified");
|
||||
if ((bsdar->posarg = basename(*argv)) == NULL)
|
||||
bsdar_errc(bsdar, errno,
|
||||
"basename failed");
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (bsdar->options & AR_A)
|
||||
only_mode(bsdar, "-a", "mqr");
|
||||
if (bsdar->options & AR_B)
|
||||
only_mode(bsdar, "-b", "mqr");
|
||||
if (bsdar->options & AR_C)
|
||||
only_mode(bsdar, "-c", "qr");
|
||||
if (bsdar->options & AR_CC)
|
||||
only_mode(bsdar, "-C", "x");
|
||||
if (bsdar->options & AR_D)
|
||||
only_mode(bsdar, "-D", "qr");
|
||||
if (bsdar->options & AR_O)
|
||||
only_mode(bsdar, "-o", "x");
|
||||
if (bsdar->options & AR_SS)
|
||||
only_mode(bsdar, "-S", "mqr");
|
||||
if (bsdar->options & AR_U)
|
||||
only_mode(bsdar, "-u", "qrx");
|
||||
|
||||
if (bsdar->mode == 'M') {
|
||||
ar_mode_script(bsdar);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if ((bsdar->filename = *argv) == NULL)
|
||||
bsdar_usage();
|
||||
|
||||
bsdar->argc = --argc;
|
||||
bsdar->argv = ++argv;
|
||||
|
||||
if ((!bsdar->mode || strchr("ptx", bsdar->mode)) &&
|
||||
bsdar->options & AR_S) {
|
||||
ar_write_archive(bsdar, 's');
|
||||
if (!bsdar->mode)
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
switch(bsdar->mode) {
|
||||
case 'd': case 'm': case 'q': case 'r':
|
||||
ar_write_archive(bsdar, bsdar->mode);
|
||||
break;
|
||||
|
||||
case 'p': case 't': case 'x':
|
||||
ar_read_archive(bsdar, bsdar->mode);
|
||||
break;
|
||||
default:
|
||||
bsdar_usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
for (i = 0; i < bsdar->argc; i++)
|
||||
if (bsdar->argv[i] != NULL)
|
||||
bsdar_warnc(bsdar, 0, "%s: not found in archive",
|
||||
bsdar->argv[i]);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
set_mode(struct bsdar *bsdar, char opt)
|
||||
{
|
||||
|
||||
if (bsdar->mode != '\0' && bsdar->mode != opt)
|
||||
bsdar_errc(bsdar, 0, "Can't specify both -%c and -%c",
|
||||
opt, bsdar->mode);
|
||||
bsdar->mode = opt;
|
||||
}
|
||||
|
||||
static void
|
||||
only_mode(struct bsdar *bsdar, const char *opt, const char *valid_modes)
|
||||
{
|
||||
|
||||
if (strchr(valid_modes, bsdar->mode) == NULL)
|
||||
bsdar_errc(bsdar, 0, "Option %s is not permitted in mode -%c",
|
||||
opt, bsdar->mode);
|
||||
}
|
||||
|
||||
#define AR_USAGE_MESSAGE "\
|
||||
Usage: %s <command> [options] archive file...\n\
|
||||
Manage archives.\n\n\
|
||||
Where <command> is one of:\n\
|
||||
-d Delete members from the archive.\n\
|
||||
-m Move archive members within the archive.\n\
|
||||
-p Write the contents of members to standard output.\n\
|
||||
-q Append files to an archive.\n\
|
||||
-r Replace (add) files to an archive.\n\
|
||||
-s Add an archive symbol to an archive.\n\
|
||||
-t List files in an archive.\n\
|
||||
-x Extract members from an archive.\n\
|
||||
-M Execute MRI librarian commands.\n\
|
||||
-V Print a version identifier and exit.\n\n\
|
||||
Options:\n\
|
||||
-a MEMBER Add members after the specified member.\n\
|
||||
-b MEMBER | -i MEMBER\n\
|
||||
Add members before the specified member.\n\
|
||||
-c Do not print a message when creating a new archive.\n\
|
||||
-f | -T Only use the first fifteen characters of the member name.\n\
|
||||
-j (This option is accepted, but is ignored).\n\
|
||||
-l (This option is accepted, but is ignored).\n\
|
||||
-o Preserve modification times when extracting members.\n\
|
||||
-u Conditionally update or extract members.\n\
|
||||
-v Be verbose.\n\
|
||||
-z (This option is accepted, but is ignored).\n\
|
||||
-C Do not overwrite existing files in the file system.\n\
|
||||
-D Use fixed metadata, for consistent archive checksums.\n\
|
||||
-F FORMAT | --flavor=FORMAT\n\
|
||||
Create archives with the specified format.\n\
|
||||
-S Do not generate an archive symbol table.\n"
|
||||
|
||||
static void
|
||||
bsdar_usage(void)
|
||||
{
|
||||
(void) fprintf(stderr, AR_USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define RANLIB_USAGE_MESSAGE "\
|
||||
Usage: %s [options] archive...\n\
|
||||
Update or create archive symbol tables.\n\n\
|
||||
Options:\n\
|
||||
-t (This option is accepted, but ignored).\n\
|
||||
-D Use fixed metadata, for consistent archive checksums.\n\
|
||||
-V Print a version identifier and exit.\n"
|
||||
|
||||
static void
|
||||
ranlib_usage(void)
|
||||
{
|
||||
(void)fprintf(stderr, RANLIB_USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
bsdar_version(void)
|
||||
{
|
||||
(void)printf("%s (%s, %s)\n", ELFTC_GETPROGNAME(), archive_version_string(),
|
||||
elftc_version());
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
143
ar/ar.h
Normal file
143
ar/ar.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*-
|
||||
* Copyright (c) 2007 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ar.h 2496 2012-04-24 02:33:40Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <libelf.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
/*
|
||||
* ar(1) options.
|
||||
*/
|
||||
#define AR_A 0x0001 /* position-after */
|
||||
#define AR_B 0x0002 /* position-before */
|
||||
#define AR_C 0x0004 /* creating new archive */
|
||||
#define AR_CC 0x0008 /* do not overwrite when extracting */
|
||||
#define AR_J 0x0010 /* bzip2 compression */
|
||||
#define AR_O 0x0020 /* preserve original mtime when extracting */
|
||||
#define AR_S 0x0040 /* write archive symbol table */
|
||||
#define AR_SS 0x0080 /* do not write archive symbol table */
|
||||
#define AR_TR 0x0100 /* only keep first 15 chars for member name */
|
||||
#define AR_U 0x0200 /* only extract or update newer members.*/
|
||||
#define AR_V 0x0400 /* verbose mode */
|
||||
#define AR_Z 0x0800 /* gzip compression */
|
||||
#define AR_D 0x1000 /* insert dummy mode, mtime, uid and gid */
|
||||
#define AR_BSD 0x2000 /* use the BSD archive format */
|
||||
|
||||
#define DEF_BLKSZ 10240 /* default block size */
|
||||
|
||||
/* Special names. */
|
||||
|
||||
#define AR_STRINGTAB_NAME_SVR4 "//"
|
||||
#define AR_SYMTAB_NAME_BSD "__.SYMDEF"
|
||||
#define AR_SYMTAB_NAME_SVR4 "/"
|
||||
|
||||
/*
|
||||
* Convenient wrapper for general libarchive error handling.
|
||||
*/
|
||||
#define AC(CALL) do { \
|
||||
if ((CALL)) \
|
||||
bsdar_errc(bsdar, 0, "%s", \
|
||||
archive_error_string(a)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* The 'ACV' wrapper is used for libarchive APIs that changed from
|
||||
* returning 'void' to returning an 'int' in later versions of libarchive.
|
||||
*/
|
||||
#if ARCHIVE_VERSION_NUMBER >= 2000000
|
||||
#define ACV(CALL) AC(CALL)
|
||||
#else
|
||||
#define ACV(CALL) do { \
|
||||
(CALL); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In-memory representation of archive member(object).
|
||||
*/
|
||||
struct ar_obj {
|
||||
Elf *elf; /* object file descriptor */
|
||||
char *name; /* member name */
|
||||
uid_t uid; /* user id */
|
||||
gid_t gid; /* group id */
|
||||
mode_t md; /* octal file permissions */
|
||||
size_t size; /* member size */
|
||||
time_t mtime; /* modification time */
|
||||
dev_t dev; /* inode's device */
|
||||
ino_t ino; /* inode's number */
|
||||
|
||||
TAILQ_ENTRY(ar_obj) objs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure encapsulates the "global" data for "ar" program.
|
||||
*/
|
||||
struct bsdar {
|
||||
const char *filename; /* archive name. */
|
||||
const char *addlib; /* target of ADDLIB. */
|
||||
const char *posarg; /* position arg for modifiers -a, -b. */
|
||||
char mode; /* program mode */
|
||||
int options; /* command line options */
|
||||
FILE *output; /* default output stream */
|
||||
|
||||
const char *progname; /* program name */
|
||||
int argc;
|
||||
char **argv;
|
||||
|
||||
dev_t ar_dev; /* archive device. */
|
||||
ino_t ar_ino; /* archive inode. */
|
||||
|
||||
/*
|
||||
* Fields for the archive string table.
|
||||
*/
|
||||
char *as; /* buffer for archive string table. */
|
||||
size_t as_sz; /* current size of as table. */
|
||||
size_t as_cap; /* capacity of as table buffer. */
|
||||
|
||||
/*
|
||||
* Fields for the archive symbol table.
|
||||
*/
|
||||
uint32_t s_cnt; /* current number of symbols. */
|
||||
uint32_t *s_so; /* symbol offset table. */
|
||||
size_t s_so_cap; /* capacity of so table buffer. */
|
||||
char *s_sn; /* symbol name table */
|
||||
size_t s_sn_cap; /* capacity of sn table buffer. */
|
||||
size_t s_sn_sz; /* current size of sn table. */
|
||||
/* Current member's offset (relative to the end of pseudo members.) */
|
||||
off_t rela_off;
|
||||
|
||||
TAILQ_HEAD(, ar_obj) v_obj; /* object(member) list */
|
||||
};
|
||||
|
||||
void ar_mode_script(struct bsdar *ar);
|
||||
void ar_read_archive(struct bsdar *_ar, int _mode);
|
||||
void ar_write_archive(struct bsdar *_ar, int _mode);
|
||||
void bsdar_errc(struct bsdar *, int _code, const char *fmt, ...);
|
||||
int bsdar_is_pseudomember(struct bsdar *_ar, const char *_name);
|
||||
const char *bsdar_strmode(mode_t m);
|
||||
void bsdar_warnc(struct bsdar *, int _code, const char *fmt, ...);
|
65
ar/benchmark/acp.sh
Executable file
65
ar/benchmark/acp.sh
Executable file
|
@ -0,0 +1,65 @@
|
|||
#!/bin/sh
|
||||
# $Id: acp.sh 2086 2011-10-27 05:18:01Z jkoshy $
|
||||
|
||||
# This script is adapted from Jan Psota's Tar Comparison Program(TCP).
|
||||
|
||||
n=3 # number of repetitions
|
||||
AR="bsdar gnuar" # ar archivers to compare
|
||||
|
||||
test $# -ge 2 || {
|
||||
echo "usage: $0 source_dir where_to_place_archive [where_to_extract_it]"
|
||||
exit 0
|
||||
}
|
||||
|
||||
THISDIR=`/bin/pwd`
|
||||
src=$1
|
||||
dst=$2/acp.a
|
||||
ext=${3:-$2}/acptmp
|
||||
test -e $dst -o -e /tmp/acp \
|
||||
&& { echo "$dst or /tmp/acp exists, exiting"; exit 1; }
|
||||
mkdir -p $ext || exit 1
|
||||
|
||||
show_result ()
|
||||
{
|
||||
awk -vL="`du -k $dst`" '{printf "%s\t%s\t%s\%10.1d KB/s\n",
|
||||
$1, $3, $5, ($1>0?L/$1:0)}' /tmp/acp | sort | head -n 1
|
||||
}
|
||||
|
||||
test -d $src || { echo "'$src' is not a directory"; exit 1; }
|
||||
|
||||
# ar versions
|
||||
for ar in $AR; do echo -n "$ar: "; $ar -V | head -n 1;
|
||||
done
|
||||
|
||||
echo
|
||||
echo "best time of $n repetitions"
|
||||
echo -n " src=$src, "
|
||||
echo -n "`du -sh $src | awk '{print $1}'`"
|
||||
echo -n " in "
|
||||
echo "`find $src | wc -l` files"
|
||||
echo " archive=$dst, extract to $ext"
|
||||
|
||||
echo "program operation real user system speed"
|
||||
for op in "cru $dst $src/*" "t $dst" "x `basename $dst`"; do
|
||||
for ar in $AR; do
|
||||
echo -n "$ar "
|
||||
echo $op | grep -q ^cr && echo -n "create "
|
||||
echo $op | grep -q ^t && echo -n "list "
|
||||
echo $op | grep -q ^x && echo -n "extract "
|
||||
num=0
|
||||
while [ $num -lt $n ]; do
|
||||
echo $op | grep -q ^cr && rm -f $dst
|
||||
echo $op | grep -q ^x && { rm -rf $ext; mkdir -p $ext
|
||||
cp $dst $ext; cd $ext; }
|
||||
sync
|
||||
time $ar $op > /dev/null 2>> /tmp/acp
|
||||
echo $op | grep -q ^x && cd $THISDIR
|
||||
num=`expr $num + 1`
|
||||
done
|
||||
show_result
|
||||
rm -rf /tmp/acp
|
||||
done
|
||||
echo
|
||||
done
|
||||
rm -rf $ext $dst
|
||||
rm -f /tmp/acp
|
86
ar/ranlib.1
Normal file
86
ar/ranlib.1
Normal file
|
@ -0,0 +1,86 @@
|
|||
.\" Copyright (c) 2007,2009-2012 Joseph Koshy. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" This software is provided by Joseph Koshy ``as is'' and
|
||||
.\" any express or implied warranties, including, but not limited to, the
|
||||
.\" implied warranties of merchantability and fitness for a particular purpose
|
||||
.\" are disclaimed. in no event shall Joseph Koshy be liable
|
||||
.\" for any direct, indirect, incidental, special, exemplary, or consequential
|
||||
.\" damages (including, but not limited to, procurement of substitute goods
|
||||
.\" or services; loss of use, data, or profits; or business interruption)
|
||||
.\" however caused and on any theory of liability, whether in contract, strict
|
||||
.\" liability, or tort (including negligence or otherwise) arising in any way
|
||||
.\" out of the use of this software, even if advised of the possibility of
|
||||
.\" such damage.
|
||||
.\"
|
||||
.\" $Id: ranlib.1 2739 2012-12-09 17:07:46Z jkoshy $
|
||||
.\"
|
||||
.Dd December 9, 2012
|
||||
.Os
|
||||
.Dt RANLIB 1
|
||||
.Sh NAME
|
||||
.Nm ranlib
|
||||
.Nd update archive symbol tables
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl D
|
||||
.Op Fl t
|
||||
.Ar archive Ns ...
|
||||
.Nm
|
||||
.Fl V
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm ranlib
|
||||
utility is used to update an existing archive symbol table in an
|
||||
.Xr ar 1
|
||||
archive, or to add an archive symbol table to an archive lacking one.
|
||||
.Sh OPTIONS
|
||||
The
|
||||
.Nm
|
||||
utility supports the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl D
|
||||
Use zeros for the mtime, uid and gid fields, and use mode 0644 for the
|
||||
file mode field for all archive member headers.
|
||||
This ensures that checksums on the resulting archives are reproducible
|
||||
when member contents are identical.
|
||||
.It Fl t
|
||||
This option is accepted, but is ignored.
|
||||
.It Fl V
|
||||
Print a version identifier and exit.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
To update the archive symbol table for an archive
|
||||
.Pa lib.a ,
|
||||
use:
|
||||
.Dl "ranlib lib.a"
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr ar 1 ,
|
||||
.Xr ld 1 ,
|
||||
.Xr archive 3 ,
|
||||
.Xr elf 3 ,
|
||||
.Xr ar 5
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
command first appeared in AT&T UNIX Version 7.
|
||||
.Pp
|
||||
In
|
||||
.Fx 8.0 ,
|
||||
.An "Kai Wang" Aq kaiw@FreeBSD.org
|
||||
reimplemented
|
||||
.Nm
|
||||
using the
|
||||
.Lb libarchive
|
||||
and the
|
||||
.Lb libelf .
|
192
ar/read.c
Normal file
192
ar/read.c
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*-
|
||||
* Copyright (c) 2007 Kai Wang
|
||||
* Copyright (c) 2007 Tim Kientzle
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ar.h"
|
||||
|
||||
ELFTC_VCSID("$Id: read.c 2229 2011-11-27 13:25:37Z jkoshy $");
|
||||
|
||||
/*
|
||||
* Handle read modes: 'x', 't' and 'p'.
|
||||
*/
|
||||
void
|
||||
ar_read_archive(struct bsdar *bsdar, int mode)
|
||||
{
|
||||
FILE *out;
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
struct stat sb;
|
||||
struct tm *tp;
|
||||
const char *bname;
|
||||
const char *name;
|
||||
mode_t md;
|
||||
size_t size;
|
||||
time_t mtime;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char **av;
|
||||
char buf[25];
|
||||
char find;
|
||||
int i, flags, r;
|
||||
|
||||
assert(mode == 'p' || mode == 't' || mode == 'x');
|
||||
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
bsdar_errc(bsdar, 0, "archive_read_new failed");
|
||||
archive_read_support_compression_none(a);
|
||||
archive_read_support_format_ar(a);
|
||||
AC(archive_read_open_file(a, bsdar->filename, DEF_BLKSZ));
|
||||
|
||||
out = bsdar->output;
|
||||
|
||||
for (;;) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
|
||||
r == ARCHIVE_FATAL)
|
||||
bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
|
||||
if (r == ARCHIVE_EOF || r == ARCHIVE_FATAL)
|
||||
break;
|
||||
if (r == ARCHIVE_RETRY) {
|
||||
bsdar_warnc(bsdar, 0, "Retrying...");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (archive_format(a) == ARCHIVE_FORMAT_AR_BSD)
|
||||
bsdar->options |= AR_BSD;
|
||||
else
|
||||
bsdar->options &= ~AR_BSD;
|
||||
|
||||
name = archive_entry_pathname(entry);
|
||||
|
||||
/* Skip pseudo members. */
|
||||
if (bsdar_is_pseudomember(bsdar, name))
|
||||
continue;
|
||||
|
||||
if (bsdar->argc > 0) {
|
||||
find = 0;
|
||||
for(i = 0; i < bsdar->argc; i++) {
|
||||
av = &bsdar->argv[i];
|
||||
if (*av == NULL)
|
||||
continue;
|
||||
if ((bname = basename(*av)) == NULL)
|
||||
bsdar_errc(bsdar, errno,
|
||||
"basename failed");
|
||||
if (strcmp(bname, name) != 0)
|
||||
continue;
|
||||
|
||||
*av = NULL;
|
||||
find = 1;
|
||||
break;
|
||||
}
|
||||
if (!find)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mode == 't') {
|
||||
if (bsdar->options & AR_V) {
|
||||
md = archive_entry_mode(entry);
|
||||
uid = archive_entry_uid(entry);
|
||||
gid = archive_entry_gid(entry);
|
||||
size = archive_entry_size(entry);
|
||||
mtime = archive_entry_mtime(entry);
|
||||
(void)fprintf(out, "%s %6d/%-6d %8ju ",
|
||||
bsdar_strmode(md) + 1, uid, gid,
|
||||
(uintmax_t)size);
|
||||
tp = localtime(&mtime);
|
||||
(void)strftime(buf, sizeof(buf),
|
||||
"%b %e %H:%M %Y", tp);
|
||||
(void)fprintf(out, "%s %s", buf, name);
|
||||
} else
|
||||
(void)fprintf(out, "%s", name);
|
||||
r = archive_read_data_skip(a);
|
||||
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY ||
|
||||
r == ARCHIVE_FATAL) {
|
||||
(void)fprintf(out, "\n");
|
||||
bsdar_warnc(bsdar, 0, "%s",
|
||||
archive_error_string(a));
|
||||
}
|
||||
|
||||
if (r == ARCHIVE_FATAL)
|
||||
break;
|
||||
|
||||
(void)fprintf(out, "\n");
|
||||
} else {
|
||||
/* mode == 'x' || mode = 'p' */
|
||||
if (mode == 'p') {
|
||||
if (bsdar->options & AR_V) {
|
||||
(void)fprintf(out, "\n<%s>\n\n",
|
||||
name);
|
||||
fflush(out);
|
||||
}
|
||||
r = archive_read_data_into_fd(a, fileno(out));
|
||||
} else {
|
||||
/* mode == 'x' */
|
||||
if (stat(name, &sb) != 0) {
|
||||
if (errno != ENOENT) {
|
||||
bsdar_warnc(bsdar, 0,
|
||||
"stat %s failed",
|
||||
bsdar->filename);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* stat success, file exist */
|
||||
if (bsdar->options & AR_CC)
|
||||
continue;
|
||||
if (bsdar->options & AR_U &&
|
||||
archive_entry_mtime(entry) <=
|
||||
sb.st_mtime)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bsdar->options & AR_V)
|
||||
(void)fprintf(out, "x - %s\n", name);
|
||||
flags = 0;
|
||||
if (bsdar->options & AR_O)
|
||||
flags |= ARCHIVE_EXTRACT_TIME;
|
||||
|
||||
r = archive_read_extract(a, entry, flags);
|
||||
}
|
||||
|
||||
if (r)
|
||||
bsdar_warnc(bsdar, 0, "%s",
|
||||
archive_error_string(a));
|
||||
}
|
||||
}
|
||||
AC(archive_read_close(a));
|
||||
ACV(archive_read_finish(a));
|
||||
}
|
185
ar/util.c
Normal file
185
ar/util.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*-
|
||||
* Copyright (c) 2003-2007 Tim Kientzle
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "ar.h"
|
||||
|
||||
ELFTC_VCSID("$Id: util.c 2130 2011-11-10 06:56:46Z jkoshy $");
|
||||
|
||||
static void bsdar_vwarnc(struct bsdar *, int code,
|
||||
const char *fmt, va_list ap);
|
||||
static void bsdar_verrc(struct bsdar *bsdar, int code,
|
||||
const char *fmt, va_list ap);
|
||||
|
||||
static void
|
||||
bsdar_vwarnc(struct bsdar *bsdar, int code, const char *fmt, va_list ap)
|
||||
{
|
||||
|
||||
fprintf(stderr, "%s: warning: ", bsdar->progname);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
if (code != 0)
|
||||
fprintf(stderr, ": %s", strerror(code));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
bsdar_warnc(struct bsdar *bsdar, int code, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
bsdar_vwarnc(bsdar, code, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void
|
||||
bsdar_verrc(struct bsdar *bsdar, int code, const char *fmt, va_list ap)
|
||||
{
|
||||
|
||||
fprintf(stderr, "%s: fatal: ", bsdar->progname);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
if (code != 0)
|
||||
fprintf(stderr, ": %s", strerror(code));
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
bsdar_errc(struct bsdar *bsdar, int code, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
bsdar_verrc(bsdar, code, fmt, ap);
|
||||
va_end(ap);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define AR_STRMODE_SIZE 12
|
||||
const char *
|
||||
bsdar_strmode(mode_t m)
|
||||
{
|
||||
static char buf[AR_STRMODE_SIZE];
|
||||
|
||||
#if ELFTC_HAVE_STRMODE
|
||||
/* Use the system's strmode(3). */
|
||||
strmode(m, buf);
|
||||
return buf;
|
||||
|
||||
#else
|
||||
char c;
|
||||
|
||||
/*
|
||||
* The first character of the string denotes the type of the
|
||||
* entry.
|
||||
*/
|
||||
if (S_ISBLK(m))
|
||||
c = 'b';
|
||||
else if (S_ISCHR(m))
|
||||
c = 'c';
|
||||
else if (S_ISDIR(m))
|
||||
c = 'd';
|
||||
#if defined(S_ISFIFO)
|
||||
else if (S_ISFIFO(m))
|
||||
c = 'p';
|
||||
#endif
|
||||
#if defined(S_ISLNK)
|
||||
else if (S_ISLNK(m))
|
||||
c = 'l';
|
||||
#endif
|
||||
else if (S_ISREG(m))
|
||||
c = '-';
|
||||
#if defined(S_ISSOCK)
|
||||
else if (S_ISSOCK(m))
|
||||
c = 's';
|
||||
#endif
|
||||
else
|
||||
c = '?';
|
||||
buf[0] = c;
|
||||
|
||||
/* The next 3 characters show permissions for the owner. */
|
||||
buf[1] = (m & S_IRUSR) ? 'r' : '-';
|
||||
buf[2] = m & S_IWUSR ? 'w' : '-';
|
||||
if (m & S_ISUID)
|
||||
c = (m & S_IXUSR) ? 's' : 'S';
|
||||
else
|
||||
c = (m & S_IXUSR) ? 'x' : '-';
|
||||
buf[3] = c;
|
||||
|
||||
/* The next 3 characters describe permissions for the group. */
|
||||
buf[4] = (m & S_IRGRP) ? 'r' : '-';
|
||||
buf[5] = m & S_IWGRP ? 'w' : '-';
|
||||
if (m & S_ISGID)
|
||||
c = (m & S_IXGRP) ? 's' : 'S';
|
||||
else
|
||||
c = (m & S_IXGRP) ? 'x' : '-';
|
||||
buf[6] = c;
|
||||
|
||||
|
||||
/* The next 3 characters describe permissions for others. */
|
||||
buf[7] = (m & S_IROTH) ? 'r' : '-';
|
||||
buf[8] = m & S_IWOTH ? 'w' : '-';
|
||||
if (m & S_ISVTX) /* sticky bit */
|
||||
c = (m & S_IXOTH) ? 't' : 'T';
|
||||
else
|
||||
c = (m & S_IXOTH) ? 'x' : '-';
|
||||
buf[9] = c;
|
||||
|
||||
/* End the string with a blank and NUL-termination. */
|
||||
buf[10] = ' ';
|
||||
buf[11] = '\0';
|
||||
|
||||
return buf;
|
||||
#endif /* !ELTC_HAVE_STRMODE */
|
||||
}
|
||||
|
||||
int
|
||||
bsdar_is_pseudomember(struct bsdar *bsdar, const char *name)
|
||||
{
|
||||
/*
|
||||
* The "__.SYMDEF" member is special in the BSD format
|
||||
* variant.
|
||||
*/
|
||||
if (bsdar->options & AR_BSD)
|
||||
return (strcmp(name, AR_SYMTAB_NAME_BSD) == 0);
|
||||
else
|
||||
/*
|
||||
* The names "/ " and "// " are special in the SVR4
|
||||
* variant.
|
||||
*/
|
||||
return (strcmp(name, AR_STRINGTAB_NAME_SVR4) == 0 ||
|
||||
strcmp(name, AR_SYMTAB_NAME_SVR4) == 0);
|
||||
}
|
978
ar/write.c
Normal file
978
ar/write.c
Normal file
|
@ -0,0 +1,978 @@
|
|||
/*-
|
||||
* Copyright (c) 2007 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h>
|
||||
#include <libgen.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ar.h"
|
||||
|
||||
ELFTC_VCSID("$Id: write.c 2496 2012-04-24 02:33:40Z jkoshy $");
|
||||
|
||||
#define _ARMAG_LEN 8 /* length of the magic string */
|
||||
#define _ARHDR_LEN 60 /* length of the archive header */
|
||||
#define _INIT_AS_CAP 128 /* initial archive string table size */
|
||||
#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */
|
||||
#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */
|
||||
#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */
|
||||
#define _MAXNAMELEN_BSD 16 /* max member name length in bsd variant */
|
||||
#define _TRUNCATE_LEN 15 /* number of bytes to keep for member name */
|
||||
|
||||
static void add_to_ar_str_table(struct bsdar *bsdar, const char *name);
|
||||
static void add_to_ar_sym_table(struct bsdar *bsdar, const char *name);
|
||||
static struct ar_obj *create_obj_from_file(struct bsdar *bsdar,
|
||||
const char *name, time_t mtime);
|
||||
static void create_symtab_entry(struct bsdar *bsdar, Elf *e);
|
||||
static void free_obj(struct ar_obj *obj);
|
||||
static void insert_obj(struct bsdar *bsdar, struct ar_obj *obj,
|
||||
struct ar_obj *pos);
|
||||
static void read_objs(struct bsdar *bsdar, const char *archive,
|
||||
int checkargv);
|
||||
static void write_cleanup(struct bsdar *bsdar);
|
||||
static void write_data(struct bsdar *bsdar, struct archive *a,
|
||||
const void *buf, size_t s);
|
||||
static void write_objs(struct bsdar *bsdar);
|
||||
|
||||
/*
|
||||
* Create an object from a file, and return the created object
|
||||
* descriptor. Return NULL if either an error occurs, or if the '-u'
|
||||
* option was specifed and the member is not newer than the existing
|
||||
* one in the archive.
|
||||
*/
|
||||
static struct ar_obj *
|
||||
create_obj_from_file(struct bsdar *bsdar, const char *name, time_t mtime)
|
||||
{
|
||||
struct ar_obj *obj;
|
||||
struct stat sb;
|
||||
const char *bname;
|
||||
char *tmpname;
|
||||
int fd;
|
||||
|
||||
if (name == NULL)
|
||||
return (NULL);
|
||||
|
||||
obj = malloc(sizeof(struct ar_obj));
|
||||
if (obj == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
|
||||
obj->elf = NULL;
|
||||
|
||||
if ((fd = open(name, O_RDONLY, 0)) < 0) {
|
||||
bsdar_warnc(bsdar, errno, "can't open file: %s", name);
|
||||
free(obj);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
tmpname = strdup(name);
|
||||
if ((bname = basename(tmpname)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "basename failed");
|
||||
if (bsdar->options & AR_TR && strlen(bname) > _TRUNCATE_LEN) {
|
||||
if ((obj->name = malloc(_TRUNCATE_LEN + 1)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
(void)strncpy(obj->name, bname, _TRUNCATE_LEN);
|
||||
obj->name[_TRUNCATE_LEN] = '\0';
|
||||
} else
|
||||
if ((obj->name = strdup(bname)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "strdup failed");
|
||||
free(tmpname);
|
||||
|
||||
if (fstat(fd, &sb) < 0) {
|
||||
bsdar_warnc(bsdar, errno, "can't fstat file: %s", obj->name);
|
||||
goto giveup;
|
||||
}
|
||||
if (!S_ISREG(sb.st_mode)) {
|
||||
bsdar_warnc(bsdar, 0, "%s is not an ordinary file", obj->name);
|
||||
goto giveup;
|
||||
}
|
||||
|
||||
if (sb.st_dev == bsdar->ar_dev && sb.st_ino == bsdar->ar_ino) {
|
||||
bsdar_warnc(bsdar, 0, "cannot add archive \"%s\" to itself",
|
||||
obj->name);
|
||||
goto giveup;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the '-u' option is specified and member is not newer
|
||||
* than the existing one, we should not replace the member.
|
||||
* However, if mtime == 0, i.e., if nonexistent members are to
|
||||
* be forcibly replaced, then the '-u' option is to be ignored.
|
||||
*/
|
||||
if (mtime != 0 && bsdar->options & AR_U && sb.st_mtime <= mtime)
|
||||
goto giveup;
|
||||
|
||||
/*
|
||||
* When the '-D' option is specified, the mtime and UID/GID of
|
||||
* the member will be set to 0, and the file mode will be set
|
||||
* to 644. This ensures that checksums will match for two
|
||||
* archives containing identical content.
|
||||
*/
|
||||
if (bsdar->options & AR_D) {
|
||||
obj->uid = 0;
|
||||
obj->gid = 0;
|
||||
obj->mtime = 0;
|
||||
obj->md = S_IFREG | 0644;
|
||||
} else {
|
||||
obj->uid = sb.st_uid;
|
||||
obj->gid = sb.st_gid;
|
||||
obj->mtime = sb.st_mtime;
|
||||
obj->md = sb.st_mode;
|
||||
}
|
||||
obj->size = sb.st_size;
|
||||
obj->dev = sb.st_dev;
|
||||
obj->ino = sb.st_ino;
|
||||
|
||||
if (obj->size == 0) {
|
||||
return (obj);
|
||||
}
|
||||
|
||||
if ((obj->elf = elf_open(fd)) == NULL) {
|
||||
bsdar_warnc(bsdar, 0, "file initialization failed for %s: %s",
|
||||
obj->name, elf_errmsg(-1));
|
||||
goto giveup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the object fully into memory and close its file
|
||||
* descriptor.
|
||||
*/
|
||||
if (elf_cntl(obj->elf, ELF_C_FDREAD) < 0) {
|
||||
bsdar_warnc(bsdar, 0, "%s could not be read in: %s",
|
||||
obj->name, elf_errmsg(-1));
|
||||
goto giveup;
|
||||
}
|
||||
|
||||
if (close(fd) < 0)
|
||||
bsdar_errc(bsdar, errno, "close failed: %s",
|
||||
obj->name);
|
||||
|
||||
return (obj);
|
||||
|
||||
giveup:
|
||||
if (obj->elf)
|
||||
elf_end(obj->elf);
|
||||
|
||||
if (close(fd) < 0)
|
||||
bsdar_errc(bsdar, errno, "close failed: %s",
|
||||
obj->name);
|
||||
free(obj->name);
|
||||
free(obj);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an object and its associated allocations.
|
||||
*/
|
||||
static void
|
||||
free_obj(struct ar_obj *obj)
|
||||
{
|
||||
if (obj->elf)
|
||||
elf_end(obj->elf);
|
||||
|
||||
free(obj->name);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an object into a list, either before/after the 'pos' obj or
|
||||
* at the end of the list.
|
||||
*/
|
||||
static void
|
||||
insert_obj(struct bsdar *bsdar, struct ar_obj *obj, struct ar_obj *pos)
|
||||
{
|
||||
if (obj == NULL)
|
||||
bsdar_errc(bsdar, 0, "try to insert a null obj");
|
||||
|
||||
if (pos == NULL || obj == pos)
|
||||
/*
|
||||
* If the object to move happens to be the position
|
||||
* obj, or if there is no position obj, move the
|
||||
* object to the end.
|
||||
*/
|
||||
goto tail;
|
||||
|
||||
if (bsdar->options & AR_B) {
|
||||
TAILQ_INSERT_BEFORE(pos, obj, objs);
|
||||
return;
|
||||
}
|
||||
if (bsdar->options & AR_A) {
|
||||
TAILQ_INSERT_AFTER(&bsdar->v_obj, pos, obj, objs);
|
||||
return;
|
||||
}
|
||||
|
||||
tail:
|
||||
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Read objects from archive into the 'v_obj' list. Note that
|
||||
* 'checkargv' is set when read_objs() is used to read objects from
|
||||
* the target of 'ADDLIB' command in ar script mode; in this case the
|
||||
* 'argv' array specifies the members that 'ADDLIB' is to operate on.
|
||||
*/
|
||||
static void
|
||||
read_objs(struct bsdar *bsdar, const char *archive, int checkargv)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
struct ar_obj *obj;
|
||||
const char *name;
|
||||
const char *bname;
|
||||
char *buff;
|
||||
char **av;
|
||||
size_t size;
|
||||
int i, r, find;
|
||||
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
bsdar_errc(bsdar, 0, "archive_read_new failed");
|
||||
archive_read_support_compression_none(a);
|
||||
archive_read_support_format_ar(a);
|
||||
AC(archive_read_open_filename(a, archive, DEF_BLKSZ));
|
||||
for (;;) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_FATAL)
|
||||
bsdar_errc(bsdar, 0, "%s", archive_error_string(a));
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY)
|
||||
bsdar_warnc(bsdar, 0, "%s", archive_error_string(a));
|
||||
if (r == ARCHIVE_RETRY) {
|
||||
bsdar_warnc(bsdar, 0, "Retrying...");
|
||||
continue;
|
||||
}
|
||||
|
||||
name = archive_entry_pathname(entry);
|
||||
|
||||
/*
|
||||
* Skip pseudo members.
|
||||
*/
|
||||
if (bsdar_is_pseudomember(bsdar, name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If 'checkargv' is set, only read those members
|
||||
* specified in argv.
|
||||
*/
|
||||
if (checkargv && bsdar->argc > 0) {
|
||||
find = 0;
|
||||
for(i = 0; i < bsdar->argc; i++) {
|
||||
av = &bsdar->argv[i];
|
||||
if (*av == NULL)
|
||||
continue;
|
||||
if ((bname = basename(*av)) == NULL)
|
||||
bsdar_errc(bsdar, errno,
|
||||
"basename failed");
|
||||
if (strcmp(bname, name) != 0)
|
||||
continue;
|
||||
|
||||
*av = NULL;
|
||||
find = 1;
|
||||
break;
|
||||
}
|
||||
if (!find)
|
||||
continue;
|
||||
}
|
||||
|
||||
size = archive_entry_size(entry);
|
||||
|
||||
if (size > 0) {
|
||||
if ((buff = malloc(size)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
if (archive_read_data(a, buff, size) != (ssize_t)size) {
|
||||
bsdar_warnc(bsdar, 0, "%s",
|
||||
archive_error_string(a));
|
||||
free(buff);
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
buff = NULL;
|
||||
|
||||
obj = malloc(sizeof(struct ar_obj));
|
||||
if (obj == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
obj->elf = NULL;
|
||||
if (buff) {
|
||||
obj->elf = elf_openmemory(buff, size);
|
||||
if (obj->elf == NULL) {
|
||||
bsdar_warnc(bsdar, 0, "elf_openmemory() "
|
||||
"failed for %s: %s", name,
|
||||
elf_errmsg(-1));
|
||||
free(buff);
|
||||
free(obj);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((obj->name = strdup(name)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "strdup failed");
|
||||
obj->size = size;
|
||||
obj->uid = archive_entry_uid(entry);
|
||||
obj->gid = archive_entry_gid(entry);
|
||||
obj->md = archive_entry_mode(entry);
|
||||
obj->mtime = archive_entry_mtime(entry);
|
||||
obj->dev = 0;
|
||||
obj->ino = 0;
|
||||
|
||||
TAILQ_INSERT_TAIL(&bsdar->v_obj, obj, objs);
|
||||
}
|
||||
AC(archive_read_close(a));
|
||||
ACV(archive_read_finish(a));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write an archive.
|
||||
*/
|
||||
void
|
||||
ar_write_archive(struct bsdar *bsdar, int mode)
|
||||
{
|
||||
struct ar_obj *nobj, *obj, *obj_temp, *pos;
|
||||
struct stat sb;
|
||||
const char *bname;
|
||||
char **av;
|
||||
int i;
|
||||
|
||||
TAILQ_INIT(&bsdar->v_obj);
|
||||
nobj = NULL;
|
||||
pos = NULL;
|
||||
memset(&sb, 0, sizeof(sb));
|
||||
|
||||
assert(mode == 'A' || mode == 'd' || mode == 'm' || mode == 'q' ||
|
||||
mode == 'r' || mode == 's');
|
||||
|
||||
/*
|
||||
* Test if the specified archive exists, to determine
|
||||
* whether we are creating a new archive.
|
||||
*/
|
||||
if (stat(bsdar->filename, &sb) != 0) {
|
||||
if (errno != ENOENT) {
|
||||
bsdar_warnc(bsdar, 0, "stat %s failed",
|
||||
bsdar->filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We do not create archive in mode 'd', 'm' and 's'. */
|
||||
if (mode != 'r' && mode != 'q') {
|
||||
bsdar_warnc(bsdar, 0, "%s: no such file",
|
||||
bsdar->filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Issue a message if the '-c' option was not specified. */
|
||||
if (!(bsdar->options & AR_C))
|
||||
bsdar_warnc(bsdar, 0, "creating %s", bsdar->filename);
|
||||
goto new_archive;
|
||||
}
|
||||
|
||||
bsdar->ar_dev = sb.st_dev;
|
||||
bsdar->ar_ino = sb.st_ino;
|
||||
|
||||
/*
|
||||
* First read members from the existing archive.
|
||||
*/
|
||||
read_objs(bsdar, bsdar->filename, 0);
|
||||
|
||||
/*
|
||||
* For mode 's', no member will be moved, deleted or replaced.
|
||||
*/
|
||||
if (mode == 's')
|
||||
goto write_objs;
|
||||
|
||||
/*
|
||||
* For mode 'q', we don't need to adjust existing members either.
|
||||
* Also, -a, -b and -i are ignored in this mode. New members are
|
||||
* always inserted at tail.
|
||||
*/
|
||||
if (mode == 'q')
|
||||
goto new_archive;
|
||||
|
||||
/*
|
||||
* Mode 'A' adds the contents of another archive to the tail
|
||||
* of current archive. Note that mode 'A' is a special mode
|
||||
* for the 'ADDLIB' command in ar's script mode. Currently
|
||||
* there is no option that invokes this function from ar's
|
||||
* command line.
|
||||
*/
|
||||
if (mode == 'A') {
|
||||
/*
|
||||
* Read objects from the target archive of the
|
||||
* 'ADDLIB' command. If there are members spcified in
|
||||
* 'argv', read those members only, otherwise the
|
||||
* entire archive will be read.
|
||||
*/
|
||||
read_objs(bsdar, bsdar->addlib, 1);
|
||||
goto write_objs;
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find the position member specified by user.
|
||||
*/
|
||||
if (bsdar->options & AR_A || bsdar->options & AR_B) {
|
||||
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
|
||||
if (strcmp(obj->name, bsdar->posarg) == 0) {
|
||||
pos = obj;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we cannot find the position specified by the
|
||||
* user, sliently insert objects at the tail of the
|
||||
* list.
|
||||
*/
|
||||
if (pos == NULL)
|
||||
bsdar->options &= ~(AR_A | AR_B);
|
||||
}
|
||||
|
||||
for (i = 0; i < bsdar->argc; i++) {
|
||||
av = &bsdar->argv[i];
|
||||
|
||||
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) {
|
||||
if ((bname = basename(*av)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "basename failed");
|
||||
if (bsdar->options & AR_TR) {
|
||||
if (strncmp(bname, obj->name, _TRUNCATE_LEN))
|
||||
continue;
|
||||
} else
|
||||
if (strcmp(bname, obj->name) != 0)
|
||||
continue;
|
||||
|
||||
if (mode == 'r') {
|
||||
/*
|
||||
* If the new member should not
|
||||
* replace the old one, skip it.
|
||||
*/
|
||||
nobj = create_obj_from_file(bsdar, *av,
|
||||
obj->mtime);
|
||||
if (nobj == NULL)
|
||||
goto skip_obj;
|
||||
}
|
||||
|
||||
if (bsdar->options & AR_V)
|
||||
(void)fprintf(bsdar->output, "%c - %s\n",
|
||||
mode, *av);
|
||||
|
||||
TAILQ_REMOVE(&bsdar->v_obj, obj, objs);
|
||||
if (mode == 'd' || mode == 'r')
|
||||
free_obj(obj);
|
||||
|
||||
if (mode == 'm')
|
||||
insert_obj(bsdar, obj, pos);
|
||||
if (mode == 'r')
|
||||
insert_obj(bsdar, nobj, pos);
|
||||
|
||||
skip_obj:
|
||||
*av = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new_archive:
|
||||
/*
|
||||
* When operating in mode 'r', directly add the specified
|
||||
* objects which do not exist in current archive. When
|
||||
* operating in mode 'q', all objects specified by the command
|
||||
* line args are appended to the archive, without checking
|
||||
* existing members in the archive.
|
||||
*/
|
||||
for (i = 0; i < bsdar->argc; i++) {
|
||||
av = &bsdar->argv[i];
|
||||
if (*av != NULL && (mode == 'r' || mode == 'q')) {
|
||||
nobj = create_obj_from_file(bsdar, *av, 0);
|
||||
if (nobj != NULL)
|
||||
insert_obj(bsdar, nobj, pos);
|
||||
if (bsdar->options & AR_V && nobj != NULL)
|
||||
(void)fprintf(bsdar->output, "a - %s\n", *av);
|
||||
*av = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
write_objs:
|
||||
write_objs(bsdar);
|
||||
write_cleanup(bsdar);
|
||||
}
|
||||
|
||||
/*
|
||||
* Release memory.
|
||||
*/
|
||||
static void
|
||||
write_cleanup(struct bsdar *bsdar)
|
||||
{
|
||||
struct ar_obj *obj, *obj_temp;
|
||||
|
||||
TAILQ_FOREACH_SAFE(obj, &bsdar->v_obj, objs, obj_temp) {
|
||||
TAILQ_REMOVE(&bsdar->v_obj, obj, objs);
|
||||
free_obj(obj);
|
||||
}
|
||||
|
||||
free(bsdar->as);
|
||||
free(bsdar->s_so);
|
||||
free(bsdar->s_sn);
|
||||
bsdar->as = NULL;
|
||||
bsdar->s_so = NULL;
|
||||
bsdar->s_sn = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for archive_write_data().
|
||||
*/
|
||||
static void
|
||||
write_data(struct bsdar *bsdar, struct archive *a, const void *buf, size_t s)
|
||||
{
|
||||
if (archive_write_data(a, buf, s) != (ssize_t)s)
|
||||
bsdar_errc(bsdar, 0, "%s", archive_error_string(a));
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the size of the symbol table for an archive.
|
||||
*/
|
||||
static size_t
|
||||
bsdar_symtab_size(struct bsdar *bsdar)
|
||||
{
|
||||
size_t sz;
|
||||
|
||||
if (bsdar->options & AR_BSD) {
|
||||
/*
|
||||
* A BSD style symbol table has two parts.
|
||||
* Each part is preceded by its size in bytes,
|
||||
* encoded as a C 'long'. In the first part,
|
||||
* there are 's_cnt' entries, each entry being
|
||||
* 2 'long's in size. The second part
|
||||
* contains a string table.
|
||||
*/
|
||||
sz = 2 * sizeof(long) + (bsdar->s_cnt * 2 * sizeof(long)) +
|
||||
bsdar->s_sn_sz;
|
||||
} else {
|
||||
/*
|
||||
* An SVR4 style symbol table comprises of a 32 bit
|
||||
* number holding the number of entries, followed by
|
||||
* that many 32-bit offsets, followed by a string
|
||||
* table.
|
||||
*/
|
||||
sz = sizeof(uint32_t) + bsdar->s_cnt * sizeof(uint32_t) +
|
||||
bsdar->s_sn_sz;
|
||||
}
|
||||
|
||||
return (sz);
|
||||
}
|
||||
|
||||
static void
|
||||
write_svr4_symtab_entry(struct bsdar *bsdar, struct archive *a)
|
||||
{
|
||||
int nr;
|
||||
uint32_t i;
|
||||
|
||||
/* Translate offsets to big-endian form. */
|
||||
for (i = 0; i < bsdar->s_cnt; i++)
|
||||
bsdar->s_so[i] = htobe32(bsdar->s_so[i]);
|
||||
|
||||
nr = htobe32(bsdar->s_cnt);
|
||||
write_data(bsdar, a, &nr, sizeof(uint32_t));
|
||||
write_data(bsdar, a, bsdar->s_so, sizeof(uint32_t) *
|
||||
bsdar->s_cnt);
|
||||
write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz);
|
||||
}
|
||||
|
||||
static void
|
||||
write_bsd_symtab_entry(struct bsdar *bsdar, struct archive *a)
|
||||
{
|
||||
long br_sz, br_off, br_strx;
|
||||
char *s;
|
||||
uint32_t i;
|
||||
|
||||
/*
|
||||
* Write out the size in the byte of the array of 'ranlib'
|
||||
* descriptors to follow.
|
||||
*/
|
||||
|
||||
br_sz = (long) (bsdar->s_cnt * 2 * sizeof(long));
|
||||
write_data(bsdar, a, &br_sz, sizeof(long));
|
||||
|
||||
/*
|
||||
* Write out the array of 'ranlib' descriptors. Each
|
||||
* descriptor comprises of (a) an offset into the following
|
||||
* string table and (b) a file offset to the relevant member.
|
||||
*/
|
||||
for (i = 0, s = bsdar->s_sn; i < bsdar->s_cnt; i++) {
|
||||
br_strx = (long) (s - bsdar->s_sn);
|
||||
br_off = (long) bsdar->s_so[i];
|
||||
write_data(bsdar, a, &br_strx, sizeof(long));
|
||||
write_data(bsdar, a, &br_off, sizeof(long));
|
||||
|
||||
/* Find the start of the next symbol in the string table. */
|
||||
while (*s++ != '\0')
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out the size of the string table as a 'long',
|
||||
* followed by the string table itself.
|
||||
*/
|
||||
br_sz = (long) bsdar->s_sn_sz;
|
||||
write_data(bsdar, a, &br_sz, sizeof(long));
|
||||
write_data(bsdar, a, bsdar->s_sn, bsdar->s_sn_sz);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write the resulting archive members.
|
||||
*/
|
||||
static void
|
||||
write_objs(struct bsdar *bsdar)
|
||||
{
|
||||
struct ar_obj *obj;
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
size_t s_sz; /* size of archive symbol table. */
|
||||
size_t pm_sz; /* size of pseudo members */
|
||||
size_t namelen; /* size of member name. */
|
||||
size_t obj_sz; /* size of object + extended header. */
|
||||
int i;
|
||||
char *buf;
|
||||
const char *entry_name;
|
||||
|
||||
bsdar->rela_off = 0;
|
||||
|
||||
/*
|
||||
* Create the archive symbol table and the archive string
|
||||
* table, if needed.
|
||||
*/
|
||||
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
|
||||
if (!(bsdar->options & AR_SS) && obj->elf != NULL)
|
||||
create_symtab_entry(bsdar, obj->elf);
|
||||
|
||||
obj_sz = 0;
|
||||
namelen = strlen(obj->name);
|
||||
if (bsdar->options & AR_BSD) {
|
||||
/* Account for the space used by the file name. */
|
||||
if (namelen > _MAXNAMELEN_BSD ||
|
||||
strchr(obj->name, ' '))
|
||||
obj_sz += namelen;
|
||||
} else if (namelen > _MAXNAMELEN_SVR4)
|
||||
add_to_ar_str_table(bsdar, obj->name);
|
||||
|
||||
obj_sz += obj->size; /* add the actual object size */
|
||||
|
||||
/* Roundup the final size and add the header length. */
|
||||
bsdar->rela_off += _ARHDR_LEN + obj_sz + (obj_sz & 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pad the symbol name string table. It is treated specially
|
||||
* because symbol name table should be padded by a '\0', and
|
||||
* not '\n' as for normal members. The size of the 'sn' table
|
||||
* includes the pad byte.
|
||||
*/
|
||||
if (bsdar->s_cnt != 0 && bsdar->s_sn_sz % 2 != 0)
|
||||
bsdar->s_sn[bsdar->s_sn_sz++] = '\0';
|
||||
|
||||
/*
|
||||
* The archive string table is padded by a "\n" like a normal
|
||||
* member. The difference is that the size of archive string
|
||||
* table includes the pad byte, while normal members' size
|
||||
* fields do not.
|
||||
*/
|
||||
if (bsdar->as != NULL && bsdar->as_sz % 2 != 0)
|
||||
bsdar->as[bsdar->as_sz++] = '\n';
|
||||
|
||||
/*
|
||||
* If there is a symbol table, calculate the size of pseudo
|
||||
* members, and convert previously stored relative offsets to
|
||||
* absolute ones.
|
||||
*
|
||||
* absolute_offset = relative_offset + size_of_pseudo_members)
|
||||
*/
|
||||
|
||||
s_sz = bsdar_symtab_size(bsdar);
|
||||
if (bsdar->s_cnt != 0) {
|
||||
pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz);
|
||||
if (bsdar->as != NULL) /* SVR4 archives only */
|
||||
pm_sz += _ARHDR_LEN + bsdar->as_sz;
|
||||
for (i = 0; (size_t) i < bsdar->s_cnt; i++)
|
||||
bsdar->s_so[i] = bsdar->s_so[i] + pm_sz;
|
||||
}
|
||||
|
||||
if ((a = archive_write_new()) == NULL)
|
||||
bsdar_errc(bsdar, 0, "archive_write_new failed");
|
||||
|
||||
if (bsdar->options & AR_BSD)
|
||||
archive_write_set_format_ar_bsd(a);
|
||||
else
|
||||
archive_write_set_format_ar_svr4(a);
|
||||
archive_write_set_compression_none(a);
|
||||
|
||||
AC(archive_write_open_filename(a, bsdar->filename));
|
||||
|
||||
/*
|
||||
* Write the archive symbol table, if there is one. If
|
||||
* options '-s' was explicitly specified or if we were invoked
|
||||
* as 'ranlib', write the symbol table even if it is empty.
|
||||
*/
|
||||
if ((bsdar->s_cnt != 0 && !(bsdar->options & AR_SS)) ||
|
||||
bsdar->options & AR_S) {
|
||||
if (bsdar->options & AR_BSD)
|
||||
entry_name = AR_SYMTAB_NAME_BSD;
|
||||
else
|
||||
entry_name = AR_SYMTAB_NAME_SVR4;
|
||||
|
||||
entry = archive_entry_new();
|
||||
archive_entry_copy_pathname(entry, entry_name);
|
||||
if ((bsdar->options & AR_D) == 0)
|
||||
archive_entry_set_mtime(entry, time(NULL), 0);
|
||||
archive_entry_set_size(entry, s_sz);
|
||||
AC(archive_write_header(a, entry));
|
||||
if (bsdar->options & AR_BSD)
|
||||
write_bsd_symtab_entry(bsdar, a);
|
||||
else
|
||||
write_svr4_symtab_entry(bsdar, a);
|
||||
archive_entry_free(entry);
|
||||
}
|
||||
|
||||
/* Write the archive string table, if any. */
|
||||
if (bsdar->as != NULL) {
|
||||
entry = archive_entry_new();
|
||||
archive_entry_copy_pathname(entry, AR_STRINGTAB_NAME_SVR4);
|
||||
archive_entry_set_size(entry, bsdar->as_sz);
|
||||
AC(archive_write_header(a, entry));
|
||||
write_data(bsdar, a, bsdar->as, bsdar->as_sz);
|
||||
archive_entry_free(entry);
|
||||
}
|
||||
|
||||
/* Write normal members. */
|
||||
TAILQ_FOREACH(obj, &bsdar->v_obj, objs) {
|
||||
if ((buf = elf_rawfile(obj->elf, NULL)) == NULL) {
|
||||
bsdar_warnc(bsdar, 0, "elf_rawfile() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
|
||||
entry = archive_entry_new();
|
||||
archive_entry_copy_pathname(entry, obj->name);
|
||||
archive_entry_set_uid(entry, obj->uid);
|
||||
archive_entry_set_gid(entry, obj->gid);
|
||||
archive_entry_set_mode(entry, obj->md);
|
||||
archive_entry_set_size(entry, obj->size);
|
||||
archive_entry_set_mtime(entry, obj->mtime, 0);
|
||||
archive_entry_set_dev(entry, obj->dev);
|
||||
archive_entry_set_ino(entry, obj->ino);
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
AC(archive_write_header(a, entry));
|
||||
write_data(bsdar, a, buf, obj->size);
|
||||
archive_entry_free(entry);
|
||||
}
|
||||
|
||||
AC(archive_write_close(a));
|
||||
ACV(archive_write_finish(a));
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract global symbols from ELF binary members.
|
||||
*/
|
||||
static void
|
||||
create_symtab_entry(struct bsdar *bsdar, Elf *e)
|
||||
{
|
||||
Elf_Scn *scn;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
Elf_Data *data;
|
||||
char *name;
|
||||
size_t n, shstrndx;
|
||||
int elferr, tabndx, len, i;
|
||||
|
||||
if (elf_kind(e) != ELF_K_ELF) {
|
||||
/* Silently a ignore non-ELF member. */
|
||||
return;
|
||||
}
|
||||
if (elf_getshstrndx(e, &shstrndx) == 0) {
|
||||
bsdar_warnc(bsdar, 0, "elf_getshstrndx failed: %s",
|
||||
elf_errmsg(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
tabndx = -1;
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||
bsdar_warnc(bsdar, 0,
|
||||
"elf_getshdr failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) {
|
||||
bsdar_warnc(bsdar, 0,
|
||||
"elf_strptr failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, ".strtab") == 0) {
|
||||
tabndx = elf_ndxscn(scn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s",
|
||||
elf_errmsg(elferr));
|
||||
if (tabndx == -1) {
|
||||
bsdar_warnc(bsdar, 0, "can't find .strtab section");
|
||||
return;
|
||||
}
|
||||
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||
bsdar_warnc(bsdar, 0, "elf_getshdr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (shdr.sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
|
||||
data = NULL;
|
||||
n = 0;
|
||||
while (n < shdr.sh_size &&
|
||||
(data = elf_getdata(scn, data)) != NULL) {
|
||||
len = data->d_size / shdr.sh_entsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (gelf_getsym(data, i, &sym) != &sym) {
|
||||
bsdar_warnc(bsdar, 0,
|
||||
"gelf_getsym failed: %s",
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Keep only global and weak symbols. */
|
||||
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL &&
|
||||
GELF_ST_BIND(sym.st_info) != STB_WEAK)
|
||||
continue;
|
||||
|
||||
/* Keep only defined symbols. */
|
||||
if (sym.st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
if ((name = elf_strptr(e, tabndx,
|
||||
sym.st_name)) == NULL) {
|
||||
bsdar_warnc(bsdar, 0,
|
||||
"elf_strptr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
|
||||
add_to_ar_sym_table(bsdar, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
bsdar_warnc(bsdar, 0, "elf_nextscn failed: %s",
|
||||
elf_errmsg(elferr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Append to the archive string table buffer.
|
||||
*/
|
||||
static void
|
||||
add_to_ar_str_table(struct bsdar *bsdar, const char *name)
|
||||
{
|
||||
|
||||
if (bsdar->as == NULL) {
|
||||
bsdar->as_cap = _INIT_AS_CAP;
|
||||
bsdar->as_sz = 0;
|
||||
if ((bsdar->as = malloc(bsdar->as_cap)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* The space required for holding one member name in the 'as'
|
||||
* table includes: strlen(name) + (1 for '/') + (1 for '\n') +
|
||||
* (possibly 1 for padding).
|
||||
*/
|
||||
while (bsdar->as_sz + strlen(name) + 3 > bsdar->as_cap) {
|
||||
bsdar->as_cap *= 2;
|
||||
bsdar->as = realloc(bsdar->as, bsdar->as_cap);
|
||||
if (bsdar->as == NULL)
|
||||
bsdar_errc(bsdar, errno, "realloc failed");
|
||||
}
|
||||
strncpy(&bsdar->as[bsdar->as_sz], name, strlen(name));
|
||||
bsdar->as_sz += strlen(name);
|
||||
bsdar->as[bsdar->as_sz++] = '/';
|
||||
bsdar->as[bsdar->as_sz++] = '\n';
|
||||
}
|
||||
|
||||
/*
|
||||
* Append to the archive symbol table buffer.
|
||||
*/
|
||||
static void
|
||||
add_to_ar_sym_table(struct bsdar *bsdar, const char *name)
|
||||
{
|
||||
|
||||
if (bsdar->s_so == NULL) {
|
||||
if ((bsdar->s_so = malloc(_INIT_SYMOFF_CAP)) ==
|
||||
NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
bsdar->s_so_cap = _INIT_SYMOFF_CAP;
|
||||
bsdar->s_cnt = 0;
|
||||
}
|
||||
|
||||
if (bsdar->s_sn == NULL) {
|
||||
if ((bsdar->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL)
|
||||
bsdar_errc(bsdar, errno, "malloc failed");
|
||||
bsdar->s_sn_cap = _INIT_SYMNAME_CAP;
|
||||
bsdar->s_sn_sz = 0;
|
||||
}
|
||||
|
||||
if (bsdar->s_cnt * sizeof(uint32_t) >= bsdar->s_so_cap) {
|
||||
bsdar->s_so_cap *= 2;
|
||||
bsdar->s_so = realloc(bsdar->s_so, bsdar->s_so_cap);
|
||||
if (bsdar->s_so == NULL)
|
||||
bsdar_errc(bsdar, errno, "realloc failed");
|
||||
}
|
||||
bsdar->s_so[bsdar->s_cnt] = bsdar->rela_off;
|
||||
bsdar->s_cnt++;
|
||||
|
||||
/*
|
||||
* The space required for holding one symbol name in the 'sn'
|
||||
* table includes: strlen(name) + (1 for '\n') + (possibly 1
|
||||
* for padding).
|
||||
*/
|
||||
while (bsdar->s_sn_sz + strlen(name) + 2 > bsdar->s_sn_cap) {
|
||||
bsdar->s_sn_cap *= 2;
|
||||
bsdar->s_sn = realloc(bsdar->s_sn, bsdar->s_sn_cap);
|
||||
if (bsdar->s_sn == NULL)
|
||||
bsdar_errc(bsdar, errno, "realloc failed");
|
||||
}
|
||||
strncpy(&bsdar->s_sn[bsdar->s_sn_sz], name, strlen(name));
|
||||
bsdar->s_sn_sz += strlen(name);
|
||||
bsdar->s_sn[bsdar->s_sn_sz++] = '\0';
|
||||
}
|
14
as/Makefile
Normal file
14
as/Makefile
Normal file
|
@ -0,0 +1,14 @@
|
|||
# $Id: Makefile 2797 2012-12-21 18:10:25Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= as
|
||||
SRCS= as.c
|
||||
|
||||
LSRC=
|
||||
YSRC=
|
||||
LDADD= -lelftc
|
||||
|
||||
MAN= as.1
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
211
as/as.1
Normal file
211
as/as.1
Normal file
|
@ -0,0 +1,211 @@
|
|||
.\" Copyright (c) 2012 Joseph Koshy <jkoshy@users.sourceforge.net>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer
|
||||
.\" in this position and unchanged.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: as.1 2798 2012-12-22 09:02:50Z jkoshy $
|
||||
.\"
|
||||
.Dd December 22, 2012
|
||||
.Os
|
||||
.Dt AS 1
|
||||
.Sh NAME
|
||||
.Nm as
|
||||
.Nd an assembler
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl D
|
||||
.Op Fl I Ar dir
|
||||
.Op Fl J
|
||||
.Op Fl K
|
||||
.Op Fl L | Fl -keep-locals
|
||||
.Op Fl R
|
||||
.Op Fl V
|
||||
.Op Fl W | Fl -no-warn
|
||||
.Op Fl Z
|
||||
.Op Fl a Ns Oo Ar cdghlns Oc Ns Oo Ar =filename Oc
|
||||
.Op Fl g | Fl -gen-debug
|
||||
.Op Fl h | Fl -help
|
||||
.Op Fl march= Ns Ar cpu Ns Oo ,+ Ns Oo Ar extensions Oc Ns "..." Oc
|
||||
.Op Fl mtune= Ns Ar cpu
|
||||
.Op Fl n
|
||||
.Op Fl o Ar obj
|
||||
.Op Fl q
|
||||
.Op Fl -MD Ar file
|
||||
.Op Fl -defsym Ar symbol Ns = Ns Ar value
|
||||
.Op Fl -fatal-warnings
|
||||
.Op Fl -listing-lhs-width
|
||||
.Op Fl -listing-lhs-width2
|
||||
.Op Fl -listing-rhs-width
|
||||
.Op Fl -listing-cont-lines
|
||||
.Op Fl -statistics
|
||||
.Op Fl -strip-local-absolute
|
||||
.Op Fl -target-help
|
||||
.Op Fl -version
|
||||
.Op Fl -warn
|
||||
.Op Ar target-options
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility creates an ELF relocatable object from assembly language
|
||||
sources.
|
||||
.Pp
|
||||
If multiple source files are specified,
|
||||
.Nm
|
||||
will read each of them in the order specified.
|
||||
If no files are specified,
|
||||
.Nm
|
||||
will read from standard input.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility understands the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl D
|
||||
Display internal debugging messages.
|
||||
.It Fl I Ar dir
|
||||
Add the directory named by argument
|
||||
.Ar dir
|
||||
to the search path used by the
|
||||
.Ic ".include"
|
||||
directive.
|
||||
.It Fl J
|
||||
Suppress warnings about overflows in signed arithmetic.
|
||||
.It Fl K
|
||||
Warn about alterations to difference tables if any.
|
||||
.It Fl L | Fl -keep-locals
|
||||
Keep local symbols in the output file.
|
||||
The default is to discard local symbols.
|
||||
.It Fl R
|
||||
Merge the
|
||||
.Li .data
|
||||
and
|
||||
.Li .text
|
||||
sections when creating an object.
|
||||
.It Fl V
|
||||
Print the assembler version on standard output before assembling
|
||||
the inputs.
|
||||
.It Fl W | Fl -no-warn
|
||||
Suppress assembler warnings.
|
||||
.It Fl Z
|
||||
Generate an output object even if there were errors in the input.
|
||||
.It Fl a Ns Oo Ar cdghlns Oc Ns Oo Ar =filename Oc
|
||||
Control generated listings.
|
||||
The supported flags are:
|
||||
.Bl -tag -width indent -compact
|
||||
.It c
|
||||
Omit listing code in false conditional paths.
|
||||
.It d
|
||||
Omit debugging directives.
|
||||
.It g
|
||||
Include the version of the assembler and other general information
|
||||
in the generated listing.
|
||||
.It h
|
||||
Include high-level source in the listing.
|
||||
.It l
|
||||
Include assembly source in the listing.
|
||||
.It m
|
||||
Include macro expansions in the listing.
|
||||
.It n
|
||||
Suppress generation of the header and footer in the listing.
|
||||
.It s
|
||||
Include symbol information in the listing.
|
||||
.It = Ns Ar filename
|
||||
Set the name of the listing file to that specified by argument
|
||||
.Ar filename .
|
||||
If specified, this flag must be the last in the list.
|
||||
.El
|
||||
If option
|
||||
.Fl a
|
||||
is specified without additional arguments, a flag set of
|
||||
.Sq Ar hls
|
||||
is assumed.
|
||||
.It Fl g | Fl -gen-debug
|
||||
Generate debug information in DWARF format.
|
||||
.It Fl h | Fl -help
|
||||
Show a help message and exit.
|
||||
.It Fl march Ns = Ns Ar cpu Ns Oo ,+ Ns Oo Ar extensions Oc Ns "..." Oc
|
||||
Generated code for the CPU named by argument
|
||||
.Ar cpu
|
||||
with additional instruction set extensions named by the argument
|
||||
.Ar extensions .
|
||||
.It Fl mtune Ns = Ns Ar cpu
|
||||
Optimize the assembled object for the CPU named by the argument
|
||||
.Ar cpu .
|
||||
.It Fl n
|
||||
Do not optimize code alignment.
|
||||
.It Fl o Ar filename
|
||||
Write the assembled output to the file named by argument
|
||||
.Ar filename .
|
||||
.It Fl q
|
||||
Suppress warnings.
|
||||
.It Fl -MD Ar filename
|
||||
Write dependency information in a form usable by
|
||||
.Xr make 1
|
||||
to the file name by argument
|
||||
.Ar filename .
|
||||
.It Fl -defsym Ar symbol Ns = Ns Ar value
|
||||
Define symbol named by the argument
|
||||
.Ar symbol
|
||||
as having the value named by
|
||||
.Ar value .
|
||||
The argument value is an integer in one of the forms accepted
|
||||
by
|
||||
.Xr atoi 3 .
|
||||
.It Fl -fatal-warnings
|
||||
Treat all warnings as fatal.
|
||||
.It Fl -listing-lhs-width Ns = Ns Ar nwords
|
||||
Set the width of the output data column in a listing to the number
|
||||
of machine words specified in argument
|
||||
.Ar nwords .
|
||||
.It Fl -listing-lhs-width2 Ns = Ns Ar nwords
|
||||
Set the width of continuation lines for the data column to the number
|
||||
of machine words specified in argument
|
||||
.Ar nwords .
|
||||
.It Fl -listing-rhs-width Ns = Ns Ar nchars
|
||||
Set the maximum displayed width of an input source line to the number
|
||||
of characters specified by argument
|
||||
.Ar nchars .
|
||||
.It Fl -listing-cont-lines Ns = Ns Ar nlines
|
||||
Set the maximum number of listing lines generated by one input source
|
||||
line to
|
||||
.Ar nlines Ns No + Ns 1 .
|
||||
.It Fl -statistics
|
||||
Print statistics for the run at exit.
|
||||
.It Fl -strip-local-absolute
|
||||
Remove local absolute symbols from the generated output.
|
||||
.It Fl -target-help
|
||||
Display help for the target CPU.
|
||||
.It Fl -version
|
||||
Print a version identifier and exit.
|
||||
.It Fl -warn
|
||||
Print warnings.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr elfcopy 1 ,
|
||||
.Xr ld 1 ,
|
||||
.Xr nm 1 ,
|
||||
.Xr strings 1 ,
|
||||
.Xr strip 1 ,
|
||||
.Xr elf 5
|
216
as/as.c
Normal file
216
as/as.c
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Joseph Koshy
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
#include <libelftc.h>
|
||||
|
||||
ELFTC_VCSID("$Id: as.c 2799 2012-12-22 09:03:29Z jkoshy $");
|
||||
|
||||
enum as_long_option_index {
|
||||
AS_OPT_DEFSYM,
|
||||
AS_OPT_FATAL_WARNINGS,
|
||||
AS_OPT_LCL,
|
||||
AS_OPT_LLW,
|
||||
AS_OPT_LLW2,
|
||||
AS_OPT_LRW,
|
||||
AS_OPT_MD,
|
||||
AS_OPT_STATISTICS,
|
||||
AS_OPT_STRIP_LOCAL_ABSOLUTE,
|
||||
AS_OPT_TARGET_HELP,
|
||||
AS_OPT_VERSION,
|
||||
AS_OPT_WARN,
|
||||
AS_OPT__LAST
|
||||
};
|
||||
|
||||
struct as_options {
|
||||
unsigned int as_listing_flags;
|
||||
};
|
||||
|
||||
#define AS_OPTION_SHORT_OPTIONS ":a:fghm:no:qswDI:JKLMRVWXZ"
|
||||
const struct option as_option_long_options[] = {
|
||||
{ "defsym", required_argument, NULL, AS_OPT_DEFSYM },
|
||||
{ "fatal-warnings", no_argument, NULL, AS_OPT_FATAL_WARNINGS },
|
||||
{ "gen-debug", no_argument, NULL, 'g' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "keep-locals", no_argument, NULL, 'L' },
|
||||
{ "listing-lhs-width", required_argument, NULL, AS_OPT_LLW },
|
||||
{ "listing-lhs-width2", required_argument, NULL, AS_OPT_LLW2 },
|
||||
{ "listing-rhs-width", required_argument, NULL, AS_OPT_LRW },
|
||||
{ "listing-cont-lines", required_argument, NULL, AS_OPT_LCL },
|
||||
{ "mri", no_argument, NULL, 'M' },
|
||||
{ "no-warn", no_argument, NULL, 'W' },
|
||||
{ "statistics", no_argument, NULL, AS_OPT_STATISTICS },
|
||||
{ "strip-local-absolute", no_argument, NULL,
|
||||
AS_OPT_STRIP_LOCAL_ABSOLUTE },
|
||||
{ "target-help", no_argument, NULL, AS_OPT_TARGET_HELP },
|
||||
{ "version", no_argument, NULL, AS_OPT_VERSION },
|
||||
{ "warn", no_argument, NULL, AS_OPT_WARN },
|
||||
{ "MD", required_argument, NULL, AS_OPT_MD },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
#define AS_OPTION_LISTING_DEFAULT "hls"
|
||||
|
||||
#define AS_OPTION_USAGE_MESSAGE "\
|
||||
Usage: %s [options] file...\n\
|
||||
Assemble an ELF object.\n\n\
|
||||
Options:\n\
|
||||
-D Print assembler debug messages.\n\
|
||||
-I DIR Add directory to the search list.\n\
|
||||
-J Suppress warnings about signed overflows.\n\
|
||||
-K Warn about alterations to difference tables.\n\
|
||||
-L | --keep-locals Keep local symbols.\n\
|
||||
-R Merge the data and text sections.\n\
|
||||
-V Display the assembler version number.\n\
|
||||
-W | --no-warn Suppress warnings.\n\
|
||||
-Z Generate the object even if there are errors.\n\
|
||||
-a[listing-options...] Control assembler listings.\n\
|
||||
-g | --gen-debug Generate debugging information.\n\
|
||||
-h | --help Show a help message.\n\
|
||||
-march=CPU[,+EXT...] Generate code for cpu CPU and extensions EXT.\n\
|
||||
-mtune=CPU Optimize for cpu CPU.\n\
|
||||
-n Do not optimize code alignment.\n\
|
||||
-o OBJ Write the assembled object to file OBJ.\n\
|
||||
-q Suppress some warnings.\n\
|
||||
--MD FILE Write dependency information to FILE.\n\
|
||||
--defsym SYMBOL=VALUE Define symbol SYMBOL with value VALUE.\n\
|
||||
--fatal-warnings Treat warnings as fatal errors.\n\
|
||||
--listing-lhs-width=NUM Set width of the output data column.\n\
|
||||
--listing-lhs-width2=NUM Set the width of continuation lines.\n\
|
||||
--listing-rhs-width=NUM Set the max width of source lines.\n\
|
||||
--listing-cont-lines=NUM Set the maximum number of continuation lines.\n\
|
||||
--statistics Print statistics at exit.\n\
|
||||
--strip-local-absolute Strip local absolute symbols.\n\
|
||||
--target-help Show target-specific help messages.\n\
|
||||
--version Print a version identifier and exit.\n\
|
||||
--warn Print warnings.\n\
|
||||
[target options] Target specific options.\n\n\
|
||||
Options '-f', '-s', '-w', '-M', '-X' and '--mri' are accepted for\n\
|
||||
compatibility with other assemblers, but are ignored.\n"
|
||||
|
||||
void
|
||||
as_option_usage(int iserror, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (format) {
|
||||
va_start(args, format);
|
||||
vwarnx(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
(void) fprintf(iserror ? stderr : stdout,
|
||||
AS_OPTION_USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
|
||||
exit(iserror != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
as_option_listing(char *flags)
|
||||
{
|
||||
(void) flags;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int option, option_index;
|
||||
|
||||
opterr = 0; /* Suppress error messages from getopt(). */
|
||||
|
||||
for (option_index = -1;
|
||||
(option = getopt_long(argc, argv, AS_OPTION_SHORT_OPTIONS,
|
||||
as_option_long_options, &option_index)) >= 0;
|
||||
option_index = -1)
|
||||
{
|
||||
switch (option) {
|
||||
|
||||
case AS_OPT_VERSION:
|
||||
/*
|
||||
* Print a version identifier and exit.
|
||||
*/
|
||||
(void) printf("%s (%s)\n",
|
||||
ELFTC_GETPROGNAME(), elftc_version());
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'h': /* Display a help message. */
|
||||
as_option_usage(0, NULL);
|
||||
break;
|
||||
|
||||
case 'f': case 's': case 'w': case 'M': case 'X':
|
||||
/*
|
||||
* These options are accepted for compatibility
|
||||
* reasons, but are ignored.
|
||||
*/
|
||||
break;
|
||||
|
||||
case ':':
|
||||
|
||||
/*
|
||||
* A missing option argument: if the user
|
||||
* supplied a bare '-a', supply a default set
|
||||
* of listing control flags.
|
||||
*/
|
||||
if (optopt == 'a')
|
||||
as_option_listing(AS_OPTION_LISTING_DEFAULT);
|
||||
else
|
||||
errx(1, "option \"-%c\" expects an "
|
||||
"argument.", optopt);
|
||||
break;
|
||||
|
||||
case '?': /* An unknown option. */
|
||||
if (optopt)
|
||||
as_option_usage(1,
|
||||
"ERROR: unrecognized option '-%c'.",
|
||||
optopt);
|
||||
else
|
||||
as_option_usage(1,
|
||||
"ERROR: Unrecognized option \"--%s\".",
|
||||
argv[optind-1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (option_index >= 0)
|
||||
errx(1,
|
||||
"ERROR: option \"--%s\" is unimplemented.",
|
||||
as_option_long_options[option_index]);
|
||||
else
|
||||
errx(1,
|
||||
"ERROR: option '-%c' is unimplemented.",
|
||||
option);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
9
brandelf/Makefile
Normal file
9
brandelf/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
# $Id: Makefile 2066 2011-10-26 15:40:28Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= brandelf
|
||||
WARNS?= 6
|
||||
LDADD= -lelftc -lelf
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
149
brandelf/brandelf.1
Normal file
149
brandelf/brandelf.1
Normal file
|
@ -0,0 +1,149 @@
|
|||
.\" Copyright (c) 1997
|
||||
.\" John-Mark Gurney. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 3. Neither the name of the author nor the names of any co-contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY John-Mark Gurney AND CONTRIBUTORS ``AS IS''
|
||||
.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD: src/usr.bin/brandelf/brandelf.1,v 1.17 2007/03/09 14:36:18 ru Exp $
|
||||
.\" $Id: brandelf.1 2245 2011-11-29 08:11:00Z jkoshy $
|
||||
.\"
|
||||
.Dd November 29, 2011
|
||||
.Dt BRANDELF 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm brandelf
|
||||
.Nd mark an ELF binary for a specific ABI
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl V | Fl -version
|
||||
.Op Fl f Ar ELF_ABI_number
|
||||
.Op Fl h | Fl -help
|
||||
.Op Fl l
|
||||
.Op Fl t Ar brand
|
||||
.Op Fl v
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility marks an ELF binary to be run under a certain ABI.
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width indent
|
||||
.It Fl f Ar ELF_ABI_number
|
||||
Forces branding with the supplied ELF ABI number.
|
||||
Incompatible with the
|
||||
.Fl t
|
||||
option.
|
||||
These values are assigned by SCO/USL.
|
||||
.It Fl h | Fl -help
|
||||
Print a usage message and exit.
|
||||
.It Fl l
|
||||
Writes the list of all known ELF types to standard output.
|
||||
.It Fl t Ar brand
|
||||
Brands the given ELF binaries to be of the ABI specified by argument
|
||||
.Ar brand .
|
||||
Supported ABIs include
|
||||
.Dq Li 86Open ,
|
||||
.Dq Li AIX ,
|
||||
.Dq Li ARM ,
|
||||
.Dq Li AROS ,
|
||||
.Dq Li FreeBSD ,
|
||||
.Dq Li GNU ,
|
||||
.Dq Li HP/UX ,
|
||||
.Dq Li Hurd ,
|
||||
.Dq Li IRIX ,
|
||||
.Dq Li Linux
|
||||
(an alias for
|
||||
.Dq Li GNU ) ,
|
||||
.Dq Li Modesto ,
|
||||
.Dq Li NSK ,
|
||||
.Dq Li NetBSD ,
|
||||
.Dq Li None ,
|
||||
.Dq Li OpenBSD ,
|
||||
.Dq Li OpenVMS ,
|
||||
.Dq Li Standalone ,
|
||||
.Dq Li SVR4
|
||||
(an alias for
|
||||
.Dq Li None ) ,
|
||||
.Dq Li Solaris
|
||||
and
|
||||
.Dq Li Tru64 .
|
||||
.It Fl v
|
||||
Turns on verbose output.
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier and exit.
|
||||
.El
|
||||
.Pp
|
||||
If the options
|
||||
.Fl f Ar ELF_ABI_number
|
||||
or
|
||||
.Fl t Ar brand
|
||||
were specified,
|
||||
.Nm
|
||||
will brand the files named by command-line arguments
|
||||
.Ar
|
||||
to be of type
|
||||
.Ar ELF_ABI_number
|
||||
or
|
||||
.Ar brand
|
||||
respectively.
|
||||
.Pp
|
||||
If neither of the
|
||||
.Fl f
|
||||
or
|
||||
.Fl t
|
||||
options were specified,
|
||||
.Nm
|
||||
will display the current branding for the files named by the arguments
|
||||
.Ar .
|
||||
.Sh EXIT STATUS
|
||||
Exit status is 0 on success, and 1 if the command
|
||||
fails if a file does not exist, is too short, fails to brand properly,
|
||||
or the brand requested is not one of the known types and the
|
||||
.Fl f
|
||||
option is not set.
|
||||
.Sh EXAMPLES
|
||||
The following is an example of a typical usage
|
||||
of the
|
||||
.Nm
|
||||
command:
|
||||
.Bd -literal -offset indent
|
||||
brandelf file
|
||||
brandelf -t GNU file
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Rs
|
||||
.%A The Santa Cruz Operation, Inc.
|
||||
.%T System V Application Binary Interface
|
||||
.%D April 29, 1998 (DRAFT)
|
||||
.%O http://www.sco.com/developer/devspecs/
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
manual page first appeared in
|
||||
.Fx 2.2 .
|
||||
.Sh AUTHORS
|
||||
This manual page was written by
|
||||
.An John-Mark Gurney Aq gurney_j@efn.org .
|
314
brandelf/brandelf.c
Normal file
314
brandelf/brandelf.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*-
|
||||
* Copyright (c) 2008 Hyogeol Lee
|
||||
* Copyright (c) 2000, 2001 David O'Brien
|
||||
* Copyright (c) 1996 Søren Schmidt
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h>
|
||||
#include <getopt.h>
|
||||
#include <libelf.h>
|
||||
#include <libelftc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
ELFTC_VCSID("$Id: brandelf.c 2324 2011-12-12 06:36:27Z jkoshy $");
|
||||
|
||||
static int elftype(const char *);
|
||||
static const char *iselftype(int);
|
||||
static void printelftypes(void);
|
||||
static void printversion(void);
|
||||
static void usage(void);
|
||||
|
||||
struct ELFtypes {
|
||||
const char *str;
|
||||
int value;
|
||||
};
|
||||
/* XXX - any more types? */
|
||||
static struct ELFtypes elftypes[] = {
|
||||
{ "86Open", ELFOSABI_86OPEN },
|
||||
{ "AIX", ELFOSABI_AIX },
|
||||
{ "ARM", ELFOSABI_ARM },
|
||||
{ "AROS", ELFOSABI_AROS },
|
||||
{ "FreeBSD", ELFOSABI_FREEBSD },
|
||||
{ "GNU", ELFOSABI_GNU },
|
||||
{ "HP/UX", ELFOSABI_HPUX},
|
||||
{ "Hurd", ELFOSABI_HURD },
|
||||
{ "IRIX", ELFOSABI_IRIX },
|
||||
{ "Linux", ELFOSABI_GNU },
|
||||
{ "Modesto", ELFOSABI_MODESTO },
|
||||
{ "NSK", ELFOSABI_NSK },
|
||||
{ "NetBSD", ELFOSABI_NETBSD},
|
||||
{ "None", ELFOSABI_NONE},
|
||||
{ "OpenBSD", ELFOSABI_OPENBSD },
|
||||
{ "OpenVMS", ELFOSABI_OPENVMS },
|
||||
{ "Standalone", ELFOSABI_STANDALONE },
|
||||
{ "SVR4", ELFOSABI_NONE },
|
||||
{ "Solaris", ELFOSABI_SOLARIS },
|
||||
{ "Tru64", ELFOSABI_TRU64 }
|
||||
};
|
||||
|
||||
static struct option brandelf_longopts[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
GElf_Ehdr ehdr;
|
||||
Elf *elf;
|
||||
Elf_Kind kind;
|
||||
int type = ELFOSABI_NONE;
|
||||
int retval = 0;
|
||||
int ch, change = 0, verbose = 0, force = 0, listed = 0;
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "elf_version error");
|
||||
|
||||
while ((ch = getopt_long(argc, argv, "Vf:hlt:v", brandelf_longopts,
|
||||
NULL)) != -1)
|
||||
switch (ch) {
|
||||
case 'f':
|
||||
if (change)
|
||||
errx(EXIT_FAILURE, "ERROR: the -f option is "
|
||||
"incompatible with the -t option.");
|
||||
force = 1;
|
||||
type = atoi(optarg);
|
||||
if (errno == ERANGE || type < 0 || type > 255) {
|
||||
warnx("ERROR: invalid argument to option "
|
||||
"-f: %s", optarg);
|
||||
usage();
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
break;
|
||||
case 'l':
|
||||
printelftypes();
|
||||
listed = 1;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 't':
|
||||
if (force)
|
||||
errx(EXIT_FAILURE, "the -t option is "
|
||||
"incompatible with the -f option.");
|
||||
if ((type = elftype(optarg)) == -1) {
|
||||
warnx("ERROR: invalid ELF type '%s'", optarg);
|
||||
usage();
|
||||
}
|
||||
|
||||
change = 1;
|
||||
break;
|
||||
case 'V':
|
||||
printversion();
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if (!argc) {
|
||||
if (listed)
|
||||
exit(0);
|
||||
else {
|
||||
warnx("no file(s) specified");
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
while (argc) {
|
||||
int fd;
|
||||
|
||||
elf = NULL;
|
||||
|
||||
if ((fd = open(argv[0], (change || force) ? O_RDWR :
|
||||
O_RDONLY, 0)) < 0) {
|
||||
warn("error opening file %s", argv[0]);
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((elf = elf_begin(fd, (change || force) ? ELF_C_RDWR :
|
||||
ELF_C_READ, NULL)) == NULL) {
|
||||
warnx("elf_begin failed: %s", elf_errmsg(-1));
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((kind = elf_kind(elf)) != ELF_K_ELF) {
|
||||
if (kind == ELF_K_AR)
|
||||
warnx("file '%s' is an archive.", argv[0]);
|
||||
else
|
||||
warnx("file '%s' is not an ELF file.",
|
||||
argv[0]);
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (gelf_getehdr(elf, &ehdr) == NULL) {
|
||||
warnx("gelf_getehdr: %s", elf_errmsg(-1));
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!change && !force) {
|
||||
fprintf(stdout,
|
||||
"File '%s' is of brand '%s' (%u).\n",
|
||||
argv[0], iselftype(ehdr.e_ident[EI_OSABI]),
|
||||
ehdr.e_ident[EI_OSABI]);
|
||||
if (!iselftype(type)) {
|
||||
warnx("ELF ABI Brand '%u' is unknown",
|
||||
type);
|
||||
printelftypes();
|
||||
}
|
||||
} else {
|
||||
|
||||
/*
|
||||
* Keep the existing layout of the ELF object.
|
||||
*/
|
||||
if (elf_flagelf(elf, ELF_C_SET, ELF_F_LAYOUT) == 0) {
|
||||
warnx("elf_flagelf failed: %s",
|
||||
elf_errmsg(-1));
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the ABI type.
|
||||
*/
|
||||
ehdr.e_ident[EI_OSABI] = type;
|
||||
if (gelf_update_ehdr(elf, &ehdr) == 0) {
|
||||
warnx("gelf_update_ehdr error: %s",
|
||||
elf_errmsg(-1));
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write back changes.
|
||||
*/
|
||||
if (elf_update(elf, ELF_C_WRITE) == -1) {
|
||||
warnx("elf_update error: %s", elf_errmsg(-1));
|
||||
retval = 1;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
fail:
|
||||
|
||||
if (elf)
|
||||
elf_end(elf);
|
||||
|
||||
if (fd >= 0 && close(fd) == -1) {
|
||||
warnx("%s: close error", argv[0]);
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
#define USAGE_MESSAGE "\
|
||||
Usage: %s [options] file...\n\
|
||||
Set or display the ABI field for an ELF object.\n\n\
|
||||
Supported options are:\n\
|
||||
-f NUM Set the ELF ABI to the number 'NUM'.\n\
|
||||
-h | --help Print a usage message and exit.\n\
|
||||
-l List known ELF ABI names.\n\
|
||||
-t ABI Set the ELF ABI to the value named by \"ABI\".\n\
|
||||
-v Be verbose.\n\
|
||||
-V | --version Print a version identifier and exit.\n"
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
printversion(void)
|
||||
{
|
||||
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
iselftype(int etype)
|
||||
{
|
||||
size_t elfwalk;
|
||||
|
||||
for (elfwalk = 0;
|
||||
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
|
||||
elfwalk++)
|
||||
if (etype == elftypes[elfwalk].value)
|
||||
return (elftypes[elfwalk].str);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
elftype(const char *elfstrtype)
|
||||
{
|
||||
size_t elfwalk;
|
||||
|
||||
for (elfwalk = 0;
|
||||
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
|
||||
elfwalk++)
|
||||
if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0)
|
||||
return (elftypes[elfwalk].value);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static void
|
||||
printelftypes(void)
|
||||
{
|
||||
size_t elfwalk;
|
||||
|
||||
(void) printf("Known ELF types are: ");
|
||||
for (elfwalk = 0;
|
||||
elfwalk < sizeof(elftypes)/sizeof(elftypes[0]);
|
||||
elfwalk++)
|
||||
(void) printf("%s(%u) ", elftypes[elfwalk].str,
|
||||
elftypes[elfwalk].value);
|
||||
(void) printf("\n");
|
||||
}
|
15
common/Makefile
Normal file
15
common/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $Id: Makefile 2606 2012-10-02 17:52:57Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
INCS= elfdefinitions.h
|
||||
INCSDIR= /usr/include
|
||||
|
||||
.PHONY: all clean clobber depend obj
|
||||
|
||||
all depend obj:
|
||||
|
||||
clean clobber:
|
||||
rm -f ${CLEANFILES}
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.inc.mk"
|
458
common/_elftc.h
Normal file
458
common/_elftc.h
Normal file
|
@ -0,0 +1,458 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 Joseph Koshy
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: _elftc.h 2922 2013-03-17 22:53:15Z kaiwang27 $
|
||||
*/
|
||||
|
||||
/**
|
||||
** Miscellanous definitions needed by multiple components.
|
||||
**/
|
||||
|
||||
#ifndef _ELFTC_H
|
||||
#define _ELFTC_H
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void *) 0)
|
||||
#endif
|
||||
|
||||
#ifndef offsetof
|
||||
#define offsetof(T, M) ((int) &((T*) 0) -> M)
|
||||
#endif
|
||||
|
||||
/* --QUEUE-MACROS-- [[ */
|
||||
|
||||
/*
|
||||
* Supply macros missing from <sys/queue.h>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef SLIST_FOREACH_SAFE
|
||||
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_CONCAT
|
||||
#define STAILQ_CONCAT(head1, head2) do { \
|
||||
if (!STAILQ_EMPTY((head2))) { \
|
||||
*(head1)->stqh_last = (head2)->stqh_first; \
|
||||
(head1)->stqh_last = (head2)->stqh_last; \
|
||||
STAILQ_INIT((head2)); \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_EMPTY
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_ENTRY
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_FIRST
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_HEAD
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first; /* first element */ \
|
||||
struct type **stqh_last; /* addr of last next element */ \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_HEAD_INITIALIZER
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_FOREACH
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = ((head)->stqh_first); \
|
||||
(var); \
|
||||
(var) = ((var)->field.stqe_next))
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_FOREACH_SAFE
|
||||
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = STAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_INIT
|
||||
#define STAILQ_INIT(head) do { \
|
||||
(head)->stqh_first = NULL; \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_INSERT_HEAD
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
(head)->stqh_first = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_INSERT_TAIL
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
(elm)->field.stqe_next = NULL; \
|
||||
*(head)->stqh_last = (elm); \
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_INSERT_AFTER
|
||||
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
|
||||
(head)->stqh_last = &(elm)->field.stqe_next; \
|
||||
(listelm)->field.stqe_next = (elm); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_LAST
|
||||
#define STAILQ_LAST(head, type, field) \
|
||||
(STAILQ_EMPTY((head)) ? \
|
||||
NULL : ((struct type *)(void *) \
|
||||
((char *)((head)->stqh_last) - offsetof(struct type, field))))
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_NEXT
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_REMOVE
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
if ((head)->stqh_first == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
} else { \
|
||||
struct type *curelm = (head)->stqh_first; \
|
||||
while (curelm->field.stqe_next != (elm)) \
|
||||
curelm = curelm->field.stqe_next; \
|
||||
if ((curelm->field.stqe_next = \
|
||||
curelm->field.stqe_next->field.stqe_next) == NULL) \
|
||||
(head)->stqh_last = &(curelm)->field.stqe_next; \
|
||||
} \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef STAILQ_REMOVE_HEAD
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == \
|
||||
NULL) \
|
||||
(head)->stqh_last = &(head)->stqh_first; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The STAILQ_SORT macro is adapted from Simon Tatham's O(n*log(n))
|
||||
* mergesort algorithm.
|
||||
*/
|
||||
#ifndef STAILQ_SORT
|
||||
#define STAILQ_SORT(head, type, field, cmp) do { \
|
||||
STAILQ_HEAD(, type) _la, _lb; \
|
||||
struct type *_p, *_q, *_e; \
|
||||
int _i, _sz, _nmerges, _psz, _qsz; \
|
||||
\
|
||||
_sz = 1; \
|
||||
do { \
|
||||
_nmerges = 0; \
|
||||
STAILQ_INIT(&_lb); \
|
||||
while (!STAILQ_EMPTY((head))) { \
|
||||
_nmerges++; \
|
||||
STAILQ_INIT(&_la); \
|
||||
_psz = 0; \
|
||||
for (_i = 0; _i < _sz && !STAILQ_EMPTY((head)); \
|
||||
_i++) { \
|
||||
_e = STAILQ_FIRST((head)); \
|
||||
if (_e == NULL) \
|
||||
break; \
|
||||
_psz++; \
|
||||
STAILQ_REMOVE_HEAD((head), field); \
|
||||
STAILQ_INSERT_TAIL(&_la, _e, field); \
|
||||
} \
|
||||
_p = STAILQ_FIRST(&_la); \
|
||||
_qsz = _sz; \
|
||||
_q = STAILQ_FIRST((head)); \
|
||||
while (_psz > 0 || (_qsz > 0 && _q != NULL)) { \
|
||||
if (_psz == 0) { \
|
||||
_e = _q; \
|
||||
_q = STAILQ_NEXT(_q, field); \
|
||||
STAILQ_REMOVE_HEAD((head), \
|
||||
field); \
|
||||
_qsz--; \
|
||||
} else if (_qsz == 0 || _q == NULL) { \
|
||||
_e = _p; \
|
||||
_p = STAILQ_NEXT(_p, field); \
|
||||
STAILQ_REMOVE_HEAD(&_la, field);\
|
||||
_psz--; \
|
||||
} else if (cmp(_p, _q) <= 0) { \
|
||||
_e = _p; \
|
||||
_p = STAILQ_NEXT(_p, field); \
|
||||
STAILQ_REMOVE_HEAD(&_la, field);\
|
||||
_psz--; \
|
||||
} else { \
|
||||
_e = _q; \
|
||||
_q = STAILQ_NEXT(_q, field); \
|
||||
STAILQ_REMOVE_HEAD((head), \
|
||||
field); \
|
||||
_qsz--; \
|
||||
} \
|
||||
STAILQ_INSERT_TAIL(&_lb, _e, field); \
|
||||
} \
|
||||
} \
|
||||
(head)->stqh_first = _lb.stqh_first; \
|
||||
(head)->stqh_last = _lb.stqh_last; \
|
||||
_sz *= 2; \
|
||||
} while (_nmerges > 1); \
|
||||
} while (/*CONSTCOND*/0)
|
||||
#endif
|
||||
|
||||
#ifndef TAILQ_FOREACH_SAFE
|
||||
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
|
||||
(var) = (tvar))
|
||||
#endif
|
||||
|
||||
/* ]] --QUEUE-MACROS-- */
|
||||
|
||||
/*
|
||||
* VCS Ids.
|
||||
*/
|
||||
|
||||
#ifndef ELFTC_VCSID
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
#define ELFTC_VCSID(ID) __RCSID(ID)
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#define ELFTC_VCSID(ID) __FBSDID(ID)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)
|
||||
#if defined(__GNUC__)
|
||||
#define ELFTC_VCSID(ID) __asm__(".ident\t\"" ID "\"")
|
||||
#else
|
||||
#define ELFTC_VCSID(ID) /**/
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__minix)
|
||||
#if defined(__GNUC__)
|
||||
#define ELFTC_VCSID(ID) __asm__(".ident\t\"" ID "\"")
|
||||
#else
|
||||
#define ELFTC_VCSID(ID) /**/
|
||||
#endif /* __GNU__ */
|
||||
#endif
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
#define ELFTC_VCSID(ID) __RCSID(ID)
|
||||
#endif
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
#if defined(__GNUC__)
|
||||
#define ELFTC_VCSID(ID) __asm__(".ident\t\"" ID "\"")
|
||||
#else
|
||||
#define ELFTC_VCSID(ID) /**/
|
||||
#endif /* __GNUC__ */
|
||||
#endif
|
||||
|
||||
#endif /* ELFTC_VCSID */
|
||||
|
||||
/*
|
||||
* Provide an equivalent for getprogname(3).
|
||||
*/
|
||||
|
||||
#ifndef ELFTC_GETPROGNAME
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__minix) || \
|
||||
defined(__NetBSD__)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ELFTC_GETPROGNAME() getprogname()
|
||||
|
||||
#endif /* __DragonFly__ || __FreeBSD__ || __minix || __NetBSD__ */
|
||||
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
|
||||
/*
|
||||
* GLIBC based systems have a global 'char *' pointer referencing
|
||||
* the executable's name.
|
||||
*/
|
||||
extern const char *program_invocation_short_name;
|
||||
|
||||
#define ELFTC_GETPROGNAME() program_invocation_short_name
|
||||
|
||||
#endif /* __GLIBC__ */
|
||||
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
|
||||
extern const char *__progname;
|
||||
|
||||
#define ELFTC_GETPROGNAME() __progname
|
||||
|
||||
#endif /* __OpenBSD__ */
|
||||
|
||||
#endif /* ELFTC_GETPROGNAME */
|
||||
|
||||
|
||||
/**
|
||||
** Per-OS configuration.
|
||||
**/
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
|
||||
#include <osreldate.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#define ELFTC_BYTE_ORDER _BYTE_ORDER
|
||||
#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
|
||||
|
||||
#define ELFTC_HAVE_MMAP 1
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
|
||||
#include <endian.h>
|
||||
|
||||
#define ELFTC_BYTE_ORDER __BYTE_ORDER
|
||||
#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||
#define ELFTC_BYTE_ORDER_BIG_ENDIAN __BIG_ENDIAN
|
||||
|
||||
#define ELFTC_HAVE_MMAP 1
|
||||
|
||||
/*
|
||||
* Debian GNU/Linux and Debian GNU/kFreeBSD do not have strmode(3).
|
||||
*/
|
||||
#define ELFTC_HAVE_STRMODE 0
|
||||
|
||||
/* Whether we need to supply {be,le}32dec. */
|
||||
#define ELFTC_NEED_BYTEORDER_EXTENSIONS 1
|
||||
|
||||
#define roundup2 roundup
|
||||
|
||||
#endif /* __GLIBC__ */
|
||||
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
|
||||
#include <osreldate.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#define ELFTC_BYTE_ORDER _BYTE_ORDER
|
||||
#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
|
||||
|
||||
#define ELFTC_HAVE_MMAP 1
|
||||
#define ELFTC_HAVE_STRMODE 1
|
||||
#if __FreeBSD_version <= 900000
|
||||
#define ELFTC_BROKEN_YY_NO_INPUT 1
|
||||
#endif
|
||||
#endif /* __FreeBSD__ */
|
||||
|
||||
|
||||
#if defined(__minix)
|
||||
#define ELFTC_HAVE_MMAP 0
|
||||
#endif /* __minix */
|
||||
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#define ELFTC_BYTE_ORDER _BYTE_ORDER
|
||||
#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
|
||||
|
||||
#define ELFTC_HAVE_MMAP 1
|
||||
#define ELFTC_HAVE_STRMODE 1
|
||||
#if __NetBSD_Version__ <= 599002100
|
||||
/* from src/doc/CHANGES: flex(1): Import flex-2.5.35 [christos 20091025] */
|
||||
/* and 5.99.21 was from Wed Oct 21 21:28:36 2009 UTC */
|
||||
# define ELFTC_BROKEN_YY_NO_INPUT 1
|
||||
#endif
|
||||
#endif /* __NetBSD __ */
|
||||
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/endian.h>
|
||||
|
||||
#define ELFTC_BYTE_ORDER _BYTE_ORDER
|
||||
#define ELFTC_BYTE_ORDER_LITTLE_ENDIAN _LITTLE_ENDIAN
|
||||
#define ELFTC_BYTE_ORDER_BIG_ENDIAN _BIG_ENDIAN
|
||||
|
||||
#define ELFTC_HAVE_MMAP 1
|
||||
#define ELFTC_HAVE_STRMODE 1
|
||||
|
||||
#define ELFTC_NEED_BYTEORDER_EXTENSIONS 1
|
||||
#define roundup2 roundup
|
||||
|
||||
#endif /* __OpenBSD__ */
|
||||
|
||||
#endif /* _ELFTC_H */
|
2614
common/elfdefinitions.h
Normal file
2614
common/elfdefinitions.h
Normal file
File diff suppressed because it is too large
Load diff
47
common/native-elf-format
Executable file
47
common/native-elf-format
Executable file
|
@ -0,0 +1,47 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# $Id: native-elf-format 2064 2011-10-26 15:12:32Z jkoshy $
|
||||
#
|
||||
# Find the native ELF format for a host platform by compiling a
|
||||
# test object and examining the resulting object.
|
||||
#
|
||||
# This script is used if there is no easy way to determine this
|
||||
# information statically at compile time.
|
||||
|
||||
program=`basename $0`
|
||||
tmp_c=`mktemp -u nefXXXXXX`.c
|
||||
tmp_o=`echo ${tmp_c} | sed -e 's/.c$/.o/'`
|
||||
|
||||
trap "rm -f ${tmp_c} ${tmp_o}" 0 1 2 3 15
|
||||
|
||||
touch ${tmp_c}
|
||||
|
||||
echo "/* Generated by ${program} on `date` */"
|
||||
|
||||
cc -c ${tmp_c} -o ${tmp_o}
|
||||
readelf -h ${tmp_o} | awk '
|
||||
$1 ~ "Class:" {
|
||||
sub("ELF","",$2); elfclass = $2;
|
||||
}
|
||||
$1 ~ "Data:" {
|
||||
if (match($0, "little")) {
|
||||
elfdata = "LSB";
|
||||
} else {
|
||||
elfdata = "MSB";
|
||||
}
|
||||
}
|
||||
$1 ~ "Machine:" {
|
||||
if (match($0, "Intel.*386")) {
|
||||
elfarch = "EM_386";
|
||||
} else if (match($0, ".*X86-64")) {
|
||||
elfarch = "EM_X86_64";
|
||||
} else {
|
||||
elfarch = "unknown";
|
||||
}
|
||||
}
|
||||
END {
|
||||
printf("#define ELFTC_CLASS ELFCLASS%s\n", elfclass);
|
||||
printf("#define ELFTC_ARCH %s\n", elfarch);
|
||||
printf("#define ELFTC_BYTEORDER ELFDATA2%s\n", elfdata);
|
||||
}'
|
||||
|
13
common/os.Linux.mk
Normal file
13
common/os.Linux.mk
Normal file
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# Build recipes for Linux based operating systems.
|
||||
#
|
||||
# $Id: os.Linux.mk 2064 2011-10-26 15:12:32Z jkoshy $
|
||||
|
||||
_NATIVE_ELF_FORMAT = native-elf-format
|
||||
|
||||
.BEGIN: ${_NATIVE_ELF_FORMAT}.h
|
||||
|
||||
${_NATIVE_ELF_FORMAT}.h:
|
||||
${.CURDIR}/${_NATIVE_ELF_FORMAT} > ${.TARGET} || rm ${.TARGET}
|
||||
|
||||
CLEANFILES += ${_NATIVE_ELF_FORMAT}.h
|
237
common/utarray.h
Normal file
237
common/utarray.h
Normal file
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
Copyright (c) 2008-2013, Troy D. Hanson http://uthash.sourceforge.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id: utarray.h 2694 2012-11-24 17:11:58Z kaiwang27 $ */
|
||||
|
||||
/* a dynamic array implementation using macros
|
||||
* see http://uthash.sourceforge.net/utarray
|
||||
*/
|
||||
#ifndef UTARRAY_H
|
||||
#define UTARRAY_H
|
||||
|
||||
#define UTARRAY_VERSION 1.9.7
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define _UNUSED_ __attribute__ ((__unused__))
|
||||
#else
|
||||
#define _UNUSED_
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
#include <string.h> /* memset, etc */
|
||||
#include <stdlib.h> /* exit */
|
||||
|
||||
#ifndef oom
|
||||
#define oom() exit(-1)
|
||||
#endif
|
||||
|
||||
typedef void (ctor_f)(void *dst, const void *src);
|
||||
typedef void (dtor_f)(void *elt);
|
||||
typedef void (init_f)(void *elt);
|
||||
typedef struct {
|
||||
size_t sz;
|
||||
init_f *init;
|
||||
ctor_f *copy;
|
||||
dtor_f *dtor;
|
||||
} UT_icd;
|
||||
|
||||
typedef struct {
|
||||
unsigned i,n;/* i: index of next available slot, n: num slots */
|
||||
UT_icd icd; /* initializer, copy and destructor functions */
|
||||
char *d; /* n slots of size icd->sz*/
|
||||
} UT_array;
|
||||
|
||||
#define utarray_init(a,_icd) do { \
|
||||
memset(a,0,sizeof(UT_array)); \
|
||||
(a)->icd=*_icd; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_done(a) do { \
|
||||
if ((a)->n) { \
|
||||
if ((a)->icd.dtor) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
free((a)->d); \
|
||||
} \
|
||||
(a)->n=0; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_new(a,_icd) do { \
|
||||
a=(UT_array*)malloc(sizeof(UT_array)); \
|
||||
utarray_init(a,_icd); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_free(a) do { \
|
||||
utarray_done(a); \
|
||||
free(a); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_reserve(a,by) do { \
|
||||
if (((a)->i+by) > ((a)->n)) { \
|
||||
while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
|
||||
if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd.sz)) == NULL) oom(); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utarray_push_back(a,p) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,(a)->i++), p); } \
|
||||
else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd.sz); }; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_pop_back(a) do { \
|
||||
if ((a)->icd.dtor) { (a)->icd.dtor( _utarray_eltptr(a,--((a)->i))); } \
|
||||
else { (a)->i--; } \
|
||||
} while(0)
|
||||
|
||||
#define utarray_extend_back(a) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if ((a)->icd.init) { (a)->icd.init(_utarray_eltptr(a,(a)->i)); } \
|
||||
else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd.sz); } \
|
||||
(a)->i++; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_len(a) ((a)->i)
|
||||
|
||||
#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
|
||||
#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd.sz*(j) )))
|
||||
|
||||
#define utarray_insert(a,p,j) do { \
|
||||
utarray_reserve(a,1); \
|
||||
if (j > (a)->i) break; \
|
||||
if ((j) < (a)->i) { \
|
||||
memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
|
||||
((a)->i - (j))*((a)->icd.sz)); \
|
||||
} \
|
||||
if ((a)->icd.copy) { (a)->icd.copy( _utarray_eltptr(a,j), p); } \
|
||||
else { memcpy(_utarray_eltptr(a,j), p, (a)->icd.sz); }; \
|
||||
(a)->i++; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_inserta(a,w,j) do { \
|
||||
if (utarray_len(w) == 0) break; \
|
||||
if (j > (a)->i) break; \
|
||||
utarray_reserve(a,utarray_len(w)); \
|
||||
if ((j) < (a)->i) { \
|
||||
memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
|
||||
_utarray_eltptr(a,j), \
|
||||
((a)->i - (j))*((a)->icd.sz)); \
|
||||
} \
|
||||
if ((a)->icd.copy) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
|
||||
(a)->icd.copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
|
||||
utarray_len(w)*((a)->icd.sz)); \
|
||||
} \
|
||||
(a)->i += utarray_len(w); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_resize(dst,num) do { \
|
||||
size_t _ut_i; \
|
||||
if (dst->i > (size_t)(num)) { \
|
||||
if ((dst)->icd.dtor) { \
|
||||
for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \
|
||||
(dst)->icd.dtor(utarray_eltptr(dst,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
} else if (dst->i < (size_t)(num)) { \
|
||||
utarray_reserve(dst,num-dst->i); \
|
||||
if ((dst)->icd.init) { \
|
||||
for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \
|
||||
(dst)->icd.init(utarray_eltptr(dst,_ut_i)); \
|
||||
} \
|
||||
} else { \
|
||||
memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd.sz*(num-dst->i)); \
|
||||
} \
|
||||
} \
|
||||
dst->i = num; \
|
||||
} while(0)
|
||||
|
||||
#define utarray_concat(dst,src) do { \
|
||||
utarray_inserta((dst),(src),utarray_len(dst)); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_erase(a,pos,len) do { \
|
||||
if ((a)->icd.dtor) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0; _ut_i < len; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr((a),pos+_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
if ((a)->i > (pos+len)) { \
|
||||
memmove( _utarray_eltptr((a),pos), _utarray_eltptr((a),pos+len), \
|
||||
(((a)->i)-(pos+len))*((a)->icd.sz)); \
|
||||
} \
|
||||
(a)->i -= (len); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_renew(a,u) do { \
|
||||
if (a) utarray_clear(a); \
|
||||
else utarray_new((a),(u)); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_clear(a) do { \
|
||||
if ((a)->i > 0) { \
|
||||
if ((a)->icd.dtor) { \
|
||||
size_t _ut_i; \
|
||||
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
||||
(a)->icd.dtor(utarray_eltptr(a,_ut_i)); \
|
||||
} \
|
||||
} \
|
||||
(a)->i = 0; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define utarray_sort(a,cmp) do { \
|
||||
qsort((a)->d, (a)->i, (a)->icd.sz, cmp); \
|
||||
} while(0)
|
||||
|
||||
#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd.sz,cmp)
|
||||
|
||||
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
|
||||
#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : (((int)((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
|
||||
#define utarray_prev(a,e) (((e)==NULL) ? utarray_back(a) : ((utarray_eltidx(a,e) > 0) ? _utarray_eltptr(a,utarray_eltidx(a,e)-1) : NULL))
|
||||
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
|
||||
#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (int)(((char*)(e) - (char*)((a)->d))/(a)->icd.sz) : -1)
|
||||
|
||||
/* last we pre-define a few icd for common utarrays of ints and strings */
|
||||
static void utarray_str_cpy(void *dst, const void *src) {
|
||||
char *const*_src = (char*const*)src, **_dst = (char**)dst;
|
||||
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
|
||||
}
|
||||
static void utarray_str_dtor(void *elt) {
|
||||
char **eltc = (char**)elt;
|
||||
if (*eltc) free(*eltc);
|
||||
}
|
||||
static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
|
||||
static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
|
||||
static const UT_icd ut_ptr_icd _UNUSED_ = {sizeof(void*),NULL,NULL,NULL};
|
||||
|
||||
|
||||
#endif /* UTARRAY_H */
|
919
common/uthash.h
Normal file
919
common/uthash.h
Normal file
|
@ -0,0 +1,919 @@
|
|||
/*
|
||||
Copyright (c) 2003-2013, Troy D. Hanson http://uthash.sourceforge.net
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id: uthash.h 2682 2012-11-23 22:04:22Z kaiwang27 $ */
|
||||
|
||||
#ifndef UTHASH_H
|
||||
#define UTHASH_H
|
||||
|
||||
#include <string.h> /* memcmp,strlen */
|
||||
#include <stddef.h> /* ptrdiff_t */
|
||||
#include <stdlib.h> /* exit() */
|
||||
|
||||
/* These macros use decltype or the earlier __typeof GNU extension.
|
||||
As decltype is only available in newer compilers (VS2010 or gcc 4.3+
|
||||
when compiling c++ source) this code uses whatever method is needed
|
||||
or, for VS2008 where neither is available, uses casting workarounds. */
|
||||
#ifdef _MSC_VER /* MS compiler */
|
||||
#if _MSC_VER >= 1600 && defined(__cplusplus) /* VS2010 or newer in C++ mode */
|
||||
#define DECLTYPE(x) (decltype(x))
|
||||
#else /* VS2008 or older (or VS2010 in C mode) */
|
||||
#define NO_DECLTYPE
|
||||
#define DECLTYPE(x)
|
||||
#endif
|
||||
#else /* GNU, Sun and other compilers */
|
||||
#define DECLTYPE(x) (__typeof(x))
|
||||
#endif
|
||||
|
||||
#ifdef NO_DECLTYPE
|
||||
#define DECLTYPE_ASSIGN(dst,src) \
|
||||
do { \
|
||||
char **_da_dst = (char**)(&(dst)); \
|
||||
*_da_dst = (char*)(src); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DECLTYPE_ASSIGN(dst,src) \
|
||||
do { \
|
||||
(dst) = DECLTYPE(dst)(src); \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
/* a number of the hash function use uint32_t which isn't defined on win32 */
|
||||
#ifdef _MSC_VER
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#else
|
||||
#include <inttypes.h> /* uint32_t */
|
||||
#endif
|
||||
|
||||
#define UTHASH_VERSION 1.9.7
|
||||
|
||||
#ifndef uthash_fatal
|
||||
#define uthash_fatal(msg) exit(-1) /* fatal error (out of memory,etc) */
|
||||
#endif
|
||||
#ifndef uthash_malloc
|
||||
#define uthash_malloc(sz) malloc(sz) /* malloc fcn */
|
||||
#endif
|
||||
#ifndef uthash_free
|
||||
#define uthash_free(ptr,sz) free(ptr) /* free fcn */
|
||||
#endif
|
||||
|
||||
#ifndef uthash_noexpand_fyi
|
||||
#define uthash_noexpand_fyi(tbl) /* can be defined to log noexpand */
|
||||
#endif
|
||||
#ifndef uthash_expand_fyi
|
||||
#define uthash_expand_fyi(tbl) /* can be defined to log expands */
|
||||
#endif
|
||||
|
||||
/* initial number of buckets */
|
||||
#define HASH_INITIAL_NUM_BUCKETS 32 /* initial number of buckets */
|
||||
#define HASH_INITIAL_NUM_BUCKETS_LOG2 5 /* lg2 of initial number of buckets */
|
||||
#define HASH_BKT_CAPACITY_THRESH 10 /* expand when bucket count reaches */
|
||||
|
||||
/* calculate the element whose hash handle address is hhe */
|
||||
#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
|
||||
|
||||
#define HASH_FIND(hh,head,keyptr,keylen,out) \
|
||||
do { \
|
||||
unsigned _hf_bkt,_hf_hashv; \
|
||||
out=NULL; \
|
||||
if (head) { \
|
||||
HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt); \
|
||||
if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) { \
|
||||
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], \
|
||||
keyptr,keylen,out); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef HASH_BLOOM
|
||||
#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
|
||||
#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
|
||||
#define HASH_BLOOM_MAKE(tbl) \
|
||||
do { \
|
||||
(tbl)->bloom_nbits = HASH_BLOOM; \
|
||||
(tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN); \
|
||||
if (!((tbl)->bloom_bv)) { uthash_fatal( "out of memory"); } \
|
||||
memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN); \
|
||||
(tbl)->bloom_sig = HASH_BLOOM_SIGNATURE; \
|
||||
} while (0)
|
||||
|
||||
#define HASH_BLOOM_FREE(tbl) \
|
||||
do { \
|
||||
uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
|
||||
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
|
||||
|
||||
#define HASH_BLOOM_ADD(tbl,hashv) \
|
||||
HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
|
||||
|
||||
#define HASH_BLOOM_TEST(tbl,hashv) \
|
||||
HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
|
||||
|
||||
#else
|
||||
#define HASH_BLOOM_MAKE(tbl)
|
||||
#define HASH_BLOOM_FREE(tbl)
|
||||
#define HASH_BLOOM_ADD(tbl,hashv)
|
||||
#define HASH_BLOOM_TEST(tbl,hashv) (1)
|
||||
#endif
|
||||
|
||||
#define HASH_MAKE_TABLE(hh,head) \
|
||||
do { \
|
||||
(head)->hh.tbl = (UT_hash_table*)uthash_malloc( \
|
||||
sizeof(UT_hash_table)); \
|
||||
if (!((head)->hh.tbl)) { uthash_fatal( "out of memory"); } \
|
||||
memset((head)->hh.tbl, 0, sizeof(UT_hash_table)); \
|
||||
(head)->hh.tbl->tail = &((head)->hh); \
|
||||
(head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS; \
|
||||
(head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2; \
|
||||
(head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head); \
|
||||
(head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc( \
|
||||
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
|
||||
if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); } \
|
||||
memset((head)->hh.tbl->buckets, 0, \
|
||||
HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket)); \
|
||||
HASH_BLOOM_MAKE((head)->hh.tbl); \
|
||||
(head)->hh.tbl->signature = HASH_SIGNATURE; \
|
||||
} while(0)
|
||||
|
||||
#define HASH_ADD(hh,head,fieldname,keylen_in,add) \
|
||||
HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
|
||||
|
||||
#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \
|
||||
do { \
|
||||
unsigned _ha_bkt; \
|
||||
(add)->hh.next = NULL; \
|
||||
(add)->hh.key = (char*)keyptr; \
|
||||
(add)->hh.keylen = (unsigned)keylen_in; \
|
||||
if (!(head)) { \
|
||||
head = (add); \
|
||||
(head)->hh.prev = NULL; \
|
||||
HASH_MAKE_TABLE(hh,head); \
|
||||
} else { \
|
||||
(head)->hh.tbl->tail->next = (add); \
|
||||
(add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail); \
|
||||
(head)->hh.tbl->tail = &((add)->hh); \
|
||||
} \
|
||||
(head)->hh.tbl->num_items++; \
|
||||
(add)->hh.tbl = (head)->hh.tbl; \
|
||||
HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets, \
|
||||
(add)->hh.hashv, _ha_bkt); \
|
||||
HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh); \
|
||||
HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv); \
|
||||
HASH_EMIT_KEY(hh,head,keyptr,keylen_in); \
|
||||
HASH_FSCK(hh,head); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_TO_BKT( hashv, num_bkts, bkt ) \
|
||||
do { \
|
||||
bkt = ((hashv) & ((num_bkts) - 1)); \
|
||||
} while(0)
|
||||
|
||||
/* delete "delptr" from the hash table.
|
||||
* "the usual" patch-up process for the app-order doubly-linked-list.
|
||||
* The use of _hd_hh_del below deserves special explanation.
|
||||
* These used to be expressed using (delptr) but that led to a bug
|
||||
* if someone used the same symbol for the head and deletee, like
|
||||
* HASH_DELETE(hh,users,users);
|
||||
* We want that to work, but by changing the head (users) below
|
||||
* we were forfeiting our ability to further refer to the deletee (users)
|
||||
* in the patch-up process. Solution: use scratch space to
|
||||
* copy the deletee pointer, then the latter references are via that
|
||||
* scratch pointer rather than through the repointed (users) symbol.
|
||||
*/
|
||||
#define HASH_DELETE(hh,head,delptr) \
|
||||
do { \
|
||||
unsigned _hd_bkt; \
|
||||
struct UT_hash_handle *_hd_hh_del; \
|
||||
if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) ) { \
|
||||
uthash_free((head)->hh.tbl->buckets, \
|
||||
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
|
||||
HASH_BLOOM_FREE((head)->hh.tbl); \
|
||||
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
|
||||
head = NULL; \
|
||||
} else { \
|
||||
_hd_hh_del = &((delptr)->hh); \
|
||||
if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) { \
|
||||
(head)->hh.tbl->tail = \
|
||||
(UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
|
||||
(head)->hh.tbl->hho); \
|
||||
} \
|
||||
if ((delptr)->hh.prev) { \
|
||||
((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) + \
|
||||
(head)->hh.tbl->hho))->next = (delptr)->hh.next; \
|
||||
} else { \
|
||||
DECLTYPE_ASSIGN(head,(delptr)->hh.next); \
|
||||
} \
|
||||
if (_hd_hh_del->next) { \
|
||||
((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next + \
|
||||
(head)->hh.tbl->hho))->prev = \
|
||||
_hd_hh_del->prev; \
|
||||
} \
|
||||
HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt); \
|
||||
HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del); \
|
||||
(head)->hh.tbl->num_items--; \
|
||||
} \
|
||||
HASH_FSCK(hh,head); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
|
||||
#define HASH_FIND_STR(head,findstr,out) \
|
||||
HASH_FIND(hh,head,findstr,strlen(findstr),out)
|
||||
#define HASH_ADD_STR(head,strfield,add) \
|
||||
HASH_ADD(hh,head,strfield,strlen(add->strfield),add)
|
||||
#define HASH_FIND_INT(head,findint,out) \
|
||||
HASH_FIND(hh,head,findint,sizeof(int),out)
|
||||
#define HASH_ADD_INT(head,intfield,add) \
|
||||
HASH_ADD(hh,head,intfield,sizeof(int),add)
|
||||
#define HASH_FIND_PTR(head,findptr,out) \
|
||||
HASH_FIND(hh,head,findptr,sizeof(void *),out)
|
||||
#define HASH_ADD_PTR(head,ptrfield,add) \
|
||||
HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
|
||||
#define HASH_DEL(head,delptr) \
|
||||
HASH_DELETE(hh,head,delptr)
|
||||
|
||||
/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
|
||||
* This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
|
||||
*/
|
||||
#ifdef HASH_DEBUG
|
||||
#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
|
||||
#define HASH_FSCK(hh,head) \
|
||||
do { \
|
||||
unsigned _bkt_i; \
|
||||
unsigned _count, _bkt_count; \
|
||||
char *_prev; \
|
||||
struct UT_hash_handle *_thh; \
|
||||
if (head) { \
|
||||
_count = 0; \
|
||||
for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) { \
|
||||
_bkt_count = 0; \
|
||||
_thh = (head)->hh.tbl->buckets[_bkt_i].hh_head; \
|
||||
_prev = NULL; \
|
||||
while (_thh) { \
|
||||
if (_prev != (char*)(_thh->hh_prev)) { \
|
||||
HASH_OOPS("invalid hh_prev %p, actual %p\n", \
|
||||
_thh->hh_prev, _prev ); \
|
||||
} \
|
||||
_bkt_count++; \
|
||||
_prev = (char*)(_thh); \
|
||||
_thh = _thh->hh_next; \
|
||||
} \
|
||||
_count += _bkt_count; \
|
||||
if ((head)->hh.tbl->buckets[_bkt_i].count != _bkt_count) { \
|
||||
HASH_OOPS("invalid bucket count %d, actual %d\n", \
|
||||
(head)->hh.tbl->buckets[_bkt_i].count, _bkt_count); \
|
||||
} \
|
||||
} \
|
||||
if (_count != (head)->hh.tbl->num_items) { \
|
||||
HASH_OOPS("invalid hh item count %d, actual %d\n", \
|
||||
(head)->hh.tbl->num_items, _count ); \
|
||||
} \
|
||||
/* traverse hh in app order; check next/prev integrity, count */ \
|
||||
_count = 0; \
|
||||
_prev = NULL; \
|
||||
_thh = &(head)->hh; \
|
||||
while (_thh) { \
|
||||
_count++; \
|
||||
if (_prev !=(char*)(_thh->prev)) { \
|
||||
HASH_OOPS("invalid prev %p, actual %p\n", \
|
||||
_thh->prev, _prev ); \
|
||||
} \
|
||||
_prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh); \
|
||||
_thh = ( _thh->next ? (UT_hash_handle*)((char*)(_thh->next) + \
|
||||
(head)->hh.tbl->hho) : NULL ); \
|
||||
} \
|
||||
if (_count != (head)->hh.tbl->num_items) { \
|
||||
HASH_OOPS("invalid app item count %d, actual %d\n", \
|
||||
(head)->hh.tbl->num_items, _count ); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define HASH_FSCK(hh,head)
|
||||
#endif
|
||||
|
||||
/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
|
||||
* the descriptor to which this macro is defined for tuning the hash function.
|
||||
* The app can #include <unistd.h> to get the prototype for write(2). */
|
||||
#ifdef HASH_EMIT_KEYS
|
||||
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) \
|
||||
do { \
|
||||
unsigned _klen = fieldlen; \
|
||||
write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \
|
||||
write(HASH_EMIT_KEYS, keyptr, fieldlen); \
|
||||
} while (0)
|
||||
#else
|
||||
#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
|
||||
#endif
|
||||
|
||||
/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
|
||||
#ifdef HASH_FUNCTION
|
||||
#define HASH_FCN HASH_FUNCTION
|
||||
#else
|
||||
#define HASH_FCN HASH_JEN
|
||||
#endif
|
||||
|
||||
/* The Bernstein hash function, used in Perl prior to v5.6 */
|
||||
#define HASH_BER(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _hb_keylen=keylen; \
|
||||
char *_hb_key=(char*)(key); \
|
||||
(hashv) = 0; \
|
||||
while (_hb_keylen--) { (hashv) = ((hashv) * 33) + *_hb_key++; } \
|
||||
bkt = (hashv) & (num_bkts-1); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
|
||||
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
|
||||
#define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _sx_i; \
|
||||
char *_hs_key=(char*)(key); \
|
||||
hashv = 0; \
|
||||
for(_sx_i=0; _sx_i < keylen; _sx_i++) \
|
||||
hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i]; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_FNV(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _fn_i; \
|
||||
char *_hf_key=(char*)(key); \
|
||||
hashv = 2166136261UL; \
|
||||
for(_fn_i=0; _fn_i < keylen; _fn_i++) \
|
||||
hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _ho_i; \
|
||||
char *_ho_key=(char*)(key); \
|
||||
hashv = 0; \
|
||||
for(_ho_i=0; _ho_i < keylen; _ho_i++) { \
|
||||
hashv += _ho_key[_ho_i]; \
|
||||
hashv += (hashv << 10); \
|
||||
hashv ^= (hashv >> 6); \
|
||||
} \
|
||||
hashv += (hashv << 3); \
|
||||
hashv ^= (hashv >> 11); \
|
||||
hashv += (hashv << 15); \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#define HASH_JEN_MIX(a,b,c) \
|
||||
do { \
|
||||
a -= b; a -= c; a ^= ( c >> 13 ); \
|
||||
b -= c; b -= a; b ^= ( a << 8 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 13 ); \
|
||||
a -= b; a -= c; a ^= ( c >> 12 ); \
|
||||
b -= c; b -= a; b ^= ( a << 16 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 5 ); \
|
||||
a -= b; a -= c; a ^= ( c >> 3 ); \
|
||||
b -= c; b -= a; b ^= ( a << 10 ); \
|
||||
c -= a; c -= b; c ^= ( b >> 15 ); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_JEN(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
unsigned _hj_i,_hj_j,_hj_k; \
|
||||
char *_hj_key=(char*)(key); \
|
||||
hashv = 0xfeedbeef; \
|
||||
_hj_i = _hj_j = 0x9e3779b9; \
|
||||
_hj_k = (unsigned)keylen; \
|
||||
while (_hj_k >= 12) { \
|
||||
_hj_i += (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[2] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[3] << 24 ) ); \
|
||||
_hj_j += (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[6] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[7] << 24 ) ); \
|
||||
hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 ) \
|
||||
+ ( (unsigned)_hj_key[10] << 16 ) \
|
||||
+ ( (unsigned)_hj_key[11] << 24 ) ); \
|
||||
\
|
||||
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
|
||||
\
|
||||
_hj_key += 12; \
|
||||
_hj_k -= 12; \
|
||||
} \
|
||||
hashv += keylen; \
|
||||
switch ( _hj_k ) { \
|
||||
case 11: hashv += ( (unsigned)_hj_key[10] << 24 ); \
|
||||
case 10: hashv += ( (unsigned)_hj_key[9] << 16 ); \
|
||||
case 9: hashv += ( (unsigned)_hj_key[8] << 8 ); \
|
||||
case 8: _hj_j += ( (unsigned)_hj_key[7] << 24 ); \
|
||||
case 7: _hj_j += ( (unsigned)_hj_key[6] << 16 ); \
|
||||
case 6: _hj_j += ( (unsigned)_hj_key[5] << 8 ); \
|
||||
case 5: _hj_j += _hj_key[4]; \
|
||||
case 4: _hj_i += ( (unsigned)_hj_key[3] << 24 ); \
|
||||
case 3: _hj_i += ( (unsigned)_hj_key[2] << 16 ); \
|
||||
case 2: _hj_i += ( (unsigned)_hj_key[1] << 8 ); \
|
||||
case 1: _hj_i += _hj_key[0]; \
|
||||
} \
|
||||
HASH_JEN_MIX(_hj_i, _hj_j, hashv); \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
/* The Paul Hsieh hash function */
|
||||
#undef get16bits
|
||||
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||
#endif
|
||||
|
||||
#if !defined (get16bits)
|
||||
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
|
||||
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||
#endif
|
||||
#define HASH_SFH(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
char *_sfh_key=(char*)(key); \
|
||||
uint32_t _sfh_tmp, _sfh_len = keylen; \
|
||||
\
|
||||
int _sfh_rem = _sfh_len & 3; \
|
||||
_sfh_len >>= 2; \
|
||||
hashv = 0xcafebabe; \
|
||||
\
|
||||
/* Main loop */ \
|
||||
for (;_sfh_len > 0; _sfh_len--) { \
|
||||
hashv += get16bits (_sfh_key); \
|
||||
_sfh_tmp = (get16bits (_sfh_key+2) << 11) ^ hashv; \
|
||||
hashv = (hashv << 16) ^ _sfh_tmp; \
|
||||
_sfh_key += 2*sizeof (uint16_t); \
|
||||
hashv += hashv >> 11; \
|
||||
} \
|
||||
\
|
||||
/* Handle end cases */ \
|
||||
switch (_sfh_rem) { \
|
||||
case 3: hashv += get16bits (_sfh_key); \
|
||||
hashv ^= hashv << 16; \
|
||||
hashv ^= _sfh_key[sizeof (uint16_t)] << 18; \
|
||||
hashv += hashv >> 11; \
|
||||
break; \
|
||||
case 2: hashv += get16bits (_sfh_key); \
|
||||
hashv ^= hashv << 11; \
|
||||
hashv += hashv >> 17; \
|
||||
break; \
|
||||
case 1: hashv += *_sfh_key; \
|
||||
hashv ^= hashv << 10; \
|
||||
hashv += hashv >> 1; \
|
||||
} \
|
||||
\
|
||||
/* Force "avalanching" of final 127 bits */ \
|
||||
hashv ^= hashv << 3; \
|
||||
hashv += hashv >> 5; \
|
||||
hashv ^= hashv << 4; \
|
||||
hashv += hashv >> 17; \
|
||||
hashv ^= hashv << 25; \
|
||||
hashv += hashv >> 6; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
|
||||
#ifdef HASH_USING_NO_STRICT_ALIASING
|
||||
/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
|
||||
* For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
|
||||
* MurmurHash uses the faster approach only on CPU's where we know it's safe.
|
||||
*
|
||||
* Note the preprocessor built-in defines can be emitted using:
|
||||
*
|
||||
* gcc -m64 -dM -E - < /dev/null (on gcc)
|
||||
* cc -## a.c (where a.c is a simple test file) (Sun Studio)
|
||||
*/
|
||||
#if (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86))
|
||||
#define MUR_GETBLOCK(p,i) p[i]
|
||||
#else /* non intel */
|
||||
#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
|
||||
#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
|
||||
#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
|
||||
#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
|
||||
#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
|
||||
#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
|
||||
#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
|
||||
#define MUR_TWO_TWO(p) ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
|
||||
#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >> 8))
|
||||
#else /* assume little endian non-intel */
|
||||
#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
|
||||
#define MUR_TWO_TWO(p) ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
|
||||
#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) << 8))
|
||||
#endif
|
||||
#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) : \
|
||||
(MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
|
||||
(MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) : \
|
||||
MUR_ONE_THREE(p))))
|
||||
#endif
|
||||
#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
|
||||
#define MUR_FMIX(_h) \
|
||||
do { \
|
||||
_h ^= _h >> 16; \
|
||||
_h *= 0x85ebca6b; \
|
||||
_h ^= _h >> 13; \
|
||||
_h *= 0xc2b2ae35l; \
|
||||
_h ^= _h >> 16; \
|
||||
} while(0)
|
||||
|
||||
#define HASH_MUR(key,keylen,num_bkts,hashv,bkt) \
|
||||
do { \
|
||||
const uint8_t *_mur_data = (const uint8_t*)(key); \
|
||||
const int _mur_nblocks = (keylen) / 4; \
|
||||
uint32_t _mur_h1 = 0xf88D5353; \
|
||||
uint32_t _mur_c1 = 0xcc9e2d51; \
|
||||
uint32_t _mur_c2 = 0x1b873593; \
|
||||
uint32_t _mur_k1 = 0; \
|
||||
const uint8_t *_mur_tail; \
|
||||
const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
|
||||
int _mur_i; \
|
||||
for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) { \
|
||||
_mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i); \
|
||||
_mur_k1 *= _mur_c1; \
|
||||
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
|
||||
_mur_k1 *= _mur_c2; \
|
||||
\
|
||||
_mur_h1 ^= _mur_k1; \
|
||||
_mur_h1 = MUR_ROTL32(_mur_h1,13); \
|
||||
_mur_h1 = _mur_h1*5+0xe6546b64; \
|
||||
} \
|
||||
_mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4); \
|
||||
_mur_k1=0; \
|
||||
switch((keylen) & 3) { \
|
||||
case 3: _mur_k1 ^= _mur_tail[2] << 16; \
|
||||
case 2: _mur_k1 ^= _mur_tail[1] << 8; \
|
||||
case 1: _mur_k1 ^= _mur_tail[0]; \
|
||||
_mur_k1 *= _mur_c1; \
|
||||
_mur_k1 = MUR_ROTL32(_mur_k1,15); \
|
||||
_mur_k1 *= _mur_c2; \
|
||||
_mur_h1 ^= _mur_k1; \
|
||||
} \
|
||||
_mur_h1 ^= (keylen); \
|
||||
MUR_FMIX(_mur_h1); \
|
||||
hashv = _mur_h1; \
|
||||
bkt = hashv & (num_bkts-1); \
|
||||
} while(0)
|
||||
#endif /* HASH_USING_NO_STRICT_ALIASING */
|
||||
|
||||
/* key comparison function; return 0 if keys equal */
|
||||
#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
|
||||
|
||||
/* iterate over items in a known bucket to find desired item */
|
||||
#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \
|
||||
do { \
|
||||
if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head)); \
|
||||
else out=NULL; \
|
||||
while (out) { \
|
||||
if ((out)->hh.keylen == keylen_in) { \
|
||||
if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break; \
|
||||
} \
|
||||
if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
|
||||
else out = NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* add an item to a bucket */
|
||||
#define HASH_ADD_TO_BKT(head,addhh) \
|
||||
do { \
|
||||
head.count++; \
|
||||
(addhh)->hh_next = head.hh_head; \
|
||||
(addhh)->hh_prev = NULL; \
|
||||
if (head.hh_head) { (head).hh_head->hh_prev = (addhh); } \
|
||||
(head).hh_head=addhh; \
|
||||
if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH) \
|
||||
&& (addhh)->tbl->noexpand != 1) { \
|
||||
HASH_EXPAND_BUCKETS((addhh)->tbl); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* remove an item from a given bucket */
|
||||
#define HASH_DEL_IN_BKT(hh,head,hh_del) \
|
||||
(head).count--; \
|
||||
if ((head).hh_head == hh_del) { \
|
||||
(head).hh_head = hh_del->hh_next; \
|
||||
} \
|
||||
if (hh_del->hh_prev) { \
|
||||
hh_del->hh_prev->hh_next = hh_del->hh_next; \
|
||||
} \
|
||||
if (hh_del->hh_next) { \
|
||||
hh_del->hh_next->hh_prev = hh_del->hh_prev; \
|
||||
}
|
||||
|
||||
/* Bucket expansion has the effect of doubling the number of buckets
|
||||
* and redistributing the items into the new buckets. Ideally the
|
||||
* items will distribute more or less evenly into the new buckets
|
||||
* (the extent to which this is true is a measure of the quality of
|
||||
* the hash function as it applies to the key domain).
|
||||
*
|
||||
* With the items distributed into more buckets, the chain length
|
||||
* (item count) in each bucket is reduced. Thus by expanding buckets
|
||||
* the hash keeps a bound on the chain length. This bounded chain
|
||||
* length is the essence of how a hash provides constant time lookup.
|
||||
*
|
||||
* The calculation of tbl->ideal_chain_maxlen below deserves some
|
||||
* explanation. First, keep in mind that we're calculating the ideal
|
||||
* maximum chain length based on the *new* (doubled) bucket count.
|
||||
* In fractions this is just n/b (n=number of items,b=new num buckets).
|
||||
* Since the ideal chain length is an integer, we want to calculate
|
||||
* ceil(n/b). We don't depend on floating point arithmetic in this
|
||||
* hash, so to calculate ceil(n/b) with integers we could write
|
||||
*
|
||||
* ceil(n/b) = (n/b) + ((n%b)?1:0)
|
||||
*
|
||||
* and in fact a previous version of this hash did just that.
|
||||
* But now we have improved things a bit by recognizing that b is
|
||||
* always a power of two. We keep its base 2 log handy (call it lb),
|
||||
* so now we can write this with a bit shift and logical AND:
|
||||
*
|
||||
* ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
|
||||
*
|
||||
*/
|
||||
#define HASH_EXPAND_BUCKETS(tbl) \
|
||||
do { \
|
||||
unsigned _he_bkt; \
|
||||
unsigned _he_bkt_i; \
|
||||
struct UT_hash_handle *_he_thh, *_he_hh_nxt; \
|
||||
UT_hash_bucket *_he_new_buckets, *_he_newbkt; \
|
||||
_he_new_buckets = (UT_hash_bucket*)uthash_malloc( \
|
||||
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
|
||||
if (!_he_new_buckets) { uthash_fatal( "out of memory"); } \
|
||||
memset(_he_new_buckets, 0, \
|
||||
2 * tbl->num_buckets * sizeof(struct UT_hash_bucket)); \
|
||||
tbl->ideal_chain_maxlen = \
|
||||
(tbl->num_items >> (tbl->log2_num_buckets+1)) + \
|
||||
((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0); \
|
||||
tbl->nonideal_items = 0; \
|
||||
for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++) \
|
||||
{ \
|
||||
_he_thh = tbl->buckets[ _he_bkt_i ].hh_head; \
|
||||
while (_he_thh) { \
|
||||
_he_hh_nxt = _he_thh->hh_next; \
|
||||
HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt); \
|
||||
_he_newbkt = &(_he_new_buckets[ _he_bkt ]); \
|
||||
if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) { \
|
||||
tbl->nonideal_items++; \
|
||||
_he_newbkt->expand_mult = _he_newbkt->count / \
|
||||
tbl->ideal_chain_maxlen; \
|
||||
} \
|
||||
_he_thh->hh_prev = NULL; \
|
||||
_he_thh->hh_next = _he_newbkt->hh_head; \
|
||||
if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev = \
|
||||
_he_thh; \
|
||||
_he_newbkt->hh_head = _he_thh; \
|
||||
_he_thh = _he_hh_nxt; \
|
||||
} \
|
||||
} \
|
||||
uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
|
||||
tbl->num_buckets *= 2; \
|
||||
tbl->log2_num_buckets++; \
|
||||
tbl->buckets = _he_new_buckets; \
|
||||
tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ? \
|
||||
(tbl->ineff_expands+1) : 0; \
|
||||
if (tbl->ineff_expands > 1) { \
|
||||
tbl->noexpand=1; \
|
||||
uthash_noexpand_fyi(tbl); \
|
||||
} \
|
||||
uthash_expand_fyi(tbl); \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
|
||||
/* Note that HASH_SORT assumes the hash handle name to be hh.
|
||||
* HASH_SRT was added to allow the hash handle name to be passed in. */
|
||||
#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
|
||||
#define HASH_SRT(hh,head,cmpfcn) \
|
||||
do { \
|
||||
unsigned _hs_i; \
|
||||
unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize; \
|
||||
struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail; \
|
||||
if (head) { \
|
||||
_hs_insize = 1; \
|
||||
_hs_looping = 1; \
|
||||
_hs_list = &((head)->hh); \
|
||||
while (_hs_looping) { \
|
||||
_hs_p = _hs_list; \
|
||||
_hs_list = NULL; \
|
||||
_hs_tail = NULL; \
|
||||
_hs_nmerges = 0; \
|
||||
while (_hs_p) { \
|
||||
_hs_nmerges++; \
|
||||
_hs_q = _hs_p; \
|
||||
_hs_psize = 0; \
|
||||
for ( _hs_i = 0; _hs_i < _hs_insize; _hs_i++ ) { \
|
||||
_hs_psize++; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
if (! (_hs_q) ) break; \
|
||||
} \
|
||||
_hs_qsize = _hs_insize; \
|
||||
while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) { \
|
||||
if (_hs_psize == 0) { \
|
||||
_hs_e = _hs_q; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_qsize--; \
|
||||
} else if ( (_hs_qsize == 0) || !(_hs_q) ) { \
|
||||
_hs_e = _hs_p; \
|
||||
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
|
||||
((void*)((char*)(_hs_p->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_psize--; \
|
||||
} else if (( \
|
||||
cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
|
||||
DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
|
||||
) <= 0) { \
|
||||
_hs_e = _hs_p; \
|
||||
_hs_p = (UT_hash_handle*)((_hs_p->next) ? \
|
||||
((void*)((char*)(_hs_p->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_psize--; \
|
||||
} else { \
|
||||
_hs_e = _hs_q; \
|
||||
_hs_q = (UT_hash_handle*)((_hs_q->next) ? \
|
||||
((void*)((char*)(_hs_q->next) + \
|
||||
(head)->hh.tbl->hho)) : NULL); \
|
||||
_hs_qsize--; \
|
||||
} \
|
||||
if ( _hs_tail ) { \
|
||||
_hs_tail->next = ((_hs_e) ? \
|
||||
ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL); \
|
||||
} else { \
|
||||
_hs_list = _hs_e; \
|
||||
} \
|
||||
_hs_e->prev = ((_hs_tail) ? \
|
||||
ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL); \
|
||||
_hs_tail = _hs_e; \
|
||||
} \
|
||||
_hs_p = _hs_q; \
|
||||
} \
|
||||
_hs_tail->next = NULL; \
|
||||
if ( _hs_nmerges <= 1 ) { \
|
||||
_hs_looping=0; \
|
||||
(head)->hh.tbl->tail = _hs_tail; \
|
||||
DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list)); \
|
||||
} \
|
||||
_hs_insize *= 2; \
|
||||
} \
|
||||
HASH_FSCK(hh,head); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* This function selects items from one hash into another hash.
|
||||
* The end result is that the selected items have dual presence
|
||||
* in both hashes. There is no copy of the items made; rather
|
||||
* they are added into the new hash through a secondary hash
|
||||
* hash handle that must be present in the structure. */
|
||||
#define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \
|
||||
do { \
|
||||
unsigned _src_bkt, _dst_bkt; \
|
||||
void *_last_elt=NULL, *_elt; \
|
||||
UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL; \
|
||||
ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst)); \
|
||||
if (src) { \
|
||||
for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) { \
|
||||
for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head; \
|
||||
_src_hh; \
|
||||
_src_hh = _src_hh->hh_next) { \
|
||||
_elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh); \
|
||||
if (cond(_elt)) { \
|
||||
_dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho); \
|
||||
_dst_hh->key = _src_hh->key; \
|
||||
_dst_hh->keylen = _src_hh->keylen; \
|
||||
_dst_hh->hashv = _src_hh->hashv; \
|
||||
_dst_hh->prev = _last_elt; \
|
||||
_dst_hh->next = NULL; \
|
||||
if (_last_elt_hh) { _last_elt_hh->next = _elt; } \
|
||||
if (!dst) { \
|
||||
DECLTYPE_ASSIGN(dst,_elt); \
|
||||
HASH_MAKE_TABLE(hh_dst,dst); \
|
||||
} else { \
|
||||
_dst_hh->tbl = (dst)->hh_dst.tbl; \
|
||||
} \
|
||||
HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt); \
|
||||
HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh); \
|
||||
(dst)->hh_dst.tbl->num_items++; \
|
||||
_last_elt = _elt; \
|
||||
_last_elt_hh = _dst_hh; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
HASH_FSCK(hh_dst,dst); \
|
||||
} while (0)
|
||||
|
||||
#define HASH_CLEAR(hh,head) \
|
||||
do { \
|
||||
if (head) { \
|
||||
uthash_free((head)->hh.tbl->buckets, \
|
||||
(head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket)); \
|
||||
HASH_BLOOM_FREE((head)->hh.tbl); \
|
||||
uthash_free((head)->hh.tbl, sizeof(UT_hash_table)); \
|
||||
(head)=NULL; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#ifdef NO_DECLTYPE
|
||||
#define HASH_ITER(hh,head,el,tmp) \
|
||||
for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \
|
||||
el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
|
||||
#else
|
||||
#define HASH_ITER(hh,head,el,tmp) \
|
||||
for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \
|
||||
el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
|
||||
#endif
|
||||
|
||||
/* obtain a count of items in the hash */
|
||||
#define HASH_COUNT(head) HASH_CNT(hh,head)
|
||||
#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
|
||||
|
||||
typedef struct UT_hash_bucket {
|
||||
struct UT_hash_handle *hh_head;
|
||||
unsigned count;
|
||||
|
||||
/* expand_mult is normally set to 0. In this situation, the max chain length
|
||||
* threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
|
||||
* the bucket's chain exceeds this length, bucket expansion is triggered).
|
||||
* However, setting expand_mult to a non-zero value delays bucket expansion
|
||||
* (that would be triggered by additions to this particular bucket)
|
||||
* until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
|
||||
* (The multiplier is simply expand_mult+1). The whole idea of this
|
||||
* multiplier is to reduce bucket expansions, since they are expensive, in
|
||||
* situations where we know that a particular bucket tends to be overused.
|
||||
* It is better to let its chain length grow to a longer yet-still-bounded
|
||||
* value, than to do an O(n) bucket expansion too often.
|
||||
*/
|
||||
unsigned expand_mult;
|
||||
|
||||
} UT_hash_bucket;
|
||||
|
||||
/* random signature used only to find hash tables in external analysis */
|
||||
#define HASH_SIGNATURE 0xa0111fe1
|
||||
#define HASH_BLOOM_SIGNATURE 0xb12220f2
|
||||
|
||||
typedef struct UT_hash_table {
|
||||
UT_hash_bucket *buckets;
|
||||
unsigned num_buckets, log2_num_buckets;
|
||||
unsigned num_items;
|
||||
struct UT_hash_handle *tail; /* tail hh in app order, for fast append */
|
||||
ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
|
||||
|
||||
/* in an ideal situation (all buckets used equally), no bucket would have
|
||||
* more than ceil(#items/#buckets) items. that's the ideal chain length. */
|
||||
unsigned ideal_chain_maxlen;
|
||||
|
||||
/* nonideal_items is the number of items in the hash whose chain position
|
||||
* exceeds the ideal chain maxlen. these items pay the penalty for an uneven
|
||||
* hash distribution; reaching them in a chain traversal takes >ideal steps */
|
||||
unsigned nonideal_items;
|
||||
|
||||
/* ineffective expands occur when a bucket doubling was performed, but
|
||||
* afterward, more than half the items in the hash had nonideal chain
|
||||
* positions. If this happens on two consecutive expansions we inhibit any
|
||||
* further expansion, as it's not helping; this happens when the hash
|
||||
* function isn't a good fit for the key domain. When expansion is inhibited
|
||||
* the hash will still work, albeit no longer in constant time. */
|
||||
unsigned ineff_expands, noexpand;
|
||||
|
||||
uint32_t signature; /* used only to find hash tables in external analysis */
|
||||
#ifdef HASH_BLOOM
|
||||
uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
|
||||
uint8_t *bloom_bv;
|
||||
char bloom_nbits;
|
||||
#endif
|
||||
|
||||
} UT_hash_table;
|
||||
|
||||
typedef struct UT_hash_handle {
|
||||
struct UT_hash_table *tbl;
|
||||
void *prev; /* prev element in app order */
|
||||
void *next; /* next element in app order */
|
||||
struct UT_hash_handle *hh_prev; /* previous hh in bucket order */
|
||||
struct UT_hash_handle *hh_next; /* next hh in bucket order */
|
||||
void *key; /* ptr to enclosing struct's key */
|
||||
unsigned keylen; /* enclosing struct's key len */
|
||||
unsigned hashv; /* result of hash-fcn(key) */
|
||||
} UT_hash_handle;
|
||||
|
||||
#endif /* UTHASH_H */
|
15
cxxfilt/Makefile
Normal file
15
cxxfilt/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $Id: Makefile 2066 2011-10-26 15:40:28Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= c++filt
|
||||
SRCS= cxxfilt.c
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
DPADD= ${LIBELFTC} ${LIBELF}
|
||||
LDADD= -lelftc -lelf
|
||||
|
||||
MAN1= c++filt.1
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
109
cxxfilt/c++filt.1
Normal file
109
cxxfilt/c++filt.1
Normal file
|
@ -0,0 +1,109 @@
|
|||
.\" Copyright (c) 2009-2011 Joseph Koshy <jkoshy@users.sourceforge.net>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer
|
||||
.\" in this position and unchanged.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: c++filt.1 2175 2011-11-16 05:51:49Z jkoshy $
|
||||
.\"
|
||||
.Dd August 24, 2011
|
||||
.Os
|
||||
.Dt C++FILT 1
|
||||
.Sh NAME
|
||||
.Nm c++filt
|
||||
.Nd decode C++ symbols
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl -help
|
||||
.Op Fl _ | Fl -strip-underscores
|
||||
.Op Fl n | Fl -no-strip-underscores
|
||||
.Op Fl p | Fl -no-params
|
||||
.Op Fl s Ar scheme | Fl -format Ns = Ns Ar scheme
|
||||
.Op Fl V | Fl -version
|
||||
.Op Ar encoded-names ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility translates encoded C++ symbol names to human-readable form.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility has two operating modes.
|
||||
.Bl -bullet
|
||||
.It
|
||||
If arguments
|
||||
.Ar encoded-names
|
||||
are not specified, then
|
||||
.Nm
|
||||
will act as a filter, reading from standard input
|
||||
and writing to standard output.
|
||||
.It
|
||||
If arguments
|
||||
.Ar encoded-names
|
||||
are specified, then
|
||||
.Nm
|
||||
will decode each such argument in turn, writing its decoded form
|
||||
to standard output.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility recognizes the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl -help
|
||||
Print a help message and exit.
|
||||
.It Fl _ | Fl -strip-underscores
|
||||
Remove a leading underscore from symbol names prior to decoding them.
|
||||
.It Fl n | Fl -no-strip-underscores
|
||||
Do not remove leading underscores from names.
|
||||
.It Fl p | Fl -no-params
|
||||
This option is recognized but ignored.
|
||||
.It Fl s Ar scheme | Fl -format Ns = Ns Ar scheme
|
||||
Select the encoding scheme to use.
|
||||
Argument
|
||||
.Ar scheme
|
||||
can be one of the following:
|
||||
.Bl -tag -width "gnu-v5"
|
||||
.It Ar arm
|
||||
Use the encoding scheme specified by the C++ Annotated Reference Manual.
|
||||
.It Ar auto
|
||||
Guess the encoding scheme from the input.
|
||||
.It Ar gnu
|
||||
Use the encoding scheme used by the GNU C++ compiler.
|
||||
.It Ar gnu-v3
|
||||
Use the encoding scheme used by the GNU C++ compiler, version 3.
|
||||
.El
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier for
|
||||
.Nm
|
||||
and exit.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr nm 1 ,
|
||||
.Xr strip 1 ,
|
||||
.Xr elftc_demangle 3
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
224
cxxfilt/cxxfilt.c
Normal file
224
cxxfilt/cxxfilt.c
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer
|
||||
* in this position and unchanged.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <libelftc.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
ELFTC_VCSID("$Id: cxxfilt.c 2185 2011-11-19 16:07:16Z jkoshy $");
|
||||
|
||||
#define STRBUFSZ 8192
|
||||
|
||||
static int stripus = 0;
|
||||
static int noparam = 0;
|
||||
static int format = 0;
|
||||
|
||||
enum options
|
||||
{
|
||||
OPTION_HELP,
|
||||
OPTION_VERSION
|
||||
};
|
||||
|
||||
static struct option longopts[] =
|
||||
{
|
||||
{"format", required_argument, NULL, 's'},
|
||||
{"help", no_argument, NULL, OPTION_HELP},
|
||||
{"no-params", no_argument, NULL, 'p'},
|
||||
{"no-strip-underscores", no_argument, NULL, 'n'},
|
||||
{"strip-underscores", no_argument, NULL, '_'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
static struct {
|
||||
const char *fname;
|
||||
int fvalue;
|
||||
} flist[] = {
|
||||
{"auto", 0},
|
||||
{"arm", ELFTC_DEM_ARM},
|
||||
{"gnu", ELFTC_DEM_GNU2},
|
||||
{"gnu-v3", ELFTC_DEM_GNU3}
|
||||
};
|
||||
|
||||
#define USAGE_MESSAGE "\
|
||||
Usage: %s [options] [encoded-names...]\n\
|
||||
Translate C++ symbol names to human-readable form.\n\n\
|
||||
Options:\n\
|
||||
-_ | --strip-underscores Remove leading underscores prior to decoding.\n\
|
||||
-n | --no-strip-underscores Do not remove leading underscores.\n\
|
||||
-p | --no-params (Accepted but ignored).\n\
|
||||
-s SCHEME | --format=SCHEME Select the encoding scheme to use.\n\
|
||||
Valid schemes are: 'arm', 'auto', 'gnu' and\n\
|
||||
'gnu-v3'.\n\
|
||||
--help Print a help message.\n\
|
||||
--version Print a version identifier and exit.\n"
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
|
||||
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
version(void)
|
||||
{
|
||||
fprintf(stderr, "%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int
|
||||
find_format(const char *fstr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; (size_t) i < sizeof(flist) / sizeof(flist[0]); i++) {
|
||||
if (!strcmp(fstr, flist[i].fname))
|
||||
return (flist[i].fvalue);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
static char *
|
||||
demangle(char *name, int strict, int *pos)
|
||||
{
|
||||
static char dem[STRBUFSZ];
|
||||
char nb[STRBUFSZ];
|
||||
int p, t;
|
||||
|
||||
if (stripus && *name == '_') {
|
||||
strncpy(nb, name + 1, sizeof(nb) - 1);
|
||||
t = 1;
|
||||
} else {
|
||||
strncpy(nb, name, sizeof(nb) - 1);
|
||||
t = 0;
|
||||
}
|
||||
nb[sizeof(nb) - 1] = '\0';
|
||||
|
||||
p = strlen(nb);
|
||||
if (p <= 0)
|
||||
return NULL;
|
||||
|
||||
while (elftc_demangle(nb, dem, sizeof(dem), format) < 0) {
|
||||
if (!strict && p > 1) {
|
||||
nb[--p] = '\0';
|
||||
continue;
|
||||
} else
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (pos != NULL)
|
||||
*pos = t ? p + 1 : p;
|
||||
|
||||
return (dem);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
char *dem, buf[STRBUFSZ];
|
||||
int c, i, p, s, opt;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "_nps:V", longopts, NULL)) !=
|
||||
-1) {
|
||||
switch (opt) {
|
||||
case '_':
|
||||
stripus = 1;
|
||||
break;
|
||||
case 'n':
|
||||
stripus = 0;
|
||||
break;
|
||||
case 'p':
|
||||
noparam = 1;
|
||||
break;
|
||||
case 's':
|
||||
if ((format = find_format(optarg)) < 0)
|
||||
errx(EXIT_FAILURE, "unsupported format: %s",
|
||||
optarg);
|
||||
break;
|
||||
case 'V':
|
||||
version();
|
||||
/* NOT REACHED */
|
||||
case OPTION_HELP:
|
||||
default:
|
||||
usage();
|
||||
/* NOT REACHED */
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (*argv != NULL) {
|
||||
for (i = 0; i < argc; i++) {
|
||||
if ((dem = demangle(argv[i], 1, NULL)) == NULL)
|
||||
fprintf(stderr, "Failed: %s\n", argv[i]);
|
||||
else
|
||||
printf("%s\n", dem);
|
||||
}
|
||||
} else {
|
||||
p = 0;
|
||||
for (;;) {
|
||||
c = fgetc(stdin);
|
||||
if (c == EOF || !isprint(c) || strchr(" \t\n", c)) {
|
||||
if (p > 0) {
|
||||
buf[p] = '\0';
|
||||
if ((dem = demangle(buf, 0, &s)) ==
|
||||
NULL)
|
||||
printf("%s", buf);
|
||||
else {
|
||||
printf("%s", dem);
|
||||
for (i = s; i < p; i++)
|
||||
putchar(buf[i]);
|
||||
}
|
||||
p = 0;
|
||||
}
|
||||
if (c == EOF)
|
||||
break;
|
||||
if (isprint(c) || strchr(" \t\n", c))
|
||||
putchar(c);
|
||||
} else {
|
||||
if ((size_t) p >= sizeof(buf) - 1)
|
||||
warnx("buffer overflowed");
|
||||
else
|
||||
buf[p++] = c;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
7
documentation/Makefile
Normal file
7
documentation/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
# $Id: Makefile 2139 2011-11-10 14:23:13Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
SUBDIR= libelf-by-example
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.subdir.mk"
|
28
documentation/libelf-by-example/Makefile
Normal file
28
documentation/libelf-by-example/Makefile
Normal file
|
@ -0,0 +1,28 @@
|
|||
#
|
||||
# Libelf by Example
|
||||
#
|
||||
# $Id: Makefile 2441 2012-02-21 05:46:43Z jkoshy $
|
||||
|
||||
TOP = ../..
|
||||
|
||||
DOC= libelf-by-example
|
||||
|
||||
SRCS= libelf-by-example.tex prog1.txt prog2.txt prog3.txt \
|
||||
prog4.txt prog5.txt prog6.txt
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.tex.mk"
|
||||
|
||||
.if ${OS_HOST} == "Linux"
|
||||
EXTRA_LIBS= -lbsd
|
||||
.endif
|
||||
|
||||
check-example-syntax: .PHONY
|
||||
.for f in ${SRCS:Mprog*}
|
||||
@c=$$(basename ${f} .txt).c; sed -e 's/@[^@]*@//' \
|
||||
${.CURDIR}/${f} > ${.OBJDIR}/$${c}; \
|
||||
echo -n $${c} ' '; cc -I${.CURDIR}/${TOP}/common \
|
||||
-I${.CURDIR}/${TOP}/libelf ${.OBJDIR}/$${c} \
|
||||
-L${.CURDIR}/${TOP}/libelf -lelf ${EXTRA_LIBS} && \
|
||||
rm ${.OBJDIR}/$${c} a.out
|
||||
.endfor
|
||||
@echo
|
2846
documentation/libelf-by-example/libelf-by-example.tex
Normal file
2846
documentation/libelf-by-example/libelf-by-example.tex
Normal file
File diff suppressed because it is too large
Load diff
58
documentation/libelf-by-example/prog1.txt
Normal file
58
documentation/libelf-by-example/prog1.txt
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Getting started with libelf.
|
||||
*
|
||||
* $Id: prog1.txt 2133 2011-11-10 08:28:22Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <libelf.h> @\co{1}@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
Elf *e; @\co{2}@
|
||||
char *k;
|
||||
Elf_Kind ek; @\co{3}@
|
||||
|
||||
if (argc != 2)
|
||||
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE) @\co{4}@
|
||||
errx(EXIT_FAILURE, "ELF library initialization "
|
||||
"failed: %s", elf_errmsg(-1));
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY, 0)) < 0)
|
||||
err(EXIT_FAILURE, "open \%s\" failed", argv[1]);
|
||||
|
||||
if ((e = elf_begin(fd, ELF_C_READ@\co{5}@, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s.",
|
||||
elf_errmsg(-1)); @\co{6}@
|
||||
|
||||
ek = elf_kind(e); @\co{7}@
|
||||
|
||||
switch (ek) {
|
||||
case ELF_K_AR:
|
||||
k = "ar(1) archive";
|
||||
break;
|
||||
case ELF_K_ELF:
|
||||
k = "elf object";
|
||||
break;
|
||||
case ELF_K_NONE:
|
||||
k = "data";
|
||||
break;
|
||||
default:
|
||||
k = "unrecognized";
|
||||
}
|
||||
|
||||
(void) printf("%s: %s\n", argv[1], k);
|
||||
|
||||
(void) elf_end(e); @\co{8}@
|
||||
(void) close(fd);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
102
documentation/libelf-by-example/prog2.txt
Normal file
102
documentation/libelf-by-example/prog2.txt
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Print the ELF Executable Header from an ELF object.
|
||||
*
|
||||
* $Id: prog2.txt 2133 2011-11-10 08:28:22Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h> @\co{1}@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i, fd;
|
||||
Elf *e;
|
||||
char *id, bytes[5];
|
||||
size_t n;
|
||||
GElf_Ehdr ehdr; @\co{2}@
|
||||
|
||||
if (argc != 2)
|
||||
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "ELF library initialization "
|
||||
"failed: %s", elf_errmsg(-1));
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY, 0)) < 0)
|
||||
err(EXIT_FAILURE, "open \"%s\" failed", argv[1]);
|
||||
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if (elf_kind(e) != ELF_K_ELF)
|
||||
errx(EXIT_FAILURE, "\"%s\" is not an ELF object.",
|
||||
argv[1]);
|
||||
|
||||
if (gelf_getehdr(e, &ehdr) == NULL) @\co{3}@
|
||||
errx(EXIT_FAILURE, "getehdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((i = gelf_getclass(e)) == ELFCLASSNONE) @\co{4}@
|
||||
errx(EXIT_FAILURE, "getclass() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) printf("%s: %d-bit ELF object\n", argv[1],
|
||||
i == ELFCLASS32 ? 32 : 64);
|
||||
|
||||
if ((id = elf_getident(e, NULL)) == NULL) @\co{5}@
|
||||
errx(EXIT_FAILURE, "getident() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) printf("%3s e_ident[0..%1d] %7s", " ",
|
||||
EI_ABIVERSION, " ");
|
||||
|
||||
for (i = 0; i <= EI_ABIVERSION; i++) {
|
||||
(void) vis(bytes, id[i], VIS_WHITE, 0);
|
||||
(void) printf(" ['%s' %X]", bytes, id[i]);
|
||||
}
|
||||
|
||||
(void) printf("\n");
|
||||
|
||||
#define PRINT_FMT " %-20s 0x%jx\n"
|
||||
#define PRINT_FIELD(N) do { \
|
||||
(void) printf(PRINT_FMT, #N, (uintmax_t) ehdr.N); \
|
||||
} while (0)
|
||||
|
||||
PRINT_FIELD(e_type); @\co{6}@
|
||||
PRINT_FIELD(e_machine);
|
||||
PRINT_FIELD(e_version);
|
||||
PRINT_FIELD(e_entry);
|
||||
PRINT_FIELD(e_phoff);
|
||||
PRINT_FIELD(e_shoff);
|
||||
PRINT_FIELD(e_flags);
|
||||
PRINT_FIELD(e_ehsize);
|
||||
PRINT_FIELD(e_phentsize);
|
||||
PRINT_FIELD(e_shentsize);
|
||||
|
||||
if (elf_getshdrnum(e, &n) != 0) @\co{7}@
|
||||
errx(EXIT_FAILURE, "getshdrnum() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
(void) printf(PRINT_FMT, "(shnum)", (uintmax_t) n);
|
||||
|
||||
if (elf_getshdrstrndx(e, &n) != 0) @\co{8}@
|
||||
errx(EXIT_FAILURE, "getshdrstrndx() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
(void) printf(PRINT_FMT, "(shstrndx)", (uintmax_t) n);
|
||||
|
||||
if (elf_getphdrnum(e, &n) != 0) @\co{9}@
|
||||
errx(EXIT_FAILURE, "getphdrnum() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
(void) printf(PRINT_FMT, "(phnum)", (uintmax_t) n);
|
||||
|
||||
(void) elf_end(e);
|
||||
(void) close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
102
documentation/libelf-by-example/prog3.txt
Normal file
102
documentation/libelf-by-example/prog3.txt
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Print the ELF Program Header Table in an ELF object.
|
||||
*
|
||||
* $Id: prog3.txt 2133 2011-11-10 08:28:22Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h> @\co{1}@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
|
||||
void
|
||||
print_ptype(size_t pt) @\co{7}@
|
||||
{
|
||||
char *s;
|
||||
|
||||
#define C(V) case PT_##V: s = #V; break
|
||||
switch (pt) {
|
||||
C(NULL); C(LOAD); C(DYNAMIC);
|
||||
C(INTERP); C(NOTE); C(SHLIB);
|
||||
C(PHDR); C(TLS); C(SUNW_UNWIND);
|
||||
C(SUNWBSS); C(SUNWSTACK); C(SUNWDTRACE);
|
||||
C(SUNWCAP);
|
||||
default:
|
||||
s = "unknown";
|
||||
break;
|
||||
}
|
||||
(void) printf(" \"%s\"", s);
|
||||
#undef C
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i, fd;
|
||||
Elf *e;
|
||||
char *id, bytes[5];
|
||||
size_t n;
|
||||
GElf_Phdr phdr; @\co{2}@
|
||||
|
||||
if (argc != 2)
|
||||
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "ELF library initialization "
|
||||
"failed: %s", elf_errmsg(-1));
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY, 0)) < 0)
|
||||
err(EXIT_FAILURE, "open \"%s\" failed", argv[1]);
|
||||
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if (elf_kind(e) != ELF_K_ELF)
|
||||
errx(EXIT_FAILURE, "\"%s\" is not an ELF object.",
|
||||
argv[1]);
|
||||
|
||||
if (elf_getphdrnum(e, &n) != 0) @\co{3}@
|
||||
errx(EXIT_FAILURE, "elf_getphdrnum() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
for (i = 0; i < n; i++) { @\co{4}@
|
||||
if (gelf_getphdr(e, i, &phdr) != &phdr) @\co{5}@
|
||||
errx(EXIT_FAILURE, "getphdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) printf("PHDR %d:\n", i);
|
||||
#define PRINT_FMT " %-20s 0x%jx"
|
||||
#define PRINT_FIELD(N) do { \
|
||||
(void) printf(PRINT_FMT, #N, (uintmax_t) phdr.N); \
|
||||
} while (0)
|
||||
#define NL() do { (void) printf("\n"); } while (0)
|
||||
PRINT_FIELD(p_type); @\co{6}@
|
||||
print_ptype(phdr.p_type); NL();
|
||||
PRINT_FIELD(p_offset); NL();
|
||||
PRINT_FIELD(p_vaddr); NL();
|
||||
PRINT_FIELD(p_paddr); NL();
|
||||
PRINT_FIELD(p_filesz); NL();
|
||||
PRINT_FIELD(p_memsz); NL();
|
||||
PRINT_FIELD(p_flags);
|
||||
(void) printf(" [");
|
||||
if (phdr.p_flags & PF_X)
|
||||
(void) printf(" execute");
|
||||
if (phdr.p_flags & PF_R)
|
||||
(void) printf(" read");
|
||||
if (phdr.p_flags & PF_W)
|
||||
(void) printf(" write");
|
||||
printf(" ]"); NL();
|
||||
PRINT_FIELD(p_align); NL();
|
||||
}
|
||||
|
||||
(void) elf_end(e);
|
||||
(void) close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
92
documentation/libelf-by-example/prog4.txt
Normal file
92
documentation/libelf-by-example/prog4.txt
Normal file
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Print the names of ELF sections.
|
||||
*
|
||||
* $Id: prog4.txt 2133 2011-11-10 08:28:22Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <vis.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
Elf *e;
|
||||
char *name, *p, pc[4*sizeof(char)];
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *data;
|
||||
GElf_Shdr shdr;
|
||||
size_t n, shstrndx, sz;
|
||||
|
||||
if (argc != 2)
|
||||
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "ELF library initialization "
|
||||
"failed: %s", elf_errmsg(-1));
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY, 0)) < 0)
|
||||
err(EXIT_FAILURE, "open \%s\" failed", argv[1]);
|
||||
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if (elf_kind(e) != ELF_K_ELF)
|
||||
errx(EXIT_FAILURE, "%s is not an ELF object.",
|
||||
argv[1]);
|
||||
|
||||
if (elf_getshdrstrndx(e, &shstrndx) != 0) @\co{1}@
|
||||
errx(EXIT_FAILURE, "elf_getshdrstrndx() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
scn = NULL; @\co{2}@
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) { @\co{3}@
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) @\co{4}@
|
||||
errx(EXIT_FAILURE, "getshdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((name = elf_strptr(e, shstrndx, shdr.sh_name))
|
||||
== NULL) @\co{5}@
|
||||
errx(EXIT_FAILURE, "elf_strptr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) printf("Section %-4.4jd %s\n", (uintmax_t)
|
||||
elf_ndxscn(scn), name);
|
||||
}
|
||||
|
||||
if ((scn = elf_getscn(e, shstrndx)) == NULL) @\co{6}@
|
||||
errx(EXIT_FAILURE, "getscn() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr)
|
||||
errx(EXIT_FAILURE, "getshdr(shstrndx) failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) printf(".shstrab: size=%jd\n", (uintmax_t)
|
||||
shdr.sh_size);
|
||||
|
||||
data = NULL; n = 0;
|
||||
while (n < shdr.sh_size &&
|
||||
(data = elf_getdata(scn, data)) != NULL) { @\co{7}@
|
||||
p = (char *) data->d_buf;
|
||||
while (p < (char *) data->d_buf + data->d_size) {
|
||||
if (vis(pc, *p, VIS_WHITE, 0))
|
||||
printf("%s", pc);
|
||||
n++; p++;
|
||||
(void) putchar((n % 16) ? ' ' : '\n');
|
||||
}
|
||||
}
|
||||
(void) putchar('\n');
|
||||
|
||||
(void) elf_end(e);
|
||||
(void) close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
133
documentation/libelf-by-example/prog5.txt
Normal file
133
documentation/libelf-by-example/prog5.txt
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Create an ELF object.
|
||||
*
|
||||
* $Id: prog5.txt 2133 2011-11-10 08:28:22Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <libelf.h> @\co{1}@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
uint32_t hash_words[] = { @\co{2}@
|
||||
0x01234567,
|
||||
0x89abcdef,
|
||||
0xdeadc0de
|
||||
};
|
||||
|
||||
char string_table[] = { @\co{3}@
|
||||
/* Offset 0 */ '\0',
|
||||
/* Offset 1 */ '.', 'f', 'o', 'o', '\0',
|
||||
/* Offset 6 */ '.', 's', 'h', 's', 't',
|
||||
'r', 't', 'a', 'b', '\0'
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
Elf *e;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *data;
|
||||
Elf32_Ehdr *ehdr;
|
||||
Elf32_Phdr *phdr;
|
||||
Elf32_Shdr *shdr;
|
||||
|
||||
if (argc != 2)
|
||||
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "ELF library initialization "
|
||||
"failed: %s", elf_errmsg(-1));
|
||||
|
||||
if ((fd = open(argv[1], O_WRONLY|O_CREAT, 0777)) < 0) @\co{4}@
|
||||
err(EXIT_FAILURE, "open \%s\" failed", argv[1]);
|
||||
|
||||
if ((e = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL) @\co{5}@
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((ehdr = elf32_newehdr(e)) == NULL) @\co{6}@
|
||||
errx(EXIT_FAILURE, "elf32_newehdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
||||
ehdr->e_machine = EM_PPC; /* 32-bit PowerPC object */
|
||||
ehdr->e_type = ET_EXEC;
|
||||
|
||||
if ((phdr = elf32_newphdr(e, 1)) == NULL) @\co{7}@
|
||||
errx(EXIT_FAILURE, "elf32_newphdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((scn = elf_newscn(e)) == NULL) @\co{8}@
|
||||
errx(EXIT_FAILURE, "elf_newscn() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((data = elf_newdata(scn)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
data->d_align = 4;
|
||||
data->d_off = 0LL;
|
||||
data->d_buf = hash_words;
|
||||
data->d_type = ELF_T_WORD;
|
||||
data->d_size = sizeof(hash_words);
|
||||
data->d_version = EV_CURRENT;
|
||||
|
||||
if ((shdr = elf32_getshdr(scn)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf32_getshdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
shdr->sh_name = 1;
|
||||
shdr->sh_type = SHT_HASH;
|
||||
shdr->sh_flags = SHF_ALLOC;
|
||||
shdr->sh_entsize = 0;
|
||||
|
||||
if ((scn = elf_newscn(e)) == NULL) @\co{9}@
|
||||
errx(EXIT_FAILURE, "elf_newscn() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((data = elf_newdata(scn)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
data->d_align = 1;
|
||||
data->d_buf = string_table;
|
||||
data->d_off = 0LL;
|
||||
data->d_size = sizeof(string_table);
|
||||
data->d_type = ELF_T_BYTE;
|
||||
data->d_version = EV_CURRENT;
|
||||
|
||||
if ((shdr = elf32_getshdr(scn)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf32_getshdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
shdr->sh_name = 6;
|
||||
shdr->sh_type = SHT_STRTAB;
|
||||
shdr->sh_flags = SHF_STRINGS | SHF_ALLOC;
|
||||
shdr->sh_entsize = 0;
|
||||
|
||||
elf_setshstrndx(e, elf_ndxscn(scn)); @\co{10}@
|
||||
|
||||
if (elf_update(e, ELF_C_NULL) < 0) @\co{11}@
|
||||
errx(EXIT_FAILURE, "elf_update(NULL) failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
phdr->p_type = PT_PHDR;
|
||||
phdr->p_offset = ehdr->e_phoff;
|
||||
phdr->p_filesz = elf32_fsize(ELF_T_PHDR, 1, EV_CURRENT);
|
||||
|
||||
(void) elf_flagphdr(e, ELF_C_SET, ELF_F_DIRTY);
|
||||
|
||||
if (elf_update(e, ELF_C_WRITE) < 0) @\co{12}@
|
||||
errx(EXIT_FAILURE, "elf_update() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) elf_end(e);
|
||||
(void) close(fd);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
57
documentation/libelf-by-example/prog6.txt
Normal file
57
documentation/libelf-by-example/prog6.txt
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Iterate through an ar(1) archive.
|
||||
*
|
||||
* $Id: prog6.txt 2135 2011-11-10 08:59:47Z jkoshy $
|
||||
*/
|
||||
|
||||
#include <err.h>
|
||||
#include <fcntl.h>
|
||||
#include <libelf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
Elf *ar, *e;
|
||||
Elf_Arhdr *arh;
|
||||
|
||||
if (argc != 2)
|
||||
errx(EXIT_FAILURE, "usage: %s file-name", argv[0]);
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "ELF library initialization "
|
||||
"failed: %s", elf_errmsg(-1));
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY, 0)) < 0)
|
||||
err(EXIT_FAILURE, "open \%s\" failed", argv[1]);
|
||||
|
||||
if ((fd = open(argv[1], O_RDONLY, 0)) < 0) @\co{1}@
|
||||
err(EXIT_FAILURE, "open \%s\" failed", argv[1]);
|
||||
|
||||
if ((ar = elf_begin(fd, ELF_C_READ, NULL)) == NULL) @\co{2}@
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
if (elf_kind(ar) != ELF_K_AR)
|
||||
errx(EXIT_FAILURE, "%s is not an ar(1) archive.",
|
||||
argv[1]);
|
||||
|
||||
while ((e = elf_begin(fd, ELF_C_READ, ar)) != NULL) { @\co{3}@
|
||||
if ((arh = elf_getarhdr(e)) == NULL) @\co{4}@
|
||||
errx(EXIT_FAILURE, "elf_getarhdr() failed: %s.",
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) printf("%20s %zd\n", arh->ar_name,
|
||||
arh->ar_size);
|
||||
|
||||
(void) elf_next(e); @\co{5}@
|
||||
(void) elf_end(e); @\co{6}@
|
||||
}
|
||||
|
||||
(void) elf_end(ar);
|
||||
(void) close(fd);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
41
elfcopy/Makefile
Normal file
41
elfcopy/Makefile
Normal file
|
@ -0,0 +1,41 @@
|
|||
# $Id: Makefile 2290 2011-12-04 07:20:46Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= elfcopy
|
||||
|
||||
SRCS= archive.c ascii.c binary.c main.c sections.c segments.c symbols.c
|
||||
|
||||
WARNS?= 5
|
||||
|
||||
DPADD= ${LIBELF} ${LIBELFTC}
|
||||
LDADD= -lelf -lelftc
|
||||
|
||||
.if !defined(LIBELF_AR)
|
||||
LDADD+= -larchive
|
||||
.endif
|
||||
|
||||
MAN= elfcopy.1 mcs.1 strip.1
|
||||
|
||||
NO_SHARED?= yes
|
||||
|
||||
LINKS= ${BINDIR}/elfcopy ${BINDIR}/strip \
|
||||
${BINDIR}/elfcopy ${BINDIR}/mcs
|
||||
|
||||
EXTRA_TARGETS= strip mcs
|
||||
|
||||
CLEANFILES+= ${EXTRA_TARGETS}
|
||||
|
||||
# Create in-place symbolic links to "elfcopy" at build time.
|
||||
|
||||
all: ${EXTRA_TARGETS}
|
||||
|
||||
${EXTRA_TARGETS}: ${PROG}
|
||||
ln -s ${PROG} ${.TARGET}
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
||||
|
||||
.if ${OS_HOST} == "OpenBSD"
|
||||
CFLAGS+= -I/usr/local/include
|
||||
LDFLAGS+= -L/usr/local/lib
|
||||
.endif
|
528
elfcopy/archive.c
Normal file
528
elfcopy/archive.c
Normal file
|
@ -0,0 +1,528 @@
|
|||
/*-
|
||||
* Copyright (c) 2007-2009 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef LIBELF_AR
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
#endif /* ! LIBELF_AR */
|
||||
|
||||
#include "elfcopy.h"
|
||||
|
||||
ELFTC_VCSID("$Id: archive.c 2370 2011-12-29 12:48:12Z jkoshy $");
|
||||
|
||||
#define _ARMAG_LEN 8 /* length of ar magic string */
|
||||
#define _ARHDR_LEN 60 /* length of ar header */
|
||||
#define _INIT_AS_CAP 128 /* initial archive string table size */
|
||||
#define _INIT_SYMOFF_CAP (256*(sizeof(uint32_t))) /* initial so table size */
|
||||
#define _INIT_SYMNAME_CAP 1024 /* initial sn table size */
|
||||
#define _MAXNAMELEN_SVR4 15 /* max member name length in svr4 variant */
|
||||
|
||||
#ifndef LIBELF_AR
|
||||
static void ac_read_objs(struct elfcopy *ecp, int ifd);
|
||||
static void ac_write_cleanup(struct elfcopy *ecp);
|
||||
static void ac_write_data(struct archive *a, const void *buf, size_t s);
|
||||
static void ac_write_objs(struct elfcopy *ecp, int ofd);
|
||||
#endif /* ! LIBELF_AR */
|
||||
static void add_to_ar_str_table(struct elfcopy *elfcopy, const char *name);
|
||||
static void add_to_ar_sym_table(struct elfcopy *ecp, const char *name);
|
||||
static void extract_arsym(struct elfcopy *ecp);
|
||||
static void process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj);
|
||||
static void sync_ar(struct elfcopy *ecp);
|
||||
|
||||
|
||||
static void
|
||||
process_ar_obj(struct elfcopy *ecp, struct ar_obj *obj)
|
||||
{
|
||||
struct stat sb;
|
||||
char *tempfile;
|
||||
int fd;
|
||||
|
||||
/* Output to a temporary file. */
|
||||
create_tempfile(&tempfile, &fd);
|
||||
if ((ecp->eout = elf_begin(fd, ELF_C_WRITE, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
elf_flagelf(ecp->eout, ELF_C_SET, ELF_F_LAYOUT);
|
||||
create_elf(ecp);
|
||||
elf_end(ecp->ein);
|
||||
elf_end(ecp->eout);
|
||||
free(obj->buf);
|
||||
obj->buf = NULL;
|
||||
|
||||
/* Extract archive symbols. */
|
||||
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||
err(EXIT_FAILURE, "lseek failed for '%s'", tempfile);
|
||||
if ((ecp->eout = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
extract_arsym(ecp);
|
||||
elf_end(ecp->eout);
|
||||
|
||||
if (fstat(fd, &sb) == -1)
|
||||
err(EXIT_FAILURE, "fstat %s failed", tempfile);
|
||||
if (lseek(fd, 0, SEEK_SET) < 0)
|
||||
err(EXIT_FAILURE, "lseek %s failed", tempfile);
|
||||
obj->size = sb.st_size;
|
||||
if ((obj->maddr = malloc(obj->size)) == NULL)
|
||||
err(EXIT_FAILURE, "memory allocation failed for '%s'",
|
||||
tempfile);
|
||||
if ((size_t) read(fd, obj->maddr, obj->size) != obj->size)
|
||||
err(EXIT_FAILURE, "read failed for '%s'", tempfile);
|
||||
if (unlink(tempfile))
|
||||
err(EXIT_FAILURE, "unlink %s failed", tempfile);
|
||||
free(tempfile);
|
||||
close(fd);
|
||||
if (strlen(obj->name) > _MAXNAMELEN_SVR4)
|
||||
add_to_ar_str_table(ecp, obj->name);
|
||||
ecp->rela_off += _ARHDR_LEN + obj->size + obj->size % 2;
|
||||
STAILQ_INSERT_TAIL(&ecp->v_arobj, obj, objs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append to the archive string table buffer.
|
||||
*/
|
||||
static void
|
||||
add_to_ar_str_table(struct elfcopy *ecp, const char *name)
|
||||
{
|
||||
|
||||
if (ecp->as == NULL) {
|
||||
ecp->as_cap = _INIT_AS_CAP;
|
||||
ecp->as_sz = 0;
|
||||
if ((ecp->as = malloc(ecp->as_cap)) == NULL)
|
||||
err(EXIT_FAILURE, "malloc failed");
|
||||
}
|
||||
|
||||
/*
|
||||
* The space required for holding one member name in as table includes:
|
||||
* strlen(name) + (1 for '/') + (1 for '\n') + (possibly 1 for padding).
|
||||
*/
|
||||
while (ecp->as_sz + strlen(name) + 3 > ecp->as_cap) {
|
||||
ecp->as_cap *= 2;
|
||||
ecp->as = realloc(ecp->as, ecp->as_cap);
|
||||
if (ecp->as == NULL)
|
||||
err(EXIT_FAILURE, "realloc failed");
|
||||
}
|
||||
strncpy(&ecp->as[ecp->as_sz], name, strlen(name));
|
||||
ecp->as_sz += strlen(name);
|
||||
ecp->as[ecp->as_sz++] = '/';
|
||||
ecp->as[ecp->as_sz++] = '\n';
|
||||
}
|
||||
|
||||
/*
|
||||
* Append to the archive symbol table buffer.
|
||||
*/
|
||||
static void
|
||||
add_to_ar_sym_table(struct elfcopy *ecp, const char *name)
|
||||
{
|
||||
|
||||
if (ecp->s_so == NULL) {
|
||||
if ((ecp->s_so = malloc(_INIT_SYMOFF_CAP)) == NULL)
|
||||
err(EXIT_FAILURE, "malloc failed");
|
||||
ecp->s_so_cap = _INIT_SYMOFF_CAP;
|
||||
ecp->s_cnt = 0;
|
||||
}
|
||||
|
||||
if (ecp->s_sn == NULL) {
|
||||
if ((ecp->s_sn = malloc(_INIT_SYMNAME_CAP)) == NULL)
|
||||
err(EXIT_FAILURE, "malloc failed");
|
||||
ecp->s_sn_cap = _INIT_SYMNAME_CAP;
|
||||
ecp->s_sn_sz = 0;
|
||||
}
|
||||
|
||||
if (ecp->s_cnt * sizeof(uint32_t) >= ecp->s_so_cap) {
|
||||
ecp->s_so_cap *= 2;
|
||||
ecp->s_so = realloc(ecp->s_so, ecp->s_so_cap);
|
||||
if (ecp->s_so == NULL)
|
||||
err(EXIT_FAILURE, "realloc failed");
|
||||
}
|
||||
ecp->s_so[ecp->s_cnt] = ecp->rela_off;
|
||||
ecp->s_cnt++;
|
||||
|
||||
/*
|
||||
* The space required for holding one symbol name in sn table includes:
|
||||
* strlen(name) + (1 for '\n') + (possibly 1 for padding).
|
||||
*/
|
||||
while (ecp->s_sn_sz + strlen(name) + 2 > ecp->s_sn_cap) {
|
||||
ecp->s_sn_cap *= 2;
|
||||
ecp->s_sn = realloc(ecp->s_sn, ecp->s_sn_cap);
|
||||
if (ecp->s_sn == NULL)
|
||||
err(EXIT_FAILURE, "realloc failed");
|
||||
}
|
||||
strncpy(&ecp->s_sn[ecp->s_sn_sz], name, strlen(name));
|
||||
ecp->s_sn_sz += strlen(name);
|
||||
ecp->s_sn[ecp->s_sn_sz++] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
sync_ar(struct elfcopy *ecp)
|
||||
{
|
||||
size_t s_sz; /* size of archive symbol table. */
|
||||
size_t pm_sz; /* size of pseudo members */
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Pad the symbol name string table. It is treated specially because
|
||||
* symbol name table should be padded by a '\0', not the common '\n'
|
||||
* for other members. The size of sn table includes the pad bit.
|
||||
*/
|
||||
if (ecp->s_cnt != 0 && ecp->s_sn_sz % 2 != 0)
|
||||
ecp->s_sn[ecp->s_sn_sz++] = '\0';
|
||||
|
||||
/*
|
||||
* Archive string table is padded by a "\n" as the normal members.
|
||||
* The difference is that the size of archive string table counts
|
||||
* in the pad bit, while normal members' size fileds do not.
|
||||
*/
|
||||
if (ecp->as != NULL && ecp->as_sz % 2 != 0)
|
||||
ecp->as[ecp->as_sz++] = '\n';
|
||||
|
||||
/*
|
||||
* If there is a symbol table, calculate the size of pseudo members,
|
||||
* convert previously stored relative offsets to absolute ones, and
|
||||
* then make them Big Endian.
|
||||
*
|
||||
* absolute_offset = htobe32(relative_offset + size_of_pseudo_members)
|
||||
*/
|
||||
|
||||
if (ecp->s_cnt != 0) {
|
||||
s_sz = (ecp->s_cnt + 1) * sizeof(uint32_t) + ecp->s_sn_sz;
|
||||
pm_sz = _ARMAG_LEN + (_ARHDR_LEN + s_sz);
|
||||
if (ecp->as != NULL)
|
||||
pm_sz += _ARHDR_LEN + ecp->as_sz;
|
||||
for (i = 0; (size_t)i < ecp->s_cnt; i++)
|
||||
*(ecp->s_so + i) = htobe32(*(ecp->s_so + i) +
|
||||
pm_sz);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract global symbols from archive members.
|
||||
*/
|
||||
static void
|
||||
extract_arsym(struct elfcopy *ecp)
|
||||
{
|
||||
Elf_Scn *scn;
|
||||
GElf_Shdr shdr;
|
||||
GElf_Sym sym;
|
||||
Elf_Data *data;
|
||||
char *name;
|
||||
size_t n, shstrndx;
|
||||
int elferr, tabndx, len, i;
|
||||
|
||||
if (elf_kind(ecp->eout) != ELF_K_ELF) {
|
||||
warnx("internal: cannot extract symbols from non-elf object");
|
||||
return;
|
||||
}
|
||||
if (elf_getshstrndx(ecp->eout, &shstrndx) == 0) {
|
||||
warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
tabndx = -1;
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||
warnx("elf_getshdr failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if ((name = elf_strptr(ecp->eout, shstrndx, shdr.sh_name)) ==
|
||||
NULL) {
|
||||
warnx("elf_strptr failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (strcmp(name, ".strtab") == 0) {
|
||||
tabndx = elf_ndxscn(scn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||
|
||||
/* Ignore members without symbol table. */
|
||||
if (tabndx == -1)
|
||||
return;
|
||||
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(ecp->eout, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||
warnx("elf_getshdr failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (shdr.sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
|
||||
data = NULL;
|
||||
n = 0;
|
||||
while (n < shdr.sh_size &&
|
||||
(data = elf_getdata(scn, data)) != NULL) {
|
||||
len = data->d_size / shdr.sh_entsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (gelf_getsym(data, i, &sym) != &sym) {
|
||||
warnx("gelf_getsym failed: %s",
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* keep only global or weak symbols */
|
||||
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL &&
|
||||
GELF_ST_BIND(sym.st_info) != STB_WEAK)
|
||||
continue;
|
||||
|
||||
/* keep only defined symbols */
|
||||
if (sym.st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
|
||||
if ((name = elf_strptr(ecp->eout, tabndx,
|
||||
sym.st_name)) == NULL) {
|
||||
warnx("elf_strptr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
|
||||
add_to_ar_sym_table(ecp, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||
}
|
||||
|
||||
#ifndef LIBELF_AR
|
||||
|
||||
/*
|
||||
* Convenient wrapper for general libarchive error handling.
|
||||
*/
|
||||
#define AC(CALL) do { \
|
||||
if ((CALL)) \
|
||||
errx(EXIT_FAILURE, "%s", archive_error_string(a)); \
|
||||
} while (0)
|
||||
|
||||
/* Earlier versions of libarchive had some functions that returned 'void'. */
|
||||
#if ARCHIVE_VERSION_NUMBER >= 2000000
|
||||
#define ACV(CALL) AC(CALL)
|
||||
#else
|
||||
#define ACV(CALL) do { \
|
||||
(CALL); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
int
|
||||
ac_detect_ar(int ifd)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
int r;
|
||||
|
||||
r = -1;
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
return (0);
|
||||
archive_read_support_compression_none(a);
|
||||
archive_read_support_format_ar(a);
|
||||
if (archive_read_open_fd(a, ifd, 10240) == ARCHIVE_OK)
|
||||
r = archive_read_next_header(a, &entry);
|
||||
archive_read_close(a);
|
||||
archive_read_finish(a);
|
||||
|
||||
return (r == ARCHIVE_OK);
|
||||
}
|
||||
|
||||
void
|
||||
ac_create_ar(struct elfcopy *ecp, int ifd, int ofd)
|
||||
{
|
||||
|
||||
ac_read_objs(ecp, ifd);
|
||||
sync_ar(ecp);
|
||||
ac_write_objs(ecp, ofd);
|
||||
ac_write_cleanup(ecp);
|
||||
}
|
||||
|
||||
static void
|
||||
ac_read_objs(struct elfcopy *ecp, int ifd)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
struct ar_obj *obj;
|
||||
const char *name;
|
||||
char *buff;
|
||||
size_t size;
|
||||
int r;
|
||||
|
||||
ecp->rela_off = 0;
|
||||
if (lseek(ifd, 0, SEEK_SET) == -1)
|
||||
err(EXIT_FAILURE, "lseek failed");
|
||||
if ((a = archive_read_new()) == NULL)
|
||||
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||
archive_read_support_compression_none(a);
|
||||
archive_read_support_format_ar(a);
|
||||
AC(archive_read_open_fd(a, ifd, 10240));
|
||||
for(;;) {
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_FATAL)
|
||||
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r == ARCHIVE_WARN || r == ARCHIVE_RETRY)
|
||||
warnx("%s", archive_error_string(a));
|
||||
if (r == ARCHIVE_RETRY)
|
||||
continue;
|
||||
|
||||
name = archive_entry_pathname(entry);
|
||||
|
||||
/* skip pseudo members. */
|
||||
if (strcmp(name, "/") == 0 || strcmp(name, "//") == 0)
|
||||
continue;
|
||||
|
||||
size = archive_entry_size(entry);
|
||||
|
||||
if (size > 0) {
|
||||
if ((buff = malloc(size)) == NULL)
|
||||
err(EXIT_FAILURE, "malloc failed");
|
||||
if (archive_read_data(a, buff, size) != (ssize_t)size) {
|
||||
warnx("%s", archive_error_string(a));
|
||||
free(buff);
|
||||
continue;
|
||||
}
|
||||
if ((obj = malloc(sizeof(*obj))) == NULL)
|
||||
err(EXIT_FAILURE, "malloc failed");
|
||||
if ((obj->name = strdup(name)) == NULL)
|
||||
err(EXIT_FAILURE, "strdup failed");
|
||||
obj->buf = buff;
|
||||
obj->uid = archive_entry_uid(entry);
|
||||
obj->gid = archive_entry_gid(entry);
|
||||
obj->md = archive_entry_mode(entry);
|
||||
obj->mtime = archive_entry_mtime(entry);
|
||||
if ((ecp->ein = elf_memory(buff, size)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_memory() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
if (elf_kind(ecp->ein) != ELF_K_ELF)
|
||||
errx(EXIT_FAILURE,
|
||||
"file format not recognized");
|
||||
process_ar_obj(ecp, obj);
|
||||
}
|
||||
}
|
||||
AC(archive_read_close(a));
|
||||
ACV(archive_read_finish(a));
|
||||
}
|
||||
|
||||
static void
|
||||
ac_write_objs(struct elfcopy *ecp, int ofd)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
struct ar_obj *obj;
|
||||
int nr;
|
||||
|
||||
if ((a = archive_write_new()) == NULL)
|
||||
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||
archive_write_set_format_ar_svr4(a);
|
||||
archive_write_set_compression_none(a);
|
||||
AC(archive_write_open_fd(a, ofd));
|
||||
|
||||
/* Write the archive symbol table, even if it's empty. */
|
||||
entry = archive_entry_new();
|
||||
archive_entry_copy_pathname(entry, "/");
|
||||
archive_entry_set_mtime(entry, time(NULL), 0);
|
||||
archive_entry_set_size(entry, (ecp->s_cnt + 1) * sizeof(uint32_t) +
|
||||
ecp->s_sn_sz);
|
||||
AC(archive_write_header(a, entry));
|
||||
nr = htobe32(ecp->s_cnt);
|
||||
ac_write_data(a, &nr, sizeof(uint32_t));
|
||||
ac_write_data(a, ecp->s_so, sizeof(uint32_t) * ecp->s_cnt);
|
||||
ac_write_data(a, ecp->s_sn, ecp->s_sn_sz);
|
||||
archive_entry_free(entry);
|
||||
|
||||
/* Write the archive string table, if exist. */
|
||||
if (ecp->as != NULL) {
|
||||
entry = archive_entry_new();
|
||||
archive_entry_copy_pathname(entry, "//");
|
||||
archive_entry_set_size(entry, ecp->as_sz);
|
||||
AC(archive_write_header(a, entry));
|
||||
ac_write_data(a, ecp->as, ecp->as_sz);
|
||||
archive_entry_free(entry);
|
||||
}
|
||||
|
||||
/* Write normal members. */
|
||||
STAILQ_FOREACH(obj, &ecp->v_arobj, objs) {
|
||||
entry = archive_entry_new();
|
||||
archive_entry_copy_pathname(entry, obj->name);
|
||||
archive_entry_set_uid(entry, obj->uid);
|
||||
archive_entry_set_gid(entry, obj->gid);
|
||||
archive_entry_set_mode(entry, obj->md);
|
||||
archive_entry_set_size(entry, obj->size);
|
||||
archive_entry_set_mtime(entry, obj->mtime, 0);
|
||||
archive_entry_set_filetype(entry, AE_IFREG);
|
||||
AC(archive_write_header(a, entry));
|
||||
ac_write_data(a, obj->maddr, obj->size);
|
||||
archive_entry_free(entry);
|
||||
}
|
||||
|
||||
AC(archive_write_close(a));
|
||||
ACV(archive_write_finish(a));
|
||||
}
|
||||
|
||||
static void
|
||||
ac_write_cleanup(struct elfcopy *ecp)
|
||||
{
|
||||
struct ar_obj *obj, *obj_temp;
|
||||
|
||||
STAILQ_FOREACH_SAFE(obj, &ecp->v_arobj, objs, obj_temp) {
|
||||
STAILQ_REMOVE(&ecp->v_arobj, obj, ar_obj, objs);
|
||||
if (obj->maddr != NULL)
|
||||
free(obj->maddr);
|
||||
free(obj->name);
|
||||
free(obj);
|
||||
}
|
||||
|
||||
free(ecp->as);
|
||||
free(ecp->s_so);
|
||||
free(ecp->s_sn);
|
||||
ecp->as = NULL;
|
||||
ecp->s_so = NULL;
|
||||
ecp->s_sn = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper for archive_write_data().
|
||||
*/
|
||||
static void
|
||||
ac_write_data(struct archive *a, const void *buf, size_t s)
|
||||
{
|
||||
if (archive_write_data(a, buf, s) != (ssize_t)s)
|
||||
errx(EXIT_FAILURE, "%s", archive_error_string(a));
|
||||
}
|
||||
|
||||
#endif /* ! LIBELF_AR */
|
1078
elfcopy/ascii.c
Normal file
1078
elfcopy/ascii.c
Normal file
File diff suppressed because it is too large
Load diff
286
elfcopy/binary.c
Normal file
286
elfcopy/binary.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*-
|
||||
* Copyright (c) 2010,2011 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <err.h>
|
||||
#include <gelf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "elfcopy.h"
|
||||
|
||||
ELFTC_VCSID("$Id: binary.c 2358 2011-12-19 18:22:32Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* Convert ELF object to `binary'. Sections with SHF_ALLOC flag set
|
||||
* are copied to the result binary. The relative offsets for each section
|
||||
* are retained, so the result binary file might contain "holes".
|
||||
*/
|
||||
void
|
||||
create_binary(int ifd, int ofd)
|
||||
{
|
||||
Elf *e;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *d;
|
||||
GElf_Shdr sh;
|
||||
off_t base, off;
|
||||
int elferr;
|
||||
|
||||
if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_begin() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
base = 0;
|
||||
if (lseek(ofd, base, SEEK_SET) < 0)
|
||||
err(EXIT_FAILURE, "lseek failed");
|
||||
|
||||
/*
|
||||
* Find base offset in the first iteration.
|
||||
*/
|
||||
base = -1;
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
|
||||
(void) elf_errno();
|
||||
continue;
|
||||
}
|
||||
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
|
||||
sh.sh_type == SHT_NOBITS ||
|
||||
sh.sh_size == 0)
|
||||
continue;
|
||||
if (base == -1 || (off_t) sh.sh_offset < base)
|
||||
base = sh.sh_offset;
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||
|
||||
if (base == -1)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Write out sections in the second iteration.
|
||||
*/
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||
warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
|
||||
(void) elf_errno();
|
||||
continue;
|
||||
}
|
||||
if ((sh.sh_flags & SHF_ALLOC) == 0 ||
|
||||
sh.sh_type == SHT_NOBITS ||
|
||||
sh.sh_size == 0)
|
||||
continue;
|
||||
(void) elf_errno();
|
||||
if ((d = elf_getdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("elf_getdata failed: %s", elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (d->d_buf == NULL || d->d_size == 0)
|
||||
continue;
|
||||
|
||||
/* lseek to section offset relative to `base'. */
|
||||
off = sh.sh_offset - base;
|
||||
if (lseek(ofd, off, SEEK_SET) < 0)
|
||||
err(EXIT_FAILURE, "lseek failed");
|
||||
|
||||
/* Write out section contents. */
|
||||
if (write(ofd, d->d_buf, d->d_size) != (ssize_t) d->d_size)
|
||||
err(EXIT_FAILURE, "write failed");
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("elf_nextscn failed: %s", elf_errmsg(elferr));
|
||||
}
|
||||
|
||||
#define _SYMBOL_NAMSZ 1024
|
||||
|
||||
/*
|
||||
* Convert `binary' to ELF object. The input `binary' is converted to
|
||||
* a relocatable (.o) file, a few symbols will also be created to make
|
||||
* it easier to access the binary data in other compilation units.
|
||||
*/
|
||||
void
|
||||
create_elf_from_binary(struct elfcopy *ecp, int ifd, const char *ifn)
|
||||
{
|
||||
char name[_SYMBOL_NAMSZ];
|
||||
struct section *sec, *sec_temp, *shtab;
|
||||
struct stat sb;
|
||||
GElf_Ehdr oeh;
|
||||
GElf_Shdr sh;
|
||||
void *content;
|
||||
uint64_t off, data_start, data_end, data_size;
|
||||
|
||||
/* Reset internal section list. */
|
||||
if (!TAILQ_EMPTY(&ecp->v_sec))
|
||||
TAILQ_FOREACH_SAFE(sec, &ecp->v_sec, sec_list, sec_temp) {
|
||||
TAILQ_REMOVE(&ecp->v_sec, sec, sec_list);
|
||||
free(sec);
|
||||
}
|
||||
|
||||
if (fstat(ifd, &sb) == -1)
|
||||
err(EXIT_FAILURE, "fstat failed");
|
||||
|
||||
/* Read the input binary file to a internal buffer. */
|
||||
if ((content = malloc(sb.st_size)) == NULL)
|
||||
err(EXIT_FAILURE, "malloc failed");
|
||||
if (read(ifd, content, sb.st_size) != sb.st_size)
|
||||
err(EXIT_FAILURE, "read failed");
|
||||
|
||||
/*
|
||||
* TODO: copy the input binary to output binary verbatim if -O is not
|
||||
* specified.
|
||||
*/
|
||||
|
||||
/* Create EHDR for output .o file. */
|
||||
if (gelf_newehdr(ecp->eout, ecp->oec) == NULL)
|
||||
errx(EXIT_FAILURE, "gelf_newehdr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
|
||||
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Initialise e_ident fields. */
|
||||
oeh.e_ident[EI_CLASS] = ecp->oec;
|
||||
oeh.e_ident[EI_DATA] = ecp->oed;
|
||||
/*
|
||||
* TODO: Set OSABI according to the OS platform where elfcopy(1)
|
||||
* was build. (probably)
|
||||
*/
|
||||
oeh.e_ident[EI_OSABI] = ELFOSABI_NONE;
|
||||
oeh.e_machine = ecp->oem;
|
||||
oeh.e_type = ET_REL;
|
||||
oeh.e_entry = 0;
|
||||
|
||||
ecp->flags |= RELOCATABLE;
|
||||
|
||||
/* Create .shstrtab section */
|
||||
init_shstrtab(ecp);
|
||||
ecp->shstrtab->off = 0;
|
||||
|
||||
/*
|
||||
* Create `.data' section which contains the binary data. The
|
||||
* section is inserted immediately after EHDR.
|
||||
*/
|
||||
off = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT);
|
||||
if (off == 0)
|
||||
errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
|
||||
(void) create_external_section(ecp, ".data", NULL, content, sb.st_size,
|
||||
off, SHT_PROGBITS, ELF_T_BYTE, SHF_ALLOC | SHF_WRITE, 1, 0, 1);
|
||||
|
||||
/* Insert .shstrtab after .data section. */
|
||||
if ((ecp->shstrtab->os = elf_newscn(ecp->eout)) == NULL)
|
||||
errx(EXIT_FAILURE, "elf_newscn failed: %s",
|
||||
elf_errmsg(-1));
|
||||
insert_to_sec_list(ecp, ecp->shstrtab, 1);
|
||||
|
||||
/* Insert section header table here. */
|
||||
shtab = insert_shtab(ecp, 1);
|
||||
|
||||
/* Count in .symtab and .strtab section headers. */
|
||||
shtab->sz += gelf_fsize(ecp->eout, ELF_T_SHDR, 2, EV_CURRENT);
|
||||
|
||||
#define _GEN_SYMNAME(S) do { \
|
||||
snprintf(name, sizeof(name), "%s%s%s", "_binary_", ifn, S); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Create symbol table.
|
||||
*/
|
||||
create_external_symtab(ecp);
|
||||
data_start = 0;
|
||||
data_end = data_start + sb.st_size;
|
||||
data_size = sb.st_size;
|
||||
_GEN_SYMNAME("_start");
|
||||
add_to_symtab(ecp, name, data_start, 0, 1,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
|
||||
_GEN_SYMNAME("_end");
|
||||
add_to_symtab(ecp, name, data_end, 0, 1,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
|
||||
_GEN_SYMNAME("_size");
|
||||
add_to_symtab(ecp, name, data_size, 0, SHN_ABS,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE), 0, 1);
|
||||
finalize_external_symtab(ecp);
|
||||
create_symtab_data(ecp);
|
||||
#undef _GEN_SYMNAME
|
||||
|
||||
/*
|
||||
* Write the underlying ehdr. Note that it should be called
|
||||
* before elf_setshstrndx() since it will overwrite e->e_shstrndx.
|
||||
*/
|
||||
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
|
||||
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Generate section name string table (.shstrtab). */
|
||||
ecp->flags |= SYMTAB_EXIST;
|
||||
set_shstrtab(ecp);
|
||||
|
||||
/* Update sh_name pointer for each section header entry. */
|
||||
update_shdr(ecp, 0);
|
||||
|
||||
/* Properly set sh_link field of .symtab section. */
|
||||
if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
|
||||
errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
sh.sh_link = elf_ndxscn(ecp->strtab->os);
|
||||
if (!gelf_update_shdr(ecp->symtab->os, &sh))
|
||||
errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Renew oeh to get the updated e_shstrndx. */
|
||||
if (gelf_getehdr(ecp->eout, &oeh) == NULL)
|
||||
errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Resync section offsets. */
|
||||
resync_sections(ecp);
|
||||
|
||||
/* Store SHDR offset in EHDR. */
|
||||
oeh.e_shoff = shtab->off;
|
||||
|
||||
/* Update ehdr since we modified e_shoff. */
|
||||
if (gelf_update_ehdr(ecp->eout, &oeh) == 0)
|
||||
errx(EXIT_FAILURE, "gelf_update_ehdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Write out the output elf object. */
|
||||
if (elf_update(ecp->eout, ELF_C_WRITE) < 0)
|
||||
errx(EXIT_FAILURE, "elf_update() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Release allocated resource. */
|
||||
free(content);
|
||||
free_elf(ecp);
|
||||
}
|
323
elfcopy/elfcopy.1
Normal file
323
elfcopy/elfcopy.1
Normal file
|
@ -0,0 +1,323 @@
|
|||
.\" Copyright (c) 2008-2009,2011 Joseph Koshy. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" This software is provided by Joseph Koshy ``as is'' and
|
||||
.\" any express or implied warranties, including, but not limited to, the
|
||||
.\" implied warranties of merchantability and fitness for a particular purpose
|
||||
.\" are disclaimed. in no event shall Joseph Koshy be liable
|
||||
.\" for any direct, indirect, incidental, special, exemplary, or consequential
|
||||
.\" damages (including, but not limited to, procurement of substitute goods
|
||||
.\" or services; loss of use, data, or profits; or business interruption)
|
||||
.\" however caused and on any theory of liability, whether in contract, strict
|
||||
.\" liability, or tort (including negligence or otherwise) arising in any way
|
||||
.\" out of the use of this software, even if advised of the possibility of
|
||||
.\" such damage.
|
||||
.\"
|
||||
.\" $Id: elfcopy.1 2373 2011-12-30 07:13:44Z jkoshy $
|
||||
.\"
|
||||
.Dd October 03, 2011
|
||||
.Os
|
||||
.Dt ELFCOPY 1
|
||||
.Sh NAME
|
||||
.Nm elfcopy
|
||||
.Nd copy and translate object files
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat
|
||||
.Op Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname
|
||||
.Op Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname
|
||||
.Op Fl N Ar symbolname | Fl -strip-symbol= Ns Ar symbolname
|
||||
.Op Fl O Ar objformat | Fl -output-target= Ns Ar objformat
|
||||
.Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||
.Op Fl S | Fl -strip-all
|
||||
.Op Fl V | Fl -version
|
||||
.Op Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname
|
||||
.Op Fl X | Fl -discard-locals
|
||||
.Op Fl d | Fl g | Fl -strip-debug
|
||||
.Op Fl h | Fl -help
|
||||
.Op Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname
|
||||
.Op Fl p | Fl -preserve-dates
|
||||
.Op Fl w | Fl -wildcard
|
||||
.Op Fl x | Fl -discard-all
|
||||
.Op Fl -add-section Ar sectionname Ns = Ns Ar filename
|
||||
.Oo
|
||||
.Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val |
|
||||
.Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val
|
||||
.Oc
|
||||
.Oo
|
||||
.Fl -adjust-start Ns = Ns Ar increment |
|
||||
.Fl -change-start Ns = Ns Ar increment
|
||||
.Oc
|
||||
.Oo
|
||||
.Fl -adjust-vma Ns = Ns Ar increment |
|
||||
.Fl -change-addresses Ns = Ns Ar increment
|
||||
.Oc
|
||||
.Op Fl -adjust-warnings | Fl -change-warnings
|
||||
.Op Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val
|
||||
.Op Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val
|
||||
.Op Fl -gap-fill Ns = Ns Ar val
|
||||
.Op Fl -no-adjust-warnings | Fl -no-change-warnings
|
||||
.Op Fl -only-keep-debug
|
||||
.Op Fl -pad-to Ns = Ns Ar address
|
||||
.Op Fl -prefix-alloc-sections Ns = Ns Ar string
|
||||
.Op Fl -prefix-sections Ns = Ns Ar string
|
||||
.Op Fl -prefix-symbols Ns = Ns Ar string
|
||||
.Op Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags
|
||||
.Op Fl -set-section-flags Ar sectionname Ns = Ns Ar flags
|
||||
.Op Fl -set-start Ns = Ns Ar address
|
||||
.Op Fl -srec-forceS3
|
||||
.Op Fl -srec-len Ns = Ns Ar val
|
||||
.Op Fl -strip-unneeded
|
||||
.Ar infile
|
||||
.Op Ar outfile
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility copies the content of the ELF object named by argument
|
||||
.Ar infile
|
||||
to that named by argument
|
||||
.Ar outfile ,
|
||||
transforming it according to the command line options specified.
|
||||
If argument
|
||||
.Ar outfile
|
||||
is not specified,
|
||||
.Nm
|
||||
will create a temporary file and will subsequently rename it as
|
||||
.Ar infile .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility supports the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl I Ar objformat | Fl s Ar objformat | Fl -input-target= Ns Ar objformat
|
||||
Specify that the input file named by the argument
|
||||
.Ar infile
|
||||
is in the object format specified by the argument
|
||||
.Ar objformat .
|
||||
.It Fl K Ar symbolname | Fl -keep-symbol= Ns Ar symbolname
|
||||
Copy the symbol named by argument
|
||||
.Ar symbolname
|
||||
to the output.
|
||||
.It Fl L Ar symbolname | Fl -localize-symbol= Ns Ar symbolname
|
||||
Make the symbol named by argument
|
||||
.Ar symbolname
|
||||
local to the output file.
|
||||
.It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbolname
|
||||
Do not copy the symbol named by argument
|
||||
.Ar symbolname
|
||||
to the output.
|
||||
.It Fl O Ar objformat | Fl -output-target= Ns Ar objformat
|
||||
Write the output file using the object format specified in argument
|
||||
.Ar objformat .
|
||||
.It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||
Remove any section with name
|
||||
.Ar sectionname
|
||||
from the output file.
|
||||
.It Fl S | Fl -strip-all
|
||||
Do not copy symbol and relocation information to the target file.
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier and exit.
|
||||
.It Fl W Ar symbolname | Fl -weaken-symbol= Ns Ar symbolname
|
||||
Mark the symbol named by argument
|
||||
.Ar symbolname
|
||||
as weak in the output.
|
||||
.It Fl X | Fl -discard-locals
|
||||
Do not copy compiler generated local symbols to the output.
|
||||
.It Fl d | Fl g | Fl -strip-debug
|
||||
Do not copy debugging information to the target file.
|
||||
.It Fl h | Fl -help
|
||||
Display a help message and exit.
|
||||
.It Fl j Ar sectionname | Fl -only-section= Ns Ar sectionname
|
||||
Copy only the section named by argument
|
||||
.Ar sectionname
|
||||
to the output.
|
||||
.It Fl p | Fl -preserve-dates
|
||||
Set the access and modification times of the output file to the
|
||||
same as those of the input.
|
||||
.It Fl w | Fl -wildcard
|
||||
Use shell-style patterns to name symbols.
|
||||
The following meta-characters are recognized in patterns:
|
||||
.Bl -tag -width "...." -compact
|
||||
.It Li !
|
||||
If this is the first character of the pattern, invert the sense of the
|
||||
pattern match.
|
||||
.It Li *
|
||||
Matches any string of characters in a symbol name.
|
||||
.It Li ?
|
||||
Matches zero or one character in a symbol name.
|
||||
.It Li [
|
||||
Mark the start of a character class.
|
||||
.It Li \e
|
||||
Remove the special meaning of the next character in the pattern.
|
||||
.It Li ]
|
||||
Mark the end of a character class.
|
||||
.El
|
||||
.It Fl x | Fl -discard-all
|
||||
Do not copy non-global symbols to the output.
|
||||
.It Fl -add-section Ar sectionname Ns = Ns Ar filename
|
||||
Add a new section to the output file with name
|
||||
.Ar sectionname .
|
||||
The contents of the section are taken from the file named by
|
||||
argument
|
||||
.Ar filename .
|
||||
The size of the section will be the number of bytes in file
|
||||
.Ar filename .
|
||||
.It Xo
|
||||
.Fl -adjust-section-vma Ar section Ns {+|-|=} Ns Ar val |
|
||||
.Fl -change-section-address Ar section Ns {+|-|=} Ns Ar val
|
||||
.Xc
|
||||
Depending on the operator specified, increase, decrease or set both
|
||||
the virtual memory address and the load memory address of the section
|
||||
named by the argument
|
||||
.Ar section .
|
||||
The argument
|
||||
.Ar val
|
||||
specifies the desired increment, decrement or new value for the
|
||||
address.
|
||||
.It Xo
|
||||
.Fl -adjust-start Ns = Ns Ar increment |
|
||||
.Fl -change-start Ns = Ns Ar increment
|
||||
.Xc
|
||||
Increase the entry point address of the output ELF object by the value
|
||||
specified in the argument
|
||||
.Ar increment .
|
||||
.It Xo
|
||||
.Fl -adjust-vma Ns = Ns Ar increment |
|
||||
.Fl -change-addresses Ns = Ns Ar increment
|
||||
.Xc
|
||||
Increase the virtual memory address and the load memory address of all
|
||||
sections by the value specified by the argument
|
||||
.Ar increment .
|
||||
.It Fl -adjust-warnings | Fl -change-warnings
|
||||
Issue a warning if the section specified by the options
|
||||
.Fl -change-section-address ,
|
||||
.Fl -change-section-lma
|
||||
or
|
||||
.Fl -change-section-vma
|
||||
does not exist in the input object.
|
||||
This is the default.
|
||||
.It Fl -change-section-lma Ar section Ns {+|-|=} Ns Ar val
|
||||
Change or set the load memory address of the section named by the
|
||||
argument
|
||||
.Ar section .
|
||||
Depending on the operator specified, the value in argument
|
||||
.Ar val
|
||||
will be used as an increment, a decrement or as the new value
|
||||
of the load memory address.
|
||||
.It Fl -change-section-vma Ar section Ns {+|-|=} Ns Ar val
|
||||
Change or set the virtual memory address of the section named by the
|
||||
argument
|
||||
.Ar section .
|
||||
Depending on the operator specified, the value in argument
|
||||
.Ar val
|
||||
will be used as an increment, a decrement or as the new value
|
||||
of the virtual memory address.
|
||||
.It Fl -gap-fill Ns = Ns Ar val
|
||||
Fill the gaps between sections with the byte value specified by
|
||||
the argument
|
||||
.Ar val .
|
||||
.It Fl -no-adjust-warnings | Fl -no-change-warnings
|
||||
Do not issue a warning if the section specified by the options
|
||||
.Fl -change-section-address ,
|
||||
.Fl -change-section-lma
|
||||
or
|
||||
.Fl -change-section-vma
|
||||
is missing in the input object.
|
||||
.It Fl -only-keep-debug
|
||||
Copy only debugging information to the output file.
|
||||
.It Fl -pad-to Ns = Ns Ar address
|
||||
Pad the load memory address of the output object to the value
|
||||
specified by the argument
|
||||
.Ar address
|
||||
by increasing the size of the section with the highest load memory
|
||||
address.
|
||||
.It Fl -prefix-alloc-sections Ns = Ns Ar string
|
||||
Prefix the section names of all the allocated sections with
|
||||
.Ar string .
|
||||
.It Fl -prefix-sections Ns = Ns Ar string
|
||||
Prefix the section names of all the sections with
|
||||
.Ar string .
|
||||
.It Fl -prefix-symbols Ns = Ns Ar string
|
||||
Prefix the symbol names of all the symbols with
|
||||
.Ar string .
|
||||
.It Fl -rename-section Ar oldname Ns = Ns Ar newname Ns Op Ar ,flags
|
||||
Rename the section named by argument
|
||||
.Ar oldname
|
||||
to
|
||||
.Ar newname ,
|
||||
optionally changing the sections flags to that specified by argument
|
||||
.Ar flags .
|
||||
Allowed values for the argument
|
||||
.Ar flags
|
||||
are as for option
|
||||
.Fl -set-section-flags
|
||||
below.
|
||||
.It Fl -set-section-flags Ar sectionname Ns = Ns Ar flags
|
||||
Set the flags for the section named by argument
|
||||
.Ar sectionname
|
||||
to those specified by argument
|
||||
.Ar flags .
|
||||
Argument
|
||||
.Ar flags
|
||||
is a comma separated list of the following flag names:
|
||||
.Bl -tag -width "readonly" -compact
|
||||
.It alloc
|
||||
The section occupies space in the output file.
|
||||
.It code
|
||||
The section contains machine instructions.
|
||||
.It contents
|
||||
This flag is accepted but is ignored.
|
||||
.It data
|
||||
The section contains writeable data.
|
||||
.It debug
|
||||
The section holds debugging information.
|
||||
.It load
|
||||
The section is loadable.
|
||||
.It noload
|
||||
The section should not be loaded into memory.
|
||||
.It readonly
|
||||
The section is not writable.
|
||||
.It rom
|
||||
The section contains ROM'able contents.
|
||||
.It share
|
||||
This flag is accepted but is ignored.
|
||||
.El
|
||||
.It Fl -set-start Ns = Ns Ar address
|
||||
Set the start address of the output ELF object to the value specified
|
||||
by the argument
|
||||
.Ar address .
|
||||
.It Fl -srec-forceS3
|
||||
Only generate S-records of type
|
||||
.Dq S3 .
|
||||
This option is only meaningful when the output target is set to
|
||||
.Dq srec .
|
||||
.It Fl -srec-len Ns = Ns Ar val
|
||||
Set the maximum length of an S-record line to
|
||||
.Ar val .
|
||||
This option is only meaningful when the output target is set to
|
||||
.Dq srec .
|
||||
.It Fl -strip-unneeded
|
||||
Do not copy symbols that are not needed for relocation processing.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr ar 1 ,
|
||||
.Xr ld 1 ,
|
||||
.Xr mcs 1 ,
|
||||
.Xr strip 1 ,
|
||||
.Xr elf 3 ,
|
||||
.Xr ar 5 ,
|
||||
.Xr elf 5
|
||||
.Sh HISTORY
|
||||
.Nm
|
||||
has been implemented by
|
||||
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
313
elfcopy/elfcopy.h
Normal file
313
elfcopy/elfcopy.h
Normal file
|
@ -0,0 +1,313 @@
|
|||
/*-
|
||||
* Copyright (c) 2007-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: elfcopy.h 2970 2013-12-01 15:22:12Z kaiwang27 $
|
||||
*/
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <gelf.h>
|
||||
#include <libelftc.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
/*
|
||||
* User specified symbol operation (strip, keep, localize, globalize,
|
||||
* weaken, rename, etc).
|
||||
*/
|
||||
struct symop {
|
||||
const char *name;
|
||||
const char *newname;
|
||||
|
||||
#define SYMOP_KEEP 0x0001U
|
||||
#define SYMOP_STRIP 0x0002U
|
||||
#define SYMOP_GLOBALIZE 0x0004U
|
||||
#define SYMOP_LOCALIZE 0x0008U
|
||||
#define SYMOP_KEEPG 0x0010U
|
||||
#define SYMOP_WEAKEN 0x0020U
|
||||
#define SYMOP_REDEF 0x0040U
|
||||
|
||||
unsigned int op;
|
||||
|
||||
STAILQ_ENTRY(symop) symop_list;
|
||||
};
|
||||
|
||||
/* File containing symbol list. */
|
||||
struct symfile {
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
size_t size;
|
||||
char *data;
|
||||
unsigned int op;
|
||||
|
||||
STAILQ_ENTRY(symfile) symfile_list;
|
||||
};
|
||||
|
||||
/* Sections to copy/remove/rename/... */
|
||||
struct sec_action {
|
||||
const char *name;
|
||||
const char *addopt;
|
||||
const char *newname;
|
||||
const char *string;
|
||||
uint64_t lma;
|
||||
uint64_t vma;
|
||||
int64_t lma_adjust;
|
||||
int64_t vma_adjust;
|
||||
|
||||
#define SF_ALLOC 0x0001U
|
||||
#define SF_LOAD 0x0002U
|
||||
#define SF_NOLOAD 0x0004U
|
||||
#define SF_READONLY 0x0008U
|
||||
#define SF_DEBUG 0x0010U
|
||||
#define SF_CODE 0x0020U
|
||||
#define SF_DATA 0x0040U
|
||||
#define SF_ROM 0x0080U
|
||||
#define SF_SHARED 0X0100U
|
||||
#define SF_CONTENTS 0x0200U
|
||||
|
||||
int flags;
|
||||
int add;
|
||||
int append;
|
||||
int compress;
|
||||
int copy;
|
||||
int print;
|
||||
int remove;
|
||||
int rename;
|
||||
int setflags;
|
||||
int setlma;
|
||||
int setvma;
|
||||
|
||||
STAILQ_ENTRY(sec_action) sac_list;
|
||||
};
|
||||
|
||||
/* Sections to add from file. */
|
||||
struct sec_add {
|
||||
char *name;
|
||||
char *content;
|
||||
size_t size;
|
||||
|
||||
STAILQ_ENTRY(sec_add) sadd_list;
|
||||
};
|
||||
|
||||
struct segment;
|
||||
|
||||
/* Internal data structure for sections. */
|
||||
struct section {
|
||||
struct segment *seg; /* containing segment */
|
||||
const char *name; /* section name */
|
||||
char *newname; /* new section name */
|
||||
Elf_Scn *is; /* input scn */
|
||||
Elf_Scn *os; /* output scn */
|
||||
void *buf; /* section content */
|
||||
uint8_t *pad; /* section padding */
|
||||
uint64_t off; /* section offset */
|
||||
uint64_t sz; /* section size */
|
||||
uint64_t cap; /* section capacity */
|
||||
uint64_t align; /* section alignment */
|
||||
uint64_t type; /* section type */
|
||||
uint64_t vma; /* section virtual addr */
|
||||
uint64_t lma; /* section load addr */
|
||||
uint64_t pad_sz;/* section padding size */
|
||||
int loadable; /* whether loadable */
|
||||
int pseudo;
|
||||
int nocopy;
|
||||
|
||||
TAILQ_ENTRY(section) sec_list; /* next section */
|
||||
};
|
||||
|
||||
/* Internal data structure for segments. */
|
||||
struct segment {
|
||||
uint64_t addr; /* load addr */
|
||||
uint64_t off; /* file offset */
|
||||
uint64_t fsz; /* file size */
|
||||
uint64_t msz; /* memory size */
|
||||
uint64_t type; /* segment type */
|
||||
int remove; /* whether remove */
|
||||
int nsec; /* number of sections contained */
|
||||
struct section **v_sec; /* list of sections contained */
|
||||
|
||||
STAILQ_ENTRY(segment) seg_list; /* next segment */
|
||||
};
|
||||
|
||||
/*
|
||||
* In-memory representation of ar(1) archive member(object).
|
||||
*/
|
||||
struct ar_obj {
|
||||
char *name; /* member name */
|
||||
char *buf; /* member content */
|
||||
void *maddr; /* mmap start address */
|
||||
uid_t uid; /* user id */
|
||||
gid_t gid; /* group id */
|
||||
mode_t md; /* octal file permissions */
|
||||
size_t size; /* member size */
|
||||
time_t mtime; /* modification time */
|
||||
|
||||
STAILQ_ENTRY(ar_obj) objs;
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure encapsulates the "global" data for "elfcopy" program.
|
||||
*/
|
||||
struct elfcopy {
|
||||
const char *progname; /* program name */
|
||||
int iec; /* elfclass of input object */
|
||||
Elftc_Bfd_Target_Flavor itf; /* flavour of input object */
|
||||
Elftc_Bfd_Target_Flavor otf; /* flavour of output object */
|
||||
const char *otgt; /* output target name */
|
||||
int oec; /* elfclass of output object */
|
||||
unsigned char oed; /* endianess of output object */
|
||||
int oem; /* EM_XXX of output object */
|
||||
int abi; /* OSABI of output object */
|
||||
Elf *ein; /* ELF descriptor of input object */
|
||||
Elf *eout; /* ELF descriptor of output object */
|
||||
int iphnum; /* num. of input object phdr entries */
|
||||
int ophnum; /* num. of output object phdr entries */
|
||||
int nos; /* num. of output object sections */
|
||||
|
||||
enum {
|
||||
STRIP_NONE = 0,
|
||||
STRIP_ALL,
|
||||
STRIP_DEBUG,
|
||||
STRIP_NONDEBUG,
|
||||
STRIP_UNNEEDED
|
||||
} strip;
|
||||
|
||||
#define EXECUTABLE 0x00000001U
|
||||
#define DYNAMIC 0x00000002U
|
||||
#define RELOCATABLE 0x00000004U
|
||||
#define SYMTAB_EXIST 0x00000010U
|
||||
#define SYMTAB_INTACT 0x00000020U
|
||||
#define KEEP_GLOBAL 0x00000040U
|
||||
#define DISCARD_LOCAL 0x00000080U
|
||||
#define WEAKEN_ALL 0x00000100U
|
||||
#define PRESERVE_DATE 0x00001000U
|
||||
#define SREC_FORCE_S3 0x00002000U
|
||||
#define SREC_FORCE_LEN 0x00004000U
|
||||
#define SET_START 0x00008000U
|
||||
#define GAP_FILL 0x00010000U
|
||||
#define WILDCARD 0x00020000U
|
||||
#define NO_CHANGE_WARN 0x00040000U
|
||||
#define SEC_ADD 0x00080000U
|
||||
#define SEC_APPEND 0x00100000U
|
||||
#define SEC_COMPRESS 0x00200000U
|
||||
#define SEC_PRINT 0x00400000U
|
||||
#define SEC_REMOVE 0x00800000U
|
||||
#define SEC_COPY 0x01000000U
|
||||
#define DISCARD_LLABEL 0x02000000U
|
||||
|
||||
int flags; /* elfcopy run control flags. */
|
||||
int64_t change_addr; /* Section address adjustment. */
|
||||
int64_t change_start; /* Entry point adjustment. */
|
||||
uint64_t set_start; /* Entry point value. */
|
||||
unsigned long srec_len; /* S-Record length. */
|
||||
uint64_t pad_to; /* load address padding. */
|
||||
uint8_t fill; /* gap fill value. */
|
||||
char *prefix_sec; /* section prefix. */
|
||||
char *prefix_alloc; /* alloc section prefix. */
|
||||
char *prefix_sym; /* symbol prefix. */
|
||||
char *debuglink; /* GNU debuglink file. */
|
||||
struct section *symtab; /* .symtab section. */
|
||||
struct section *strtab; /* .strtab section. */
|
||||
struct section *shstrtab; /* .shstrtab section. */
|
||||
uint64_t *secndx; /* section index map. */
|
||||
uint64_t *symndx; /* symbol index map. */
|
||||
unsigned char *v_rel; /* symbols needed by relocation. */
|
||||
unsigned char *v_secsym; /* sections with section symbol. */
|
||||
STAILQ_HEAD(, segment) v_seg; /* list of segments. */
|
||||
STAILQ_HEAD(, sec_action) v_sac;/* list of section operations. */
|
||||
STAILQ_HEAD(, sec_add) v_sadd; /* list of sections to add. */
|
||||
STAILQ_HEAD(, symop) v_symop; /* list of symbols operations. */
|
||||
STAILQ_HEAD(, symfile) v_symfile; /* list of symlist files. */
|
||||
TAILQ_HEAD(, section) v_sec; /* list of sections. */
|
||||
|
||||
/*
|
||||
* Fields for the ar(1) archive.
|
||||
*/
|
||||
char *as; /* buffer for archive string table. */
|
||||
size_t as_sz; /* current size of as table. */
|
||||
size_t as_cap; /* capacity of as table buffer. */
|
||||
uint32_t s_cnt; /* current number of symbols. */
|
||||
uint32_t *s_so; /* symbol offset table. */
|
||||
size_t s_so_cap; /* capacity of so table buffer. */
|
||||
char *s_sn; /* symbol name table */
|
||||
size_t s_sn_cap; /* capacity of sn table buffer. */
|
||||
size_t s_sn_sz; /* current size of sn table. */
|
||||
off_t rela_off; /* offset relative to pseudo members. */
|
||||
STAILQ_HEAD(, ar_obj) v_arobj; /* archive object(member) list. */
|
||||
};
|
||||
|
||||
void add_section(struct elfcopy *_ecp, const char *_optarg);
|
||||
void add_to_shstrtab(struct elfcopy *_ecp, const char *_name);
|
||||
void add_to_symop_list(struct elfcopy *_ecp, const char *_name,
|
||||
const char *_newname, unsigned int _op);
|
||||
void add_to_symtab(struct elfcopy *_ecp, const char *_name,
|
||||
uint64_t _st_value, uint64_t _st_size, uint16_t _st_shndx,
|
||||
unsigned char _st_info, unsigned char _st_other, int _ndx_known);
|
||||
int add_to_inseg_list(struct elfcopy *_ecp, struct section *_sec);
|
||||
void adjust_addr(struct elfcopy *_ecp);
|
||||
void copy_content(struct elfcopy *_ecp);
|
||||
void copy_data(struct section *_s);
|
||||
void copy_phdr(struct elfcopy *_ecp);
|
||||
void copy_shdr(struct elfcopy *_ecp, struct section *_s, const char *_name,
|
||||
int _copy, int _sec_flags);
|
||||
void create_binary(int _ifd, int _ofd);
|
||||
void create_elf(struct elfcopy *_ecp);
|
||||
void create_elf_from_binary(struct elfcopy *_ecp, int _ifd, const char *ifn);
|
||||
void create_elf_from_ihex(struct elfcopy *_ecp, int _ifd);
|
||||
void create_elf_from_srec(struct elfcopy *_ecp, int _ifd);
|
||||
struct section *create_external_section(struct elfcopy *_ecp, const char *_name,
|
||||
char *_newname, void *_buf, uint64_t _size, uint64_t _off, uint64_t _stype,
|
||||
Elf_Type _dtype, uint64_t flags, uint64_t _align, uint64_t _vma,
|
||||
int _loadable);
|
||||
void create_external_symtab(struct elfcopy *_ecp);
|
||||
void create_ihex(int _ifd, int _ofd);
|
||||
void create_scn(struct elfcopy *_ecp);
|
||||
void create_srec(struct elfcopy *_ecp, int _ifd, int _ofd, const char *_ofn);
|
||||
void create_symtab(struct elfcopy *_ecp);
|
||||
void create_symtab_data(struct elfcopy *_ecp);
|
||||
void create_tempfile(char **_fn, int *_fd);
|
||||
void finalize_external_symtab(struct elfcopy *_ecp);
|
||||
void free_elf(struct elfcopy *_ecp);
|
||||
void free_sec_act(struct elfcopy *_ecp);
|
||||
void free_sec_add(struct elfcopy *_ecp);
|
||||
void free_symtab(struct elfcopy *_ecp);
|
||||
void init_shstrtab(struct elfcopy *_ecp);
|
||||
void insert_to_sec_list(struct elfcopy *_ecp, struct section *_sec,
|
||||
int _tail);
|
||||
struct section *insert_shtab(struct elfcopy *_ecp, int tail);
|
||||
int is_remove_reloc_sec(struct elfcopy *_ecp, uint32_t _sh_info);
|
||||
int is_remove_section(struct elfcopy *_ecp, const char *_name);
|
||||
struct sec_action *lookup_sec_act(struct elfcopy *_ecp,
|
||||
const char *_name, int _add);
|
||||
struct symop *lookup_symop_list(struct elfcopy *_ecp, const char *_name,
|
||||
unsigned int _op);
|
||||
void resync_sections(struct elfcopy *_ecp);
|
||||
void set_shstrtab(struct elfcopy *_ecp);
|
||||
void setup_phdr(struct elfcopy *_ecp);
|
||||
void update_shdr(struct elfcopy *_ecp, int _update_link);
|
||||
|
||||
#ifndef LIBELF_AR
|
||||
int ac_detect_ar(int _ifd);
|
||||
void ac_create_ar(struct elfcopy *_ecp, int _ifd, int _ofd);
|
||||
#endif /* ! LIBELF_AR */
|
1500
elfcopy/main.c
Normal file
1500
elfcopy/main.c
Normal file
File diff suppressed because it is too large
Load diff
125
elfcopy/mcs.1
Normal file
125
elfcopy/mcs.1
Normal file
|
@ -0,0 +1,125 @@
|
|||
.\" Copyright (c) 2011 Joseph Koshy. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY JOSEPH KOSHY ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL JOSEPH KOSHY BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: mcs.1 2247 2011-11-29 08:41:34Z jkoshy $
|
||||
.\"
|
||||
.Dd November 29, 2011
|
||||
.Os
|
||||
.Dt MCS 1
|
||||
.Sh NAME
|
||||
.Nm mcs
|
||||
.Nd manipulate the comment section of an ELF object
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl a Ar string
|
||||
.Op Fl c
|
||||
.Op Fl n Ar name
|
||||
.Op Fl p
|
||||
.Ar
|
||||
.Nm
|
||||
.Fl d
|
||||
.Op Fl n Ar name
|
||||
.Ar
|
||||
.Nm
|
||||
.Fl h | Fl -help
|
||||
.Nm
|
||||
.Fl V | Fl -version
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is used to manipulate comment sections in an ELF object.
|
||||
If a command-line argument
|
||||
.Ar file
|
||||
names an
|
||||
.Xr ar 1
|
||||
archive, then
|
||||
.Nm
|
||||
will operate on the ELF objects contained in the archive.
|
||||
.Pp
|
||||
By default
|
||||
.Nm
|
||||
operates on the ELF section named
|
||||
.Dq .comment .
|
||||
This may be changed using the
|
||||
.Fl n
|
||||
option.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility supports the following options:
|
||||
.Bl -tag -width ".Fl a Ar string"
|
||||
.It Fl a Ar string
|
||||
Append the text in
|
||||
.Ar string
|
||||
to the comment section.
|
||||
This option may be specified multiple times.
|
||||
.It Fl c
|
||||
Compress the comment section by removing duplicate entries.
|
||||
.It Fl d
|
||||
Delete the comment section from the ELF object.
|
||||
.It Fl h | Fl -help
|
||||
Display a usage message and exit.
|
||||
.It Fl n Ar name
|
||||
Operate on the section named
|
||||
.Ar name .
|
||||
.It Fl p
|
||||
Print the contents of the comment section.
|
||||
This step is taken after actions specified by the
|
||||
.Fl a
|
||||
and
|
||||
.Fl c
|
||||
options (if any) are completed.
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier and exit.
|
||||
.El
|
||||
.Sh COMPATIBILITY
|
||||
The behavior of the
|
||||
.Nm
|
||||
utility differs from its SVR4 counterpart in the following ways:
|
||||
.Bl -bullet -compact
|
||||
.It
|
||||
If the
|
||||
.Fl d
|
||||
option is specified, it causes any
|
||||
.Fl a ,
|
||||
.Fl c
|
||||
and
|
||||
.Fl p
|
||||
options present to be ignored.
|
||||
.It
|
||||
The order of options
|
||||
.Fl a ,
|
||||
.Fl c ,
|
||||
.Fl d ,
|
||||
and
|
||||
.Fl p
|
||||
on the command line is not significant.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr ar 1 ,
|
||||
.Xr elfcopy 1 ,
|
||||
.Xr ld 1 ,
|
||||
.Xr nm 1 ,
|
||||
.Xr strip 1
|
1518
elfcopy/sections.c
Normal file
1518
elfcopy/sections.c
Normal file
File diff suppressed because it is too large
Load diff
493
elfcopy/segments.c
Normal file
493
elfcopy/segments.c
Normal file
|
@ -0,0 +1,493 @@
|
|||
/*-
|
||||
* Copyright (c) 2007-2010,2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/queue.h>
|
||||
#include <err.h>
|
||||
#include <gelf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "elfcopy.h"
|
||||
|
||||
ELFTC_VCSID("$Id: segments.c 2542 2012-08-12 16:14:15Z kaiwang27 $");
|
||||
|
||||
static void insert_to_inseg_list(struct segment *seg, struct section *sec);
|
||||
|
||||
/*
|
||||
* elfcopy's segment handling is relatively simpler and less powerful than
|
||||
* libbfd. Program headers are modified or copied from input to output objects,
|
||||
* but never re-generated. As a result, if the input object has incorrect
|
||||
* program headers, the output object's program headers will remain incorrect
|
||||
* or become even worse.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Check whether a section is "loadable". If so, add it to the
|
||||
* corresponding segment list(s) and return 1.
|
||||
*/
|
||||
int
|
||||
add_to_inseg_list(struct elfcopy *ecp, struct section *s)
|
||||
{
|
||||
struct segment *seg;
|
||||
int loadable;
|
||||
|
||||
if (ecp->ophnum == 0)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Segment is a different view of an ELF object. One segment can
|
||||
* contain one or more sections, and one section can be included
|
||||
* in one or more segments, or not included in any segment at all.
|
||||
* We call those sections which can be found in one or more segments
|
||||
* "loadable" sections, and call the rest "unloadable" sections.
|
||||
* We keep track of "loadable" sections in their containing
|
||||
* segment(s)' v_sec queue. These information are later used to
|
||||
* recalculate the extents of segments, when sections are removed,
|
||||
* for example.
|
||||
*/
|
||||
loadable = 0;
|
||||
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||
if (s->off < seg->off)
|
||||
continue;
|
||||
if (s->off + s->sz > seg->off + seg->fsz &&
|
||||
s->type != SHT_NOBITS)
|
||||
continue;
|
||||
if (s->off + s->sz > seg->off + seg->msz)
|
||||
continue;
|
||||
|
||||
insert_to_inseg_list(seg, s);
|
||||
if (seg->type == PT_LOAD)
|
||||
s->seg = seg;
|
||||
s->lma = seg->addr + (s->off - seg->off);
|
||||
loadable = 1;
|
||||
}
|
||||
|
||||
return (loadable);
|
||||
}
|
||||
|
||||
void
|
||||
adjust_addr(struct elfcopy *ecp)
|
||||
{
|
||||
struct section *s, *s0;
|
||||
struct segment *seg;
|
||||
struct sec_action *sac;
|
||||
uint64_t dl, lma, old_vma, start, end;
|
||||
int found, i;
|
||||
|
||||
/*
|
||||
* Apply VMA and global LMA changes in the first iteration.
|
||||
*/
|
||||
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
|
||||
|
||||
/* Only adjust loadable section's address. */
|
||||
if (!s->loadable || s->seg == NULL)
|
||||
continue;
|
||||
|
||||
/* Apply global LMA adjustment. */
|
||||
if (ecp->change_addr != 0)
|
||||
s->lma += ecp->change_addr;
|
||||
|
||||
if (!s->pseudo) {
|
||||
old_vma = s->vma;
|
||||
|
||||
/* Apply global VMA adjustment. */
|
||||
if (ecp->change_addr != 0)
|
||||
s->vma += ecp->change_addr;
|
||||
|
||||
/* Apply section VMA adjustment. */
|
||||
sac = lookup_sec_act(ecp, s->name, 0);
|
||||
if (sac == NULL)
|
||||
continue;
|
||||
if (sac->setvma)
|
||||
s->vma = sac->vma;
|
||||
if (sac->vma_adjust != 0)
|
||||
s->vma += sac->vma_adjust;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply sections LMA change in the second iteration.
|
||||
*/
|
||||
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
|
||||
|
||||
/* Only adjust loadable section's LMA. */
|
||||
if (!s->loadable || s->seg == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check if there is a LMA change request for this
|
||||
* section.
|
||||
*/
|
||||
sac = lookup_sec_act(ecp, s->name, 0);
|
||||
if (sac == NULL)
|
||||
continue;
|
||||
if (!sac->setlma && sac->lma_adjust == 0)
|
||||
continue;
|
||||
lma = s->lma;
|
||||
if (sac->setlma)
|
||||
lma = sac->lma;
|
||||
if (sac->lma_adjust != 0)
|
||||
lma += sac->lma_adjust;
|
||||
if (lma == s->lma)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check if the LMA change is viable.
|
||||
*
|
||||
* 1. Check if the new LMA is properly aligned accroding to
|
||||
* section alignment.
|
||||
*
|
||||
* 2. Compute the new extent of segment that contains this
|
||||
* section, make sure it doesn't overlap with other
|
||||
* segments.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
printf("LMA for section %s: %#jx\n", s->name, lma);
|
||||
#endif
|
||||
|
||||
if (lma % s->align != 0)
|
||||
errx(EXIT_FAILURE, "The load address %#jx for "
|
||||
"section %s is not aligned to %ju",
|
||||
(uintmax_t) lma, s->name, s->align);
|
||||
|
||||
if (lma < s->lma) {
|
||||
/* Move section to lower address. */
|
||||
if (lma < s->lma - s->seg->addr)
|
||||
errx(EXIT_FAILURE, "Not enough space to move "
|
||||
"section %s load address to %#jx", s->name,
|
||||
(uintmax_t) lma);
|
||||
start = lma - (s->lma - s->seg->addr);
|
||||
if (s == s->seg->v_sec[s->seg->nsec - 1])
|
||||
end = start + s->seg->msz;
|
||||
else
|
||||
end = s->seg->addr + s->seg->msz;
|
||||
|
||||
} else {
|
||||
/* Move section to upper address. */
|
||||
if (s == s->seg->v_sec[0])
|
||||
start = lma;
|
||||
else
|
||||
start = s->seg->addr;
|
||||
end = lma + (s->seg->addr + s->seg->msz - s->lma);
|
||||
if (end < start)
|
||||
errx(EXIT_FAILURE, "Not enough space to move "
|
||||
"section %s load address to %#jx", s->name,
|
||||
(uintmax_t) lma);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("new extent for segment containing %s: (%#jx,%#jx)\n",
|
||||
s->name, start, end);
|
||||
#endif
|
||||
|
||||
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||
if (seg == s->seg || seg->type != PT_LOAD)
|
||||
continue;
|
||||
if (start > seg->addr + seg->msz)
|
||||
continue;
|
||||
if (end < seg->addr)
|
||||
continue;
|
||||
errx(EXIT_FAILURE, "The extent of segment containing "
|
||||
"section %s overlaps with segment(%#jx,%#jx)",
|
||||
s->name, seg->addr, seg->addr + seg->msz);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update section LMA and file offset.
|
||||
*/
|
||||
|
||||
if (lma < s->lma) {
|
||||
/*
|
||||
* To move a section to lower load address, we decrease
|
||||
* the load addresses of the section and all the
|
||||
* sections that are before it, and we increase the
|
||||
* file offsets of all the sections that are after it.
|
||||
*/
|
||||
dl = s->lma - lma;
|
||||
for (i = 0; i < s->seg->nsec; i++) {
|
||||
s0 = s->seg->v_sec[i];
|
||||
s0->lma -= dl;
|
||||
#ifdef DEBUG
|
||||
printf("section %s LMA set to %#jx\n",
|
||||
s0->name, (uintmax_t) s0->lma);
|
||||
#endif
|
||||
if (s0 == s)
|
||||
break;
|
||||
}
|
||||
for (i = i + 1; i < s->seg->nsec; i++) {
|
||||
s0 = s->seg->v_sec[i];
|
||||
s0->off += dl;
|
||||
#ifdef DEBUG
|
||||
printf("section %s offset set to %#jx\n",
|
||||
s0->name, (uintmax_t) s0->off);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* To move a section to upper load address, we increase
|
||||
* the load addresses of the section and all the
|
||||
* sections that are after it, and we increase the
|
||||
* their file offsets too unless the section in question
|
||||
* is the first in its containing segment.
|
||||
*/
|
||||
dl = lma - s->lma;
|
||||
for (i = 0; i < s->seg->nsec; i++)
|
||||
if (s->seg->v_sec[i] == s)
|
||||
break;
|
||||
if (i >= s->seg->nsec)
|
||||
errx(EXIT_FAILURE, "Internal: section `%s' not"
|
||||
" found in its containing segement",
|
||||
s->name);
|
||||
for (; i < s->seg->nsec; i++) {
|
||||
s0 = s->seg->v_sec[i];
|
||||
s0->lma += dl;
|
||||
#ifdef DEBUG
|
||||
printf("section %s LMA set to %#jx\n",
|
||||
s0->name, (uintmax_t) s0->lma);
|
||||
#endif
|
||||
if (s != s->seg->v_sec[0]) {
|
||||
s0->off += dl;
|
||||
#ifdef DEBUG
|
||||
printf("section %s offset set to %#jx\n",
|
||||
s0->name, (uintmax_t) s0->off);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply load address padding.
|
||||
*/
|
||||
|
||||
if (ecp->pad_to != 0) {
|
||||
|
||||
/*
|
||||
* Find the section with highest load address.
|
||||
*/
|
||||
|
||||
s = NULL;
|
||||
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||
if (seg->type != PT_LOAD)
|
||||
continue;
|
||||
for (i = seg->nsec - 1; i >= 0; i--)
|
||||
if (seg->v_sec[i]->type != SHT_NOBITS)
|
||||
break;
|
||||
if (i < 0)
|
||||
continue;
|
||||
if (s == NULL)
|
||||
s = seg->v_sec[i];
|
||||
else {
|
||||
s0 = seg->v_sec[i];
|
||||
if (s0->lma > s->lma)
|
||||
s = s0;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == NULL)
|
||||
goto issue_warn;
|
||||
|
||||
/* No need to pad if the pad_to address is lower. */
|
||||
if (ecp->pad_to <= s->lma + s->sz)
|
||||
goto issue_warn;
|
||||
|
||||
s->pad_sz = ecp->pad_to - (s->lma + s->sz);
|
||||
#ifdef DEBUG
|
||||
printf("pad section %s load to address %#jx by %#jx\n", s->name,
|
||||
(uintmax_t) ecp->pad_to, (uintmax_t) s->pad_sz);
|
||||
#endif
|
||||
}
|
||||
|
||||
issue_warn:
|
||||
|
||||
/*
|
||||
* Issue a warning if there are VMA/LMA adjust requests for
|
||||
* some nonexistent sections.
|
||||
*/
|
||||
if ((ecp->flags & NO_CHANGE_WARN) == 0) {
|
||||
STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
|
||||
if (!sac->setvma && !sac->setlma &&
|
||||
!sac->vma_adjust && !sac->lma_adjust)
|
||||
continue;
|
||||
found = 0;
|
||||
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
|
||||
if (s->pseudo || s->name == NULL)
|
||||
continue;
|
||||
if (!strcmp(s->name, sac->name)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
warnx("cannot find section `%s'", sac->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
insert_to_inseg_list(struct segment *seg, struct section *sec)
|
||||
{
|
||||
struct section *s;
|
||||
int i;
|
||||
|
||||
seg->nsec++;
|
||||
seg->v_sec = realloc(seg->v_sec, seg->nsec * sizeof(*seg->v_sec));
|
||||
if (seg->v_sec == NULL)
|
||||
err(EXIT_FAILURE, "realloc failed");
|
||||
|
||||
/*
|
||||
* Sort the section in order of offset.
|
||||
*/
|
||||
|
||||
for (i = seg->nsec - 1; i > 0; i--) {
|
||||
s = seg->v_sec[i - 1];
|
||||
if (sec->off >= s->off) {
|
||||
seg->v_sec[i] = sec;
|
||||
break;
|
||||
} else
|
||||
seg->v_sec[i] = s;
|
||||
}
|
||||
if (i == 0)
|
||||
seg->v_sec[0] = sec;
|
||||
}
|
||||
|
||||
void
|
||||
setup_phdr(struct elfcopy *ecp)
|
||||
{
|
||||
struct segment *seg;
|
||||
GElf_Phdr iphdr;
|
||||
size_t iphnum;
|
||||
int i;
|
||||
|
||||
if (elf_getphnum(ecp->ein, &iphnum) == 0)
|
||||
errx(EXIT_FAILURE, "elf_getphnum failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
ecp->ophnum = ecp->iphnum = iphnum;
|
||||
if (iphnum == 0)
|
||||
return;
|
||||
|
||||
/* If --only-keep-debug is specified, discard all program headers. */
|
||||
if (ecp->strip == STRIP_NONDEBUG) {
|
||||
ecp->ophnum = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; (size_t)i < iphnum; i++) {
|
||||
if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
|
||||
errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
if ((seg = calloc(1, sizeof(*seg))) == NULL)
|
||||
err(EXIT_FAILURE, "calloc failed");
|
||||
seg->addr = iphdr.p_vaddr;
|
||||
seg->off = iphdr.p_offset;
|
||||
seg->fsz = iphdr.p_filesz;
|
||||
seg->msz = iphdr.p_memsz;
|
||||
seg->type = iphdr.p_type;
|
||||
STAILQ_INSERT_TAIL(&ecp->v_seg, seg, seg_list);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
copy_phdr(struct elfcopy *ecp)
|
||||
{
|
||||
struct segment *seg;
|
||||
struct section *s;
|
||||
GElf_Phdr iphdr, ophdr;
|
||||
int i;
|
||||
|
||||
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||
if (seg->type == PT_PHDR) {
|
||||
if (!TAILQ_EMPTY(&ecp->v_sec)) {
|
||||
s = TAILQ_FIRST(&ecp->v_sec);
|
||||
if (s->pseudo)
|
||||
seg->addr = s->lma +
|
||||
gelf_fsize(ecp->eout, ELF_T_EHDR,
|
||||
1, EV_CURRENT);
|
||||
}
|
||||
seg->fsz = seg->msz = gelf_fsize(ecp->eout, ELF_T_PHDR,
|
||||
ecp->ophnum, EV_CURRENT);
|
||||
continue;
|
||||
}
|
||||
|
||||
seg->fsz = seg->msz = 0;
|
||||
for (i = 0; i < seg->nsec; i++) {
|
||||
s = seg->v_sec[i];
|
||||
seg->msz = s->off + s->sz - seg->off;
|
||||
if (s->type != SHT_NOBITS)
|
||||
seg->fsz = seg->msz;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space for program headers, note that libelf keep
|
||||
* track of the number in internal variable, and a call to
|
||||
* elf_update is needed to update e_phnum of ehdr.
|
||||
*/
|
||||
if (gelf_newphdr(ecp->eout, ecp->ophnum) == NULL)
|
||||
errx(EXIT_FAILURE, "gelf_newphdr() failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/*
|
||||
* This elf_update() call is to update the e_phnum field in
|
||||
* ehdr. It's necessary because later we will call gelf_getphdr(),
|
||||
* which does sanity check by comparing ndx argument with e_phnum.
|
||||
*/
|
||||
if (elf_update(ecp->eout, ELF_C_NULL) < 0)
|
||||
errx(EXIT_FAILURE, "elf_update() failed: %s", elf_errmsg(-1));
|
||||
|
||||
/*
|
||||
* iphnum == ophnum, since we don't remove program headers even if
|
||||
* they no longer contain sections.
|
||||
*/
|
||||
i = 0;
|
||||
STAILQ_FOREACH(seg, &ecp->v_seg, seg_list) {
|
||||
if (i >= ecp->iphnum)
|
||||
break;
|
||||
if (gelf_getphdr(ecp->ein, i, &iphdr) != &iphdr)
|
||||
errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
if (gelf_getphdr(ecp->eout, i, &ophdr) != &ophdr)
|
||||
errx(EXIT_FAILURE, "gelf_getphdr failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
ophdr.p_type = iphdr.p_type;
|
||||
ophdr.p_vaddr = seg->addr;
|
||||
ophdr.p_paddr = seg->addr;
|
||||
ophdr.p_flags = iphdr.p_flags;
|
||||
ophdr.p_align = iphdr.p_align;
|
||||
ophdr.p_offset = seg->off;
|
||||
ophdr.p_filesz = seg->fsz;
|
||||
ophdr.p_memsz = seg->msz;
|
||||
if (!gelf_update_phdr(ecp->eout, i, &ophdr))
|
||||
err(EXIT_FAILURE, "gelf_update_phdr failed :%s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
132
elfcopy/strip.1
Normal file
132
elfcopy/strip.1
Normal file
|
@ -0,0 +1,132 @@
|
|||
.\" Copyright (c) 2011 Joseph Koshy. All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY JOSEPH KOSHY ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL JOSEPH KOSHY BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: strip.1 2069 2011-10-26 15:53:48Z jkoshy $
|
||||
.\"
|
||||
.Dd September 17, 2011
|
||||
.Os
|
||||
.Dt STRIP 1
|
||||
.Sh NAME
|
||||
.Nm strip
|
||||
.Nd discard information from ELF objects
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl d | Fl g | Fl S | Fl -strip-debug
|
||||
.Op Fl h | Fl -help
|
||||
.Op Fl -only-keep-debug
|
||||
.Op Fl o Ar outputfile | Fl -output-file= Ns Ar outputfile
|
||||
.Op Fl p | Fl -preserve-dates
|
||||
.Op Fl s | Fl -strip-all
|
||||
.Op Fl -strip-unneeded
|
||||
.Op Fl w | Fl -wildcard
|
||||
.Op Fl x | Fl -discard-all
|
||||
.Op Fl I Ar format | Fl -input-target= Ns Ar format
|
||||
.Op Fl K Ar symbol | Fl -keep-symbol= Ns Ar symbol
|
||||
.Op Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbol
|
||||
.Op Fl O Ar format | Fl -output-target= Ns Ar format
|
||||
.Op Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||
.Op Fl V | Fl -version
|
||||
.Op Fl X | Fl -discard-locals
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is used to discard information from ELF objects.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility supports the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl d | Fl g | Fl S | Fl -strip-debug
|
||||
Remove debugging symbols only.
|
||||
.It Fl h | Fl -help
|
||||
Print a help message and exit.
|
||||
.It Fl -only-keep-debug
|
||||
Remove all content except that which would be used for debugging.
|
||||
.It Fl o Ar outputfile | Fl -output-file= Ns Ar outputfile
|
||||
Write the stripped object to file
|
||||
.Ar outputfile .
|
||||
The default behaviour is to modify objects in place.
|
||||
.It Fl p | Fl -preserve-dates
|
||||
Preserve the object's access and modification times.
|
||||
.It Fl s | Fl -strip-all
|
||||
Remove all symbols.
|
||||
.It Fl -strip-unneeded
|
||||
Remove all symbols not needed for further relocation processing.
|
||||
.It Fl w | Fl -wildcard
|
||||
Use shell-style patterns to name symbols.
|
||||
The following meta-characters are recognized in patterns:
|
||||
.Bl -tag -width "...." -compact
|
||||
.It Li !
|
||||
If this is the first character of the pattern, invert the sense of the
|
||||
pattern match.
|
||||
.It Li *
|
||||
Matches any string of characters in a symbol name.
|
||||
.It Li ?
|
||||
Matches zero or one character in a symbol name.
|
||||
.It Li [
|
||||
Mark the start of a character class.
|
||||
.It Li \e
|
||||
Remove the special meaning of the next character in the pattern.
|
||||
.It Li ]
|
||||
Mark the end of a character class.
|
||||
.El
|
||||
.It Fl x | Fl -discard-all
|
||||
Discard all non-global symbols.
|
||||
.It Fl I Ar format | Fl -input-target= Ns Ar format
|
||||
These options are accepted, but are ignored.
|
||||
.It Fl K Ar symbol | Fl -keep-symbol= Ns Ar symbol
|
||||
Keep the symbol
|
||||
.Ar symbol
|
||||
even if it would otherwise be stripped.
|
||||
This option may be specified multiple times.
|
||||
.It Fl N Ar symbol | Fl -strip-symbol= Ns Ar symbol
|
||||
Remove the symbol
|
||||
.Ar symbol
|
||||
even if it would otherwise have been kept.
|
||||
This option may be specified multiple times.
|
||||
.It Fl O Ar format | Fl -output-target= Ns Ar format
|
||||
Set the output file format to
|
||||
.Ar format .
|
||||
For the full list of supported formats, please see the documentation
|
||||
for function
|
||||
.Xr elftc_bfd_find_target 3 .
|
||||
.It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname
|
||||
Remove the section named by the argument
|
||||
.Ar sectionname .
|
||||
This option may be specified multiple times.
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier and exit.
|
||||
.It Fl X | Fl -discard-locals
|
||||
Remove compiler-generated local symbols.
|
||||
.El
|
||||
.Sh DIAGNOSTICS
|
||||
.Ex -std
|
||||
.Sh SEE ALSO
|
||||
.Xr ar 1 ,
|
||||
.Xr elfcopy 1 ,
|
||||
.Xr ld 1 ,
|
||||
.Xr mcs 1 ,
|
||||
.Xr elf 3 ,
|
||||
.Xr elftc_bfd_find_target 3 ,
|
||||
.Xr fnmatch 3
|
1040
elfcopy/symbols.c
Normal file
1040
elfcopy/symbols.c
Normal file
File diff suppressed because it is too large
Load diff
11
elfdump/Makefile
Normal file
11
elfdump/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
# $Id: Makefile 2289 2011-12-04 07:11:47Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= elfdump
|
||||
WARNS?= 6
|
||||
|
||||
DPADD= ${LIBELFTC} ${LIBELF}
|
||||
LDADD= -lelftc -lelf
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
158
elfdump/elfdump.1
Normal file
158
elfdump/elfdump.1
Normal file
|
@ -0,0 +1,158 @@
|
|||
.\" Copyright (c) 2003 David O'Brien
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD: src/usr.bin/elfdump/elfdump.1,v 1.6 2005/01/18 13:43:48 ru Exp $
|
||||
.\" $Id: elfdump.1 2069 2011-10-26 15:53:48Z jkoshy $
|
||||
.\"
|
||||
.Dd August 25, 2011
|
||||
.Dt ELFDUMP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm elfdump
|
||||
.Nd "display information about"
|
||||
.Tn ELF
|
||||
files
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Fl a | cdeGhiknprsv
|
||||
.Op Fl S
|
||||
.Op Fl V
|
||||
.Op Fl N Ar name
|
||||
.Op Fl w Ar file
|
||||
.Ar file ...
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility
|
||||
dumps various information about the specified
|
||||
.Tn ELF
|
||||
.Ar file .
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width ".Fl w Ar file"
|
||||
.It Fl a
|
||||
Dump all information.
|
||||
.It Fl c
|
||||
Dump shared headers.
|
||||
.It Fl d
|
||||
Dump dynamic symbols.
|
||||
.It Fl e
|
||||
Dump ELF header.
|
||||
.It Fl G
|
||||
Dump the GOT.
|
||||
.It Fl h
|
||||
Dump the hash values.
|
||||
.It Fl i
|
||||
Dump the dynamic interpreter.
|
||||
.It Fl k
|
||||
Dump the ELF checksum.
|
||||
.It Fl n
|
||||
Dump note sections.
|
||||
.It Fl N Ar name
|
||||
Only dump the section with the specific
|
||||
.Ar name .
|
||||
Archive symbol table can be specified with
|
||||
the special section name ARSYM.
|
||||
More than one
|
||||
.Fl N
|
||||
option may appear.
|
||||
.It Fl p
|
||||
Dump the program header.
|
||||
.It Fl r
|
||||
Dump relocations.
|
||||
.It Fl s
|
||||
Dump the symbol table.
|
||||
.It Fl S
|
||||
Output in the Solaris
|
||||
.Nm
|
||||
format.
|
||||
.It Fl v
|
||||
Dump the symbol-versioning sections.
|
||||
.It Fl V
|
||||
Print a version identifier and exit.
|
||||
.It Fl w Ar file
|
||||
Write output to a
|
||||
.Ar file
|
||||
instead of the standard output.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
The following is an example of a typical usage
|
||||
of the
|
||||
.Nm
|
||||
command:
|
||||
.Pp
|
||||
.Dl "elfdump -a -w output /bin/ls"
|
||||
.Pp
|
||||
To dump the content of '.dynsym' symbol table:
|
||||
.Pp
|
||||
.Dl "elfdump -s -N .dynsym /bin/ls"
|
||||
.Pp
|
||||
To dump the archive symbol table,
|
||||
but not the symbol tables of archive members:
|
||||
.Pp
|
||||
.Dl "elfdump -s -N ARSYM /usr/lib/libelf.a"
|
||||
.Pp
|
||||
To dump the content of .got section and
|
||||
the symbol-versioning sections in Solaris
|
||||
.Nm
|
||||
format:
|
||||
.Pp
|
||||
.Dl "elfdump -S -Gv /bin/ls"
|
||||
.Sh SEE ALSO
|
||||
.Xr objdump 1 ,
|
||||
.Xr readelf 1 ,
|
||||
.Xr elf 3
|
||||
.Rs
|
||||
.%A "AT&T Unix Systems Labs"
|
||||
.%T "System V Application Binary Interface"
|
||||
.%O http://www.sco.com/developers/gabi/
|
||||
.Re
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility first appeared in
|
||||
.Fx 5.0 .
|
||||
.Sh AUTHORS
|
||||
.An -nosplit
|
||||
The
|
||||
.Nm
|
||||
utility
|
||||
was written by
|
||||
.An Jake Burkholder Aq jake@FreeBSD.org .
|
||||
Later it was rewritten based on the
|
||||
libelf library.
|
||||
This
|
||||
manual page was written by
|
||||
.An David O'Brien Aq obrien@FreeBSD.org .
|
||||
.Pp
|
||||
.An Kai Wang Aq kaiw@FreeBSD.org
|
||||
rewrote it using the
|
||||
.Lb libelf
|
||||
and implemented additional functionality.
|
||||
.Sh BUGS
|
||||
Does not fully implement the
|
||||
.Tn ELF
|
||||
gABI.
|
2821
elfdump/elfdump.c
Normal file
2821
elfdump/elfdump.c
Normal file
File diff suppressed because it is too large
Load diff
15
findtextrel/Makefile
Normal file
15
findtextrel/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
# $Id: Makefile 2069 2011-10-26 15:53:48Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= findtextrel
|
||||
SRCS= findtextrel.c
|
||||
|
||||
WARNS?= 6
|
||||
|
||||
DPADD= ${LIBELFTC} ${LIBDWARF} ${LIBELF}
|
||||
LDADD= -lelftc -ldwarf -lelf
|
||||
|
||||
MAN1= findtextrel.1
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
104
findtextrel/findtextrel.1
Normal file
104
findtextrel/findtextrel.1
Normal file
|
@ -0,0 +1,104 @@
|
|||
.\" Copyright (c) 2010,2011 Joseph Koshy <jkoshy@users.sourceforge.net>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer
|
||||
.\" in this position and unchanged.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: findtextrel.1 2069 2011-10-26 15:53:48Z jkoshy $
|
||||
.\"
|
||||
.Dd August 25, 2011
|
||||
.Os
|
||||
.Dt FINDTEXTREL 1
|
||||
.Sh NAME
|
||||
.Nm findtextrel
|
||||
.Nd locate text relocation entries in position independent ELF executables
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl V
|
||||
.Op Fl H
|
||||
.Op Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility displays information about text relocations in ELF objects
|
||||
containing position independent code.
|
||||
.Pp
|
||||
Text relocations are usually undesirable because they require that the
|
||||
text sections of objects be modified at load time, preventing the
|
||||
sharing of text sections across multiple processes using a dynamic
|
||||
shared object.
|
||||
.Pp
|
||||
Arguments
|
||||
.Ar
|
||||
name ELF executables to be examined.
|
||||
If no files are specified, the
|
||||
.Nm
|
||||
utility will examine the file
|
||||
.Pa a.out
|
||||
in the current directory.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility recognizes the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl H
|
||||
Print a brief help message.
|
||||
.It Fl V
|
||||
Print a version identifier and exit.
|
||||
.El
|
||||
.Sh EXIT STATUS
|
||||
.Ex -std
|
||||
.Sh EXAMPLES
|
||||
To list text relocations in an object, use:
|
||||
.Bd -literal -offset indent
|
||||
% findtextrel a.out
|
||||
a.out: ELF object contains text relocation records:
|
||||
a.out: off: 0x530, func: main, file: a.c, line: 5
|
||||
.Ed
|
||||
.Sh DIAGNOSTICS
|
||||
The
|
||||
.Nm
|
||||
may issue the following diagnostics:
|
||||
.Bl -diag
|
||||
.It "ELF object is not a DSO/PIE"
|
||||
The ELF executable specified by argument
|
||||
.Ar object
|
||||
was not a position independent executable.
|
||||
.It "ELF object does not contain a text relocation"
|
||||
The ELF executable specified by argument
|
||||
.Ar object
|
||||
contained no text relocations.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr addr2line 1 ,
|
||||
.Xr nm 1 ,
|
||||
.Xr readelf 1
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Nm
|
||||
utility first appeared in the
|
||||
.Nm elfutils
|
||||
toolset from Red Hat, Inc.
|
||||
.Sh AUTHORS
|
||||
This implementation of the
|
||||
.Nm
|
||||
utility was created by
|
||||
.An "Kai Wang" Aq kaiwang27@users.sourceforge.net .
|
417
findtextrel/findtextrel.c
Normal file
417
findtextrel/findtextrel.c
Normal file
|
@ -0,0 +1,417 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/param.h>
|
||||
#include <err.h>
|
||||
#include <dwarf.h>
|
||||
#include <fcntl.h>
|
||||
#include <gelf.h>
|
||||
#include <getopt.h>
|
||||
#include <libdwarf.h>
|
||||
#include <libelftc.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
ELFTC_VCSID("$Id: findtextrel.c 2185 2011-11-19 16:07:16Z jkoshy $");
|
||||
|
||||
static struct option longopts[] = {
|
||||
{"help", no_argument, NULL, 'H'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
#define USAGE_MESSAGE "\
|
||||
Usage: %s [options] [files...]\n\
|
||||
Show text relocations present in position independent code.\n\n\
|
||||
Options:\n\
|
||||
-H Print a help message.\n\
|
||||
-V Print a version identifier and exit.\n"
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
(void) fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
version(void)
|
||||
{
|
||||
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static const char *
|
||||
find_symbol(const char *fn, Elf *e, Elf_Data *d, GElf_Shdr *sh, uintmax_t off)
|
||||
{
|
||||
GElf_Sym sym;
|
||||
const char *name;
|
||||
int i, len;
|
||||
|
||||
len = d->d_size / sh->sh_entsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (gelf_getsym(d, i, &sym) != &sym) {
|
||||
warnx("%s: gelf_getsym() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (GELF_ST_TYPE(sym.st_info) != STT_FUNC)
|
||||
continue;
|
||||
if (off >= sym.st_value && off < sym.st_value + sym.st_size) {
|
||||
name = elf_strptr(e, sh->sh_link, sym.st_name);
|
||||
if (name == NULL)
|
||||
warnx("%s: elf_strptr() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
return (name);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
report_textrel(const char *fn, Elf *e, Dwarf_Debug dbg, uintmax_t off,
|
||||
int *textrel)
|
||||
{
|
||||
Dwarf_Die die;
|
||||
Dwarf_Line *lbuf;
|
||||
Dwarf_Error de;
|
||||
Dwarf_Half tag;
|
||||
Dwarf_Unsigned lopc, hipc, lineno, plineno;
|
||||
Dwarf_Signed lcount;
|
||||
Dwarf_Addr lineaddr, plineaddr;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *d;
|
||||
GElf_Shdr sh;
|
||||
const char *name;
|
||||
char *file, *pfile;
|
||||
int elferr, found, i, ret;
|
||||
|
||||
if (!*textrel) {
|
||||
printf("%s: ELF object contains text relocation records:\n",
|
||||
fn);
|
||||
*textrel = 1;
|
||||
}
|
||||
|
||||
printf("%s: off: %#jx", fn, off);
|
||||
|
||||
found = 0;
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||
warnx("%s: gelf_getshdr() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (sh.sh_type != SHT_DYNSYM &&
|
||||
sh.sh_type != SHT_SYMTAB)
|
||||
continue;
|
||||
(void) elf_errno();
|
||||
if ((d = elf_getdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("%s: elf_getdata() failed: %s",
|
||||
fn, elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (d->d_size <= 0)
|
||||
continue;
|
||||
if ((name = find_symbol(fn, e, d, &sh, off)) != NULL) {
|
||||
printf(", func: %s", name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("%s: elf_nextscn() failed: %s", fn,
|
||||
elf_errmsg(elferr));
|
||||
|
||||
if (dbg == NULL)
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* More verbose output if debugging information is available.
|
||||
*/
|
||||
|
||||
while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
|
||||
&de)) == DW_DLV_OK) {
|
||||
die = NULL;
|
||||
while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
|
||||
if (dwarf_tag(die, &tag, &de) != DW_DLV_OK)
|
||||
goto out;
|
||||
/* XXX: What about DW_TAG_partial_unit? */
|
||||
if (tag == DW_TAG_compile_unit)
|
||||
break;
|
||||
}
|
||||
if (die == NULL) {
|
||||
/* Could not find DW_TAG_compile_unit DIE. */
|
||||
goto out;
|
||||
}
|
||||
if (!dwarf_attrval_unsigned(die, DW_AT_low_pc, &lopc, &de) &&
|
||||
!dwarf_attrval_unsigned(die, DW_AT_high_pc, &hipc, &de)) {
|
||||
/*
|
||||
* Check if the address falls into the PC range of
|
||||
* this CU.
|
||||
*/
|
||||
if (off < lopc || off >= hipc)
|
||||
continue;
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (dwarf_srclines(die, &lbuf, &lcount, &de) != DW_DLV_OK)
|
||||
continue;
|
||||
|
||||
found = 0;
|
||||
plineaddr = ~0ULL;
|
||||
plineno = 0;
|
||||
pfile = NULL;
|
||||
for (i = 0; i < lcount; i++) {
|
||||
if (dwarf_lineaddr(lbuf[i], &lineaddr, &de))
|
||||
continue;
|
||||
if (dwarf_lineno(lbuf[i], &lineno, &de))
|
||||
continue;
|
||||
if (dwarf_linesrc(lbuf[i], &file, &de))
|
||||
continue;
|
||||
if (off == lineaddr) {
|
||||
found = 1;
|
||||
goto out;
|
||||
} else if (off < lineaddr && off > plineaddr) {
|
||||
lineno = plineno;
|
||||
file = pfile;
|
||||
found = 1;
|
||||
goto out;
|
||||
}
|
||||
plineaddr = lineaddr;
|
||||
plineno = lineno;
|
||||
pfile = file;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (found)
|
||||
printf(", file: %s, line: %ju", file, lineno);
|
||||
|
||||
/*
|
||||
* Reset internal CU pointer, so we will start from the first CU
|
||||
* next round.
|
||||
*/
|
||||
while (ret != DW_DLV_NO_ENTRY) {
|
||||
if (ret == DW_DLV_ERROR)
|
||||
break;
|
||||
ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
|
||||
&de);
|
||||
}
|
||||
|
||||
done:
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
examine_reloc(const char *fn, Elf *e, Elf_Data *d, GElf_Shdr *sh, GElf_Phdr *ph,
|
||||
int phnum, Dwarf_Debug dbg, int *textrel)
|
||||
{
|
||||
GElf_Rel rel;
|
||||
GElf_Rela rela;
|
||||
int i, j, len;
|
||||
|
||||
len = d->d_size / sh->sh_entsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (sh->sh_type == SHT_REL) {
|
||||
if (gelf_getrel(d, i, &rel) != &rel) {
|
||||
warnx("%s: gelf_getrel() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (gelf_getrela(d, i, &rela) != &rela) {
|
||||
warnx("%s: gelf_getrela() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (j = 0; j < phnum; j++) {
|
||||
if (sh->sh_type == SHT_REL) {
|
||||
if (rel.r_offset >= ph[j].p_offset &&
|
||||
rel.r_offset < ph[j].p_offset +
|
||||
ph[j].p_filesz)
|
||||
report_textrel(fn, e, dbg,
|
||||
(uintmax_t) rel.r_offset, textrel);
|
||||
} else {
|
||||
if (rela.r_offset >= ph[j].p_offset &&
|
||||
rela.r_offset < ph[j].p_offset +
|
||||
ph[j].p_filesz)
|
||||
report_textrel(fn, e, dbg,
|
||||
(uintmax_t) rela.r_offset, textrel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
find_textrel(const char *fn)
|
||||
{
|
||||
Elf *e;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *d;
|
||||
GElf_Ehdr eh;
|
||||
GElf_Phdr *ph;
|
||||
GElf_Shdr sh;
|
||||
Dwarf_Debug dbg;
|
||||
Dwarf_Error de;
|
||||
int elferr, fd, i, phnum, textrel;
|
||||
|
||||
e = NULL;
|
||||
ph = NULL;
|
||||
dbg = NULL;
|
||||
|
||||
if ((fd = open(fn, O_RDONLY)) < 0) {
|
||||
warn("%s", fn);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
|
||||
warnx("%s: elf_begin() failed: %s", fn, elf_errmsg(-1));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (gelf_getehdr(e, &eh) != &eh) {
|
||||
warnx("%s: gelf_getehdr() failed: %s", fn, elf_errmsg(-1));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (eh.e_type != ET_DYN) {
|
||||
printf("%s: ELF object is not a DSO/PIE\n", fn);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search program header for executable segments.
|
||||
*/
|
||||
|
||||
if (eh.e_phnum == 0) {
|
||||
printf("%s: ELF object does not contain program headers\n",
|
||||
fn);
|
||||
goto exit;
|
||||
}
|
||||
if ((ph = calloc(eh.e_phnum, sizeof(GElf_Phdr))) == NULL)
|
||||
err(EXIT_FAILURE, "calloc failed");
|
||||
phnum = 0;
|
||||
for (i = 0; (unsigned) i < eh.e_phnum; i++) {
|
||||
if (gelf_getphdr(e, i, &ph[phnum]) != &ph[phnum]) {
|
||||
warnx("%s: gelf_getphdr() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (ph[phnum].p_flags & PF_X)
|
||||
phnum++;
|
||||
}
|
||||
if (phnum == 0) {
|
||||
printf("%s: ELF object does not contain any executable "
|
||||
"segment\n", fn);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Check if debugging information is available. */
|
||||
if (dwarf_elf_init(e, DW_DLC_READ, NULL, NULL, &dbg, &de))
|
||||
dbg = NULL;
|
||||
|
||||
/*
|
||||
* Search relocation records for possible text relocations.
|
||||
*/
|
||||
textrel = 0;
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &sh) == NULL) {
|
||||
warnx("%s: gelf_getshdr() failed: %s", fn,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (sh.sh_type == SHT_REL || sh.sh_type == SHT_RELA) {
|
||||
(void) elf_errno();
|
||||
if ((d = elf_getdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("%s: elf_getdata() failed: %s",
|
||||
fn, elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (d->d_size <= 0)
|
||||
continue;
|
||||
examine_reloc(fn, e, d, &sh, ph, phnum, dbg, &textrel);
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
warnx("%s: elf_nextscn() failed: %s", fn, elf_errmsg(elferr));
|
||||
|
||||
if (!textrel)
|
||||
printf("%s: ELF object does not contain a text relocation\n",
|
||||
fn);
|
||||
|
||||
exit:
|
||||
if (dbg)
|
||||
dwarf_finish(dbg, &de);
|
||||
if (ph)
|
||||
free(ph);
|
||||
if (e)
|
||||
(void) elf_end(e);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int i, opt;
|
||||
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
errx(EXIT_FAILURE, "elf_version(): %s", elf_errmsg(-1));
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "HV", longopts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'H':
|
||||
usage();
|
||||
case 'V':
|
||||
version();
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
argc -= optind;
|
||||
|
||||
if (argc > 0)
|
||||
for (i = 0; i < argc; i++)
|
||||
find_textrel(argv[i]);
|
||||
else
|
||||
find_textrel("a.out");
|
||||
|
||||
exit(0);
|
||||
}
|
20
isa/Makefile
Normal file
20
isa/Makefile
Normal file
|
@ -0,0 +1,20 @@
|
|||
# $Id: Makefile 2903 2013-01-16 12:35:50Z jkoshy $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= isa
|
||||
SRCS= isa.c
|
||||
LSRC=
|
||||
YSRC=
|
||||
LDADD= -lelftc
|
||||
|
||||
ISA= avr.isa
|
||||
|
||||
MAN= isa.1 isa.5
|
||||
|
||||
check-specifications: .PHONY
|
||||
.for f in ${ISA}
|
||||
${.OBJDIR}/${PROG} -n --query ${f}
|
||||
.endfor
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
280
isa/avr.isa
Normal file
280
isa/avr.isa
Normal file
|
@ -0,0 +1,280 @@
|
|||
;
|
||||
; $Id: avr.isa 2899 2013-01-16 05:17:02Z jkoshy $
|
||||
;
|
||||
; An instruction set description for Atmel AVR(TM) 8 bit CPUs.
|
||||
;
|
||||
; * Most instructions are 16 bit wide, except a few that use an
|
||||
; additional 16-bit offset field.
|
||||
; * There are 32 general purpose registers which are 8-bit wide.
|
||||
; Three pairs of registers are used for 16bit memory addressing:
|
||||
; X (r27:r26), Y (r29:r28), and Z (r31:r30).
|
||||
; * Some instructions operate on limited subsets of these registers:
|
||||
; - The 'movw' instruction operates on register pairs.
|
||||
; - Some instructions only operate on subsets of the register file.
|
||||
|
||||
arch avr
|
||||
cpus
|
||||
core = [ AT90S1200 ATtiny11 ATtiny12 ATtiny15 ATtiny28 ]
|
||||
core8k = core ++ [ AT90S2313 AT90S2323 ATtiny22 AT90S2333
|
||||
AT90S2343 AT90S4414 AT90S4433 AT90S4434 AT90S8515
|
||||
AT90C8534 AT90S8535 ATtiny26 ATmega8515 ]
|
||||
core128k = core8k ++ [ ATmega103 ATmega603 AT43USB320 AT76C711 ]
|
||||
enhancedcore = core ++ [ ATmega8 ATmega83 ATmega85 ]
|
||||
; TODO fill in the rest.
|
||||
|
||||
; The instruction stream has two types of tokens:
|
||||
token i(16) ; a 16 bit instruction.
|
||||
offset(16) ; a 16 bit offset
|
||||
|
||||
; The 32 source registers are encoded using a combination of a 4-bit
|
||||
; and a 1-bit field.
|
||||
let Rsrclow = i[3:0]
|
||||
Rsrchighbit = i[9]
|
||||
Rsrc = Rsrchighbit & Rsrclow
|
||||
where Rsrc[4] = Rsrchighbit
|
||||
Rsrc[3:0] = Rsrclow
|
||||
names [ R%n | n = 0..31 ]
|
||||
Rsrcpair = i[3:0] ; Source register pairs.
|
||||
names [ R%n | n = 0..31, n % 2 == 0 ]
|
||||
|
||||
Rdst = i[8:4] ; The 32 dst registers use 5 contiguous bits.
|
||||
names [ R%n | n = 0..31 ]
|
||||
Rdstpair = i[7:4] ; destination register pairs
|
||||
names [ R%n | n = 0..31, n %2 == 0 ]
|
||||
|
||||
; Some instructions work on the 16 higher numbered registers.
|
||||
Rsrchigh = i[7:4]
|
||||
names [ R%n | n = 16..31 ]
|
||||
Rdsthigh = i[7:4]
|
||||
names [ R%n | n = 16..31 ]
|
||||
|
||||
; Registers used for the MUL instructions (R16-23).
|
||||
Rmulsrc = i[2:0]
|
||||
names [ R%n | n = 16..23 ]
|
||||
Rmuldst = i[6:4]
|
||||
names [ R%n | n = 16..23 ]
|
||||
|
||||
; 8 bit immediate value.
|
||||
let Khigh = i[11:8]
|
||||
Klow = i[ 3:0]
|
||||
K = Khigh & Klow
|
||||
where K[8:4] = Khigh
|
||||
K[3:0] = Klow
|
||||
|
||||
; call or jmp to an absolute location
|
||||
let jmpcallbit = i[1]
|
||||
Jmpcall loc = i[15:9] = 0b1001010 & i[3:2] = 0b11 &
|
||||
i[8:4] = loc[21:17] & i[0] = loc[16]
|
||||
<+> ; next location
|
||||
offset[15:0] = loc[15:0]
|
||||
in
|
||||
call %loc <=> Jmpcall loc & jmpcallbit = 1
|
||||
jmp %loc <=> Jmpcall loc & jmpcallbit = 0
|
||||
|
||||
; Immediate operations on the high registers.
|
||||
let immediateops@[ sbci subi sbr cbr ] = [ i[13:12] = n | n = 0..3 ]
|
||||
with i[15:14] = 0b01
|
||||
@immediateops %Rdsthigh, %K <=> &*
|
||||
|
||||
; The CPI (Compare Immediate) instruction has a different encoding.
|
||||
cpi %Rdsthigh, %K <=> i[15:12] = 0b0011 &*
|
||||
|
||||
; Move register pair.
|
||||
movw %Rdstpair, %Rsrcpair <=> i[15:8] = 0b00000001 &*
|
||||
|
||||
; 8x8 -> 16 bit signed multiply.
|
||||
muls %Rdsthigh, %Rsrchigh <=> i[15:8] = 0b00000010 &*
|
||||
|
||||
; Unsigned multiply.
|
||||
mul %Rdst, %Rsrc <=> i[15:10] = 0b100111 &*
|
||||
|
||||
; Fractional multiply instructions.
|
||||
with i[15:8] = 0b00000011
|
||||
fmulsu %Rmuldst, %Rmulsrc <=> i[7,3] = [1,1] &*
|
||||
fmuls %Rmuldst, %Rmulsrc <=> i[7,3] = [1,0] &*
|
||||
fmul %Rmuldst, %Rmulsrc <=> i[7,3] = [0,1] &*
|
||||
mulsu %Rmuldst, %Rmulsrc <=> i[7,3] = [0,0] &*
|
||||
|
||||
; 2-operand instructions operating on all 32 registers.
|
||||
let OpTwo@[ cpc sbc add cpse cp sub adc and eor or mov ] in
|
||||
cpc = i[15:10] = 0b000001
|
||||
with i[15:12] = 0b0010
|
||||
[ and eor or mov ] = [ i[11:10] = n | n = 0..3 ]
|
||||
with i[15:12] = 0b0001
|
||||
[ cpse cp sub adc ] = [ i[11:10] = n | n = 0..3 ]
|
||||
with i[15:11] = 0b00001
|
||||
[ sbc add ] = [ i[10] = n | n = 0..1 ]
|
||||
in
|
||||
@OpTwo %Rdst, %Rsrc <=> &*
|
||||
|
||||
let OpOne = [ com neg swap inc asr lsr ror ]
|
||||
with i[15:9] = 0b1001010 & i[3] = 0
|
||||
[ com neg swap inc _ asr lsr ror ] = [ i[2:0] = n | n = 0..7 ]
|
||||
in
|
||||
@OpOne %Rdst <=> &*
|
||||
|
||||
let bitno = i[2:0]
|
||||
|
||||
let clear = i[7] in
|
||||
with i[15:8] = 0b10010100 & i[3:0] = 0b1000
|
||||
bclr %bitno <=> clear = 1 &*
|
||||
bset %bitno <=> clear = 0 &*
|
||||
|
||||
; Additional aliases.
|
||||
let statusbit = i[6:4]
|
||||
names [ "C" "Z" "N" "V" "S" "H" "T" "I" ]
|
||||
cl%statusbit <=> bclr & bitno = statusbit
|
||||
se%statusbit <=> bset & bitno = statusbit
|
||||
|
||||
|
||||
; NOP
|
||||
nop <=> i[15:0] = 0
|
||||
|
||||
let loadstore = i[9]
|
||||
|
||||
; Index load/store with offset
|
||||
let lddlow = i[2:0]
|
||||
lddmid = i[11:10]
|
||||
lddhigh = i[13]
|
||||
Lddoffset = lddlow & lddmid & lddhigh
|
||||
where Lddoffset[5] = lddhigh
|
||||
Lddoffset[4:3] = lddmid
|
||||
Lddoffset[2:0] = lddlow
|
||||
yz = i[3] ; Y/Z bit for LDD with offset
|
||||
names [ "Z" "Y" ]
|
||||
with i[15:14] = 0b10 & i[12] = 0b0
|
||||
ldd %Rdst, %yz "+" %Lddoffset <=> loadstore = 0 &*
|
||||
std %Rdst, %yz "+" %Lddoffset <=> loadstore = 1 &*
|
||||
|
||||
; Indexed load/store with increment & decrement
|
||||
let xyz = i[3:2] ; X/Y/Z for LD ops
|
||||
names [ "Z" _ "Y" "X" ]
|
||||
auto = i[0:1]
|
||||
with i[15:10] = 0b100100 ; prefix for indexed loads
|
||||
ld %Rdst, %xyz <=> loadstore = 0 & auto = 0 &*
|
||||
ld %Rdst, %xyz+ <=> loadstore = 0 & auto = 1 &*
|
||||
ld %Rdst, -%xyz <=> loadstore = 0 & auto = 2 &*
|
||||
st %xyz, %Rdst <=> loadstore = 1 & auto = 0 &*
|
||||
st %xyz+, %Rdst <=> loadstore = 1 & auto = 1 &*
|
||||
st -%xyz, %Rdst <=> loadstore = 1 & auto = 2 &*
|
||||
|
||||
; The 'andi' instruction is 'cbi' with a negated constant.
|
||||
andi %Rdsthigh, %Kcomp <=> cbr & Rdsthigh & K = ~Kcomp
|
||||
; The 'ori' instruction is an alias for 'sbr'.
|
||||
ori %Rdsthigh, %K <=> sbr &*
|
||||
|
||||
; Single operand instructions implemented using two operand ones.
|
||||
clr %Rdst <=> eor & Rsrc = Rdst & Rdst
|
||||
lsl %Rdst <=> add & Rsrc = Rdst & Rdst
|
||||
rol %Rdst <=> adc & Rsrc = Rdst & Rdst
|
||||
tst %Rdst <=> and & Rsrc = Rdst & Rdst
|
||||
|
||||
with i[15:9] = 0b1001010 & i[7:0] = 0b0001001
|
||||
ijmp <=> indircallbit = 0 & eibit = 0
|
||||
icall <=> indircallbit = 1 & eibit = 0
|
||||
eijmp <=> indircallbit = 0 & eibit = 1
|
||||
eicall <=> indircallbit = 1 & eibit = 1
|
||||
where indircallbit = i[7]
|
||||
eibit = i[4]
|
||||
|
||||
with i[15:8] = 0b10010101 & i[3:0] = 0b1000
|
||||
let splops = i[7:4]
|
||||
miscops@[ ret reti sleep break wdr lpm elpm spm ] =
|
||||
[ splops = [ 0 1 8 9 10 12 13 14 ] ]
|
||||
in
|
||||
@miscops <=> &*
|
||||
|
||||
; Load program memory has two variants.
|
||||
lpm <=> i[15:0] = 0b1001010111001000 ; load to R0
|
||||
lpm %Rdst,Z%zincr <=> i[15:9] = 0b1001000 & i[3:1] = 0b010 &*
|
||||
where zincr = i[0] names [ "" "+" ]
|
||||
|
||||
; Store program memory.
|
||||
spm <=> i[15:0] = 0b1001010111101000
|
||||
|
||||
; Decrement register.
|
||||
dec %Rdst <=> i[15:9] = 0b1001010 & i[3:0] = 0b1010 &*
|
||||
|
||||
; DES round %des, operates on R0..R15
|
||||
let des = i[7:4] in
|
||||
des %des <=> i[15:8] = 0b10010100 & i[3:0] = 0b1011 &*
|
||||
|
||||
; Add/Sub register pairs with an immediate
|
||||
let addsub = i[8]
|
||||
Rdstimm = i[5:4]
|
||||
names [ R24 R26 R28 R30 ]
|
||||
Kimm6high = i[7:6]
|
||||
Kimm6low = i[3:0]
|
||||
Kimm6 = Kimm6high & Kimm6low
|
||||
where Kimm6[5:4] = Kimm6high
|
||||
Kimm6[3:0] = Kimm6low
|
||||
with i[15:9] = 0b1001011
|
||||
adiw %Rdstimm, %Kimm6 <=> addsub = 0 &*
|
||||
sbiw %Rdstimm, %Kimm6 <=> addsub = 1 &*
|
||||
|
||||
; Operations on bits in I/O registers.
|
||||
let bitops@[ cbi sbic sbi sbis ] = [ instr[9:8] = n | n = 0..3 ]
|
||||
ioaddr = i[7:3]
|
||||
with i[15:10] = 0b100110
|
||||
@bitops %ioaddr, %bit <=> &*
|
||||
|
||||
; IN/OUT operations
|
||||
let inout = i[11]
|
||||
Alow = i[3:0]
|
||||
Ahigh = i[10:9]
|
||||
A = Ahigh & Alow
|
||||
with i[15..12] = 0b1011
|
||||
in %Rdst, %A <=> inout = 0 & *
|
||||
out %Rst, %A <=> inout = 1 & *
|
||||
|
||||
; Relative jmp/call
|
||||
let reljmpcall = i[12]
|
||||
reloffset = i[11:0]
|
||||
with i[15:13] = 0b110
|
||||
rjmp %label <=> reljmpcall = 0 & reloffset = (label - . - 1)
|
||||
rcall %label <=> reljmpcall = 1 & reloffset = (label - . - 1)
|
||||
|
||||
; Load Immediate
|
||||
ldi %Rdsthigh, %K <=> i[15:12] = 0b1110 &*
|
||||
|
||||
; Conditional branches
|
||||
let clearedorset = i[10]
|
||||
condoffset = i[9:3]
|
||||
with i[15:11] = 0b11110
|
||||
brbs %bitno, %label <=> clearedorset = 0 & bitno &
|
||||
condoffset = (label - . - 1)
|
||||
brbc %bitno, %label <=> clearedorset = 1 & bitno &
|
||||
condoffset = (label - . - 1)
|
||||
|
||||
; Aliases
|
||||
brcs %l => brbs & bitno = 0 & label = l
|
||||
brlo %l => brbs & bitno = 0 & label = l
|
||||
breq %l => brbs & bitno = 1 & label = l
|
||||
brmi %l => brbs & bitno = 2 & label = l
|
||||
brvs %l => brbs & bitno = 3 & label = l
|
||||
brlt %l => brbs & bitno = 4 & label = l
|
||||
brhs %l => brbs & bitno = 5 & label = l
|
||||
brts %l => brbs & bitno = 6 & label = l
|
||||
brie %l => brbs & bitno = 7 & label = l
|
||||
|
||||
brcc %l => brbc & bitno = 0 & label = l
|
||||
brsh %l => brbc & bitno = 0 & label = l
|
||||
brne %l => brbc & bitno = 1 & label = l
|
||||
brpl %l => brbc & bitno = 2 & label = l
|
||||
brvc %l => brbc & bitno = 3 & label = l
|
||||
brge %l => brbc & bitno = 4 & label = l
|
||||
brhc %l => brbc & bitno = 5 & label = l
|
||||
brtc %l => brbc & bitno = 6 & label = l
|
||||
brid %l => brbc & bitno = 7 & label = l
|
||||
|
||||
; BLD/BST
|
||||
let bldst = i[9]
|
||||
with i[15:10] = 0b111110 & i[3] = 0
|
||||
bld %Rdst, %bitno <=> bldst = 0 &*
|
||||
bst %Rdst, %bitno <=> bldst = 1 &*
|
||||
|
||||
; SBRC/SBRS
|
||||
let setclr = i[9]
|
||||
with i[15:10] = 0b111111 & i[3] = 0
|
||||
sbrc %Rdst, %bit <=> setclr = 0 &*
|
||||
sbrc %Rdst, %bit <=> setclr = 1 &*
|
248
isa/isa.1
Normal file
248
isa/isa.1
Normal file
|
@ -0,0 +1,248 @@
|
|||
.\" Copyright (c) 2012,2013 Joseph Koshy.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: isa.1 2889 2013-01-13 15:36:04Z jkoshy $
|
||||
.\"
|
||||
.Dd January 13, 2013
|
||||
.Os
|
||||
.Dt ISA 1
|
||||
.Sh NAME
|
||||
.Nm isa
|
||||
.Nd instruction set analyser
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl a Ar architecture | Fl -arch Ns = Ns Ar architecture
|
||||
.Op Fl c Ar cpu | Fl -cpu Ns = Ns Ar cpu
|
||||
.Op Fl h | Fl -help
|
||||
.Op Fl i Ar filename | Fl -input Ns = Ns Ar filename
|
||||
.Op Fl n | Fl -dry-run
|
||||
.Op Fl o Ar filename | Fl -output Ns = Ns Ar filename
|
||||
.Op Fl p Ar string | Fl -prefix Ns = Ns Ar string
|
||||
.Op Fl s Ar filename | Fl -spec Ns = Ns Ar filename
|
||||
.Op Fl q | Fl -quiet
|
||||
.Op Fl v | Fl -verbose
|
||||
.Op Fl D | Fl -decode
|
||||
.Op Fl E | Fl -encode
|
||||
.Op Fl L | Fl -list-instructions
|
||||
.Op Fl N Ar number | Fl -ntests Ns = Ns Ar number
|
||||
.Op Fl Q | Fl -query
|
||||
.Op Fl R Ar number | Fl -random-seed Ns = Ns Ar number
|
||||
.Op Fl T | Fl -test
|
||||
.Op Fl V | Fl -version
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is used to generate instruction stream encoders and decoders
|
||||
from a textual description of a CPU instruction set.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility supports three operational modes, as specified by the use of
|
||||
the
|
||||
.Fl D ,
|
||||
.Fl E
|
||||
or
|
||||
.Fl Q
|
||||
options:
|
||||
.Bl -tag -width indent
|
||||
.It Cm Decode
|
||||
.Pq Fl D | Fl -decode
|
||||
In this mode, the
|
||||
.Nm
|
||||
utility transforms source code, expanding match pattern between the
|
||||
tokens
|
||||
.Dq Li "[ISA["
|
||||
and
|
||||
.Dq Li "]ISA]"
|
||||
into the appropriate code for matching instruction streams.
|
||||
The section
|
||||
.Sx "Matching Instructions"
|
||||
describes the decode functionality in greater depth.
|
||||
.It Cm Encode
|
||||
.Pq Fl E | Fl -encode
|
||||
In this mode, the
|
||||
.Nm
|
||||
utility generates C code to emit binary instruction streams.
|
||||
.It Cm Query
|
||||
.Pq Fl Q | Fl -query
|
||||
In this mode, the
|
||||
.Nm
|
||||
utility is used to retrieve information from instruction set
|
||||
specifications.
|
||||
.El
|
||||
.Pp
|
||||
If no operational mode is specified, a default of
|
||||
.Cm Query
|
||||
will be used.
|
||||
.Pp
|
||||
Instruction set specifications may be specified using the
|
||||
.Fa a
|
||||
option, or by using the command line arguments
|
||||
.Ar .
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
utility accepts the following options:
|
||||
.Bl -tag -width indent
|
||||
.It Fl a Ar architecture | Fl -arch Ns = N Ar architecture
|
||||
Use instruction set specifications specified by the argument
|
||||
.Ar architecture .
|
||||
The
|
||||
.Nm
|
||||
utility will look for these specifications in the locations
|
||||
specified by the environment variable
|
||||
.Ev ISAPATH ,
|
||||
in addition to a built-in search location.
|
||||
The default architecture is that for the host the
|
||||
.Nm
|
||||
utility is being executed on.s
|
||||
.It Fl c Ar cpu | Fl -cpu Ns = Ns Ar cpu
|
||||
Generate encoders and decoders for the specific instruction set
|
||||
variant supported by CPU
|
||||
.Ar cpu .
|
||||
This option may be specified multiple times.
|
||||
If the argument
|
||||
.Ar cpu
|
||||
starts with a minus, the CPU specified will be removed from list of
|
||||
CPUs to be supported.
|
||||
.It Fl h | Fl -help
|
||||
Print a help message and exit.
|
||||
.It Fl i Ar filename | Fl -input Ns = Ns Ar filename
|
||||
When generating a decoder, read the source to be expanded from the
|
||||
file named in the argument
|
||||
.Ar filename .
|
||||
If an input file is not specified, the
|
||||
.Nm
|
||||
utility will read from its standard input.
|
||||
.It Fl n | Fl -dry-run
|
||||
Exit without creating any output after checking inputs for errors.
|
||||
.It Fl o Ar filename | Fl -output Ns = Ns Ar filename
|
||||
When generating encoders and decoders, send the output to the file
|
||||
specified by the argument
|
||||
.Ar filename .
|
||||
If an output file is not specified, the
|
||||
.Nm
|
||||
utility will write to its standard output.
|
||||
.It Fl p Ar string | Fl -prefix Ns = Ns Ar string
|
||||
When in encode mode, use the string in argument
|
||||
.Ar string
|
||||
as a prefix for generated symbols.
|
||||
.It Fl q | Fl -quiet
|
||||
Suppress warning messages.
|
||||
.It Fl s Ar filename | Fl -spec Ns = Ns Ar filename
|
||||
Read an instruction set specification from the file named by argument
|
||||
.Ar filename .
|
||||
This option may be specified multiple times, in which case the
|
||||
.Nm
|
||||
utilitiy behaves as if the specifications had been concatenated in the
|
||||
sequence specified.
|
||||
.It Fl v | Fl -verbose
|
||||
Increase the verbosity level.
|
||||
This option may be specified multiple times.
|
||||
.It Fl D | Fl -decode
|
||||
Transform sources expanding match patterns in source code to
|
||||
lower-level instruction stream decoding code.
|
||||
By default, the
|
||||
.Nm
|
||||
utility will read from standard input and write to standard output,
|
||||
unless otherwise specified by the
|
||||
.Fl i
|
||||
and
|
||||
.Fl o
|
||||
options.
|
||||
.It Fl E | Fl -encode
|
||||
Build an instruction stream encoder.
|
||||
.It Fl L | Fl -list-instructions
|
||||
When in query mode, generate a list of all known instructions.
|
||||
.It Fl N Ar number | Fl -ntests Ns = Ns Ar number
|
||||
When in query mode, specify the number of test sequences to be
|
||||
generated if the
|
||||
.Fl -T | Fl -test
|
||||
option was specified.
|
||||
.It Fl Q | Fl -query
|
||||
Retrieve information about an instruction set.
|
||||
.It Fl R Ar number | Fl -random-seed Ns = Ns Ar number
|
||||
Use the argument
|
||||
.Ar number
|
||||
as the seed for pseudorandom number generation.
|
||||
If this option is not specified, the
|
||||
.Nm
|
||||
utility will initialize the pseudorandom number generator in an
|
||||
implementation-defined manner.
|
||||
.It Fl T | Fl -test
|
||||
Generate instruction sequences for use in testing tools such as
|
||||
assemblers.
|
||||
.It Fl V | Fl -version
|
||||
Print a version identifier and exit.
|
||||
.El
|
||||
.Sh ENVIRONMENT
|
||||
The behavior of the
|
||||
.Nm
|
||||
utility is affected by the following environemnt variables:
|
||||
.Bl -tag
|
||||
.It Ev ISAPATH
|
||||
Specifies a colon-separated set of directories tp be used when
|
||||
searching for instruction specifications.
|
||||
.El
|
||||
.Sh FILES
|
||||
.Bl -tag -width indent
|
||||
.It Pa /usr/share/isa/
|
||||
The default location for instruction set specifications.
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
To check the instruction specifications in file
|
||||
.Pa spec.isa ,
|
||||
use:
|
||||
.D1 isa -n "spec.isa"
|
||||
.Pp
|
||||
To expand instruction decoding templates in the file
|
||||
.Pa a.m ,
|
||||
assuming a generic
|
||||
.Tn AVR
|
||||
CPU, and generating a C source file, use:
|
||||
.D1 isa -a avr -D < a.m > a.c
|
||||
.Sh SEE ALSO
|
||||
.Xr elf 3 ,
|
||||
.Xr elf 5 ,
|
||||
.Xr isa 5
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility is scheduled to appear in a future release from the
|
||||
Elftoolchain project.
|
||||
.\" TODO Reword the above when the target release is finalized.
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Xr isa 1
|
||||
utility was written by
|
||||
.An Joseph Koshy
|
||||
.Aq jkoshy@users.sourceforge.net .
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
utility is wildly unstable at this point of time.
|
||||
If you intend to use this utility, please get in touch with the
|
||||
project's developers at
|
||||
.Aq elftoolchain-developers@lists.sourceforge.net .
|
366
isa/isa.5
Normal file
366
isa/isa.5
Normal file
|
@ -0,0 +1,366 @@
|
|||
.\" Copyright (c) 2013 Joseph Koshy.
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $Id: isa.5 2900 2013-01-16 12:27:01Z jkoshy $
|
||||
.\"
|
||||
.Dd January 16, 2013
|
||||
.Os
|
||||
.Dt ISA 1
|
||||
.Sh NAME
|
||||
.Nm isa
|
||||
.Nd input file format for the isa utility
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility is used to generate instruction stream encoders and decoders
|
||||
from a textual description of a machine instruction set.
|
||||
This manual page documents the form of the textual description
|
||||
accepted by the
|
||||
.Nm
|
||||
utility.
|
||||
.Ss Basic Concepts
|
||||
A machine instruction is composed of one
|
||||
.Em tokens ,
|
||||
each kind of token having a defined width.
|
||||
Simple RISC-like instruction sets have instructions that use 1 or 2
|
||||
tokens, typically an instruction word and an optional immediate field.
|
||||
More complex CISC instruction sets may use many more kinds of tokens.
|
||||
.Pp
|
||||
Each token is made up of
|
||||
.Em fields ,
|
||||
for example, an instruction token could be made up of an opcode field,
|
||||
additional fields naming registers, fields containing flags, immediate
|
||||
values and so on.
|
||||
Fields may be named using the
|
||||
.Cm let
|
||||
directive, or can be unnamed.
|
||||
The bitslice operator
|
||||
.Pq Li \&[]
|
||||
can be used to denote specific portions of a token.
|
||||
.Pp
|
||||
Non-overlapping fields are grouped together into
|
||||
.Em fragments .
|
||||
Fragments may be composed using the
|
||||
.Dq "&"
|
||||
operator.
|
||||
The textual form of a fragment may be specified using
|
||||
the
|
||||
.Li names
|
||||
directive.
|
||||
.Pp
|
||||
A set of fragments that fully specifies each bit in a token is
|
||||
said to be
|
||||
.Sq complete .
|
||||
Only complete fragment sets can be emitted.
|
||||
.Pp
|
||||
.Ss Input Syntax
|
||||
The semicolon
|
||||
.Dq "\&;"
|
||||
introduces a comment.
|
||||
All text from the semicolon to the end of the line is ignored.
|
||||
.Pp
|
||||
The language uses indentation to specify scope (i.e., it uses the
|
||||
offside rule), as in the
|
||||
.Ic Python
|
||||
and
|
||||
.Ic Haskell
|
||||
programming languages.
|
||||
.Ss Operators
|
||||
.Bl -tag
|
||||
.It "Composing Fragments"
|
||||
The
|
||||
.Dq Li \&&
|
||||
operator is used to join fragments, forming a larger fragment.
|
||||
For example, to specify a fragment that is comprised of two
|
||||
previously named fragments
|
||||
.Ar Rtop
|
||||
and
|
||||
.Ar Rbottom ,
|
||||
use:
|
||||
.Bd -literal -offset indent
|
||||
Rtop & Rbottom
|
||||
.Ed
|
||||
.It "Generators"
|
||||
A generator expression has the form
|
||||
.Li [ Ar expr1 Ns Li \&| Ns Ar expr2 Ns \&... Ns Li ]
|
||||
and denotes a sequence of values
|
||||
.Va expr1 ,
|
||||
where the additional expressions
|
||||
.Va expr2
|
||||
serve to define the range of values generated.
|
||||
Any
|
||||
.Dq Li \&% Ns
|
||||
-escapes in
|
||||
.Va expr1
|
||||
are expanded.
|
||||
For example,
|
||||
.Dl [ R%n | n = 0..31 ]
|
||||
generates the sequence
|
||||
.Li R0 ,
|
||||
.Li R1 ,
|
||||
\&... ,
|
||||
.Li R31 .
|
||||
.It "Numeric Ranges"
|
||||
The notation
|
||||
.Dq \&..
|
||||
denotes a numeric range.
|
||||
For example,
|
||||
.Dl 0..(2^16-1)
|
||||
represents the numbers 0 to 65535, inclusive.
|
||||
.It Sequences
|
||||
Sequences of items are bracketed by square brackets
|
||||
.Dq "\&["
|
||||
and
|
||||
.Dq "\&]" .
|
||||
For example,
|
||||
.Dl "let n = [ a b c d ]"
|
||||
Sequences can be given a local name using the
|
||||
.Va name
|
||||
.Li @
|
||||
.Va sequence
|
||||
syntax, for example:
|
||||
.Dl bar@[ 1 2 3 ]
|
||||
defines
|
||||
.Va bar
|
||||
as a local name for the expression [ 1 2 3 ].
|
||||
.Pp
|
||||
The
|
||||
.Dq Li \&++
|
||||
operator is used to concatenate sequences.
|
||||
These sequences must be of the same type.
|
||||
.It "Sequencing Tokens"
|
||||
The
|
||||
.Dq Li \&<+>
|
||||
operator separates tokens in sequence.
|
||||
For example, to specify an instruction that has two tokens T1 and T2
|
||||
in sequence, use:
|
||||
.Bd -literal -offset indent
|
||||
\&..the definition of T1..
|
||||
<+>
|
||||
\&..the definition of T2..
|
||||
.Ed
|
||||
.It Slices
|
||||
Slices may be specified using the slice notation, namely
|
||||
.Ar name Ns
|
||||
.Li \&[ Ns
|
||||
.Ar highbit Ns
|
||||
.Li \&: Ns
|
||||
.Ar lowbit Ns
|
||||
.Li \&] ,
|
||||
where
|
||||
.Ar highbit
|
||||
and
|
||||
.Ar lowbit
|
||||
are inclusive zero-based indices and
|
||||
.Ar name
|
||||
is the name of a token.
|
||||
.Bd -literal -offset indent
|
||||
let Rsrc = instruction[3:0]
|
||||
.Ed
|
||||
.Pp
|
||||
Sparse slices may be specified by separating slice expressions using
|
||||
commas, for example bit 7 and 5 of the
|
||||
.Va ifield
|
||||
token may be specified using:
|
||||
.Dl ifield[7,5]
|
||||
.It "Specifying Assembly Formats"
|
||||
The
|
||||
.Dq Li \&<=>
|
||||
infix operator is used to specify assembly language syntax and its
|
||||
mapping to sequences of fragments defined earlier, see the section
|
||||
.Sx "Defining Assembly Syntax" .
|
||||
.Pp
|
||||
The
|
||||
.Dq Li \&&*
|
||||
operator indicates that all the named fragments in the LHS (the
|
||||
assembly syntax side) of the
|
||||
.Dq Li \&<=>
|
||||
operator should be treated as being present on the RHS.
|
||||
This operator allows instructions that have a simple one-to-one
|
||||
mapping between their assembly language definition and instruction
|
||||
encoding to be described succinctly.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
muls %Rd, %Rs <=> i[15:8] = 0b00000010 &*
|
||||
.Ed
|
||||
.El
|
||||
.Ss Language Constructs
|
||||
The input language has the following constructs:
|
||||
.Bl -tag -width indent
|
||||
.It Li arch Ar string
|
||||
Specifies the name of the instruction set architecture being
|
||||
processed.
|
||||
.Bd -literal -offset indent
|
||||
arch myarch
|
||||
.Ed
|
||||
.It Li cpus
|
||||
Starts a block naming CPU identifiers.
|
||||
Specific instructions or groups of instructions may be flagged
|
||||
as being supported on sets of the CPUs so declared.
|
||||
.Bd -literal -offset indent
|
||||
cpus
|
||||
basic = [ CPU1 CPU2 ]
|
||||
advanced = basic ++ [ CPU3 ]
|
||||
.Ed
|
||||
.It Li token Ar name "(" Ar width ")"
|
||||
Defines a token with name
|
||||
.Ar name
|
||||
and width
|
||||
.Ar width .
|
||||
For example, to define a 16 bit named
|
||||
.Ar i
|
||||
(short for
|
||||
.Dq instruction ) ,
|
||||
and a 8 bit offset token named
|
||||
.Ar o ,
|
||||
use:
|
||||
.Bd -literal -offset indent
|
||||
token i(16) ; a comment here
|
||||
o(8)
|
||||
.Ed
|
||||
.It Li let Ar name [ Ar params ] "=" Ar expression
|
||||
Declare
|
||||
.Ar name
|
||||
as being the equivalent of
|
||||
.Ar expression .
|
||||
.It Li names Ar generator-expression
|
||||
Defines the textual representation for a fragment.
|
||||
For example,
|
||||
.Bd -literal -offset indent -compact
|
||||
let Rsrc = i[3:0]
|
||||
names [ R%n | n = 0..7 ]
|
||||
.Ed
|
||||
specifies that a value of 0 for fragment
|
||||
.Va Rsrc
|
||||
should be shown as
|
||||
.Li R0 ,
|
||||
and so on.
|
||||
Conversely, when assembing text, the string
|
||||
.Dq R15
|
||||
would be translated to a fragment value of 15.
|
||||
.It Li where Ar name [ Ar params ] = Ar expression
|
||||
Like the
|
||||
.Li let
|
||||
statement, a
|
||||
.Li where
|
||||
statement introduces local definitions, except that the scope of these
|
||||
definitions is the statement preceding the
|
||||
.Li where
|
||||
keyword.
|
||||
Example:
|
||||
.Bd -literal -offset indent
|
||||
let Kimm6 = Kimm6high & Kimm6low
|
||||
where Kimm6[5:4] = Kimm6high
|
||||
Kimm6[3:0] = Kimm6low
|
||||
.Ed
|
||||
.It Li with Ar fragment-definition
|
||||
Defines fragment assignments that hold for statements in the scope of
|
||||
the
|
||||
.Li with
|
||||
statement.
|
||||
For example,
|
||||
.Bd -literal -offset indent
|
||||
with i[15:8] = 0b00000011
|
||||
fmulsu %Rd, %Rs <=> i[7,3] = [1,1] &*
|
||||
.Ed
|
||||
.El
|
||||
.Ss Defining Assembly Syntax
|
||||
Assembly syntax is described using the
|
||||
.Li \&<=>
|
||||
operator.
|
||||
The form of the operator is
|
||||
.Bd -ragged -offset indent
|
||||
assembler-text
|
||||
.Li \&<=>
|
||||
.Va fragment
|
||||
.Li \&&
|
||||
.Va fragment
|
||||
.Li & \&...
|
||||
.Ed
|
||||
.Pp
|
||||
The RHS of the
|
||||
.Li \&<=>
|
||||
operator must specify a
|
||||
.Sq complete
|
||||
fragment set, i.e., no bits should be unspecified in any of the tokens
|
||||
used in the RHS.
|
||||
The LHS of the
|
||||
.Li \&<=>
|
||||
operator consists of literal text interspersed by fragment names.
|
||||
Fragment names are prefixed by the
|
||||
.Sq \&%
|
||||
character.
|
||||
These fragment names in the LHS may refer to fragment names defined
|
||||
earlier, or may be new names that are local to the current definition.
|
||||
.Pp
|
||||
For example, the following definition defines an instruction with
|
||||
mnemonic
|
||||
.Dq Li rjmp .
|
||||
.Bd -literal -offset indent
|
||||
let reloffset = i[11:0]
|
||||
reljmpcall = i[12]
|
||||
in
|
||||
with i[15:13] = 0b110
|
||||
rjmp %label <=> reljmpcall = 0 & reloffset = (label - . - 1)
|
||||
.Ed
|
||||
.Pp
|
||||
In this definition, the field
|
||||
.Va label
|
||||
is a local fragment, one that is used to compute the value of the
|
||||
.Va reloffset
|
||||
field in the instruction.
|
||||
In the RHS, the
|
||||
.Va reljmpcall
|
||||
bit is defined as being 0.
|
||||
The rest of the bits in the token
|
||||
.Va i
|
||||
are specified by the enclosing
|
||||
.Li with
|
||||
statement.
|
||||
.Sh SEE ALSO
|
||||
.Xr elf 3 ,
|
||||
.Xr elf 5 ,
|
||||
.Xr isa 1
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
utility is scheduled to appear in a future release from the
|
||||
Elftoolchain project.
|
||||
.\" TODO Reword the above when the target release is finalized.
|
||||
.Sh AUTHORS
|
||||
The
|
||||
.Xr isa 1
|
||||
utility was written by
|
||||
.An Joseph Koshy
|
||||
.Aq jkoshy@users.sourceforge.net .
|
||||
.Sh BUGS
|
||||
The
|
||||
.Nm
|
||||
utility is
|
||||
.Ud
|
||||
The input format documented in this manual is likely to change
|
||||
in the future.
|
||||
If you intend to use this utility, please get in touch with the
|
||||
project's developers at
|
||||
.Aq elftoolchain-developers@lists.sourceforge.net .
|
286
isa/isa.c
Normal file
286
isa/isa.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
/*-
|
||||
* Copyright (c) 2012,2013 Joseph Koshy
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libelftc.h>
|
||||
|
||||
#include "_elftc.h"
|
||||
|
||||
ELFTC_VCSID("$Id: isa.c 2934 2013-03-30 01:40:49Z jkoshy $");
|
||||
|
||||
/*
|
||||
* Option handling.
|
||||
*/
|
||||
|
||||
enum isa_mode {
|
||||
ISA_MODE_DECODE,
|
||||
ISA_MODE_ENCODE,
|
||||
ISA_MODE_QUERY
|
||||
};
|
||||
|
||||
enum isa_submode {
|
||||
ISA_SUBMODE_GENERATE_TESTS,
|
||||
ISA_SUBMODE_LIST_INSTRUCTIONS
|
||||
};
|
||||
|
||||
#define ISA_OPT_DRY_RUN 0x0001
|
||||
#define ISA_OPT_NO_WARNINGS 0x0002
|
||||
#define ISA_OPT_VERBOSE 0x0004
|
||||
|
||||
/* Record a option. */
|
||||
struct isa_option {
|
||||
const char *isa_option;
|
||||
SLIST_ENTRY(isa_option) isa_next;
|
||||
};
|
||||
|
||||
struct isa_config {
|
||||
unsigned int isa_flags;
|
||||
enum isa_mode isa_mode;
|
||||
enum isa_submode isa_submode;
|
||||
int isa_ntests;
|
||||
int isa_seed;
|
||||
const char *isa_arch;
|
||||
const char *isa_input;
|
||||
const char *isa_output;
|
||||
const char *isa_prefix;
|
||||
SLIST_HEAD(,isa_option) isa_cpus;
|
||||
SLIST_HEAD(,isa_option) isa_specs;
|
||||
};
|
||||
|
||||
#define ISA_MAX_LONG_OPTION_LENGTH 64
|
||||
|
||||
static struct option isa_long_options[] = {
|
||||
{ "arch", required_argument, NULL, 'a' },
|
||||
{ "cpu", required_argument, NULL, 'c' },
|
||||
{ "decode", no_argument, NULL, 'D' },
|
||||
{ "dry-run", no_argument, NULL, 'n' },
|
||||
{ "encode", no_argument, NULL, 'E' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "input", required_argument, NULL, 'i' },
|
||||
{ "list-instructions", no_argument, NULL, 'L' },
|
||||
{ "ntests", required_argument, NULL, 'N' },
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "prefix", required_argument, NULL, 'p' },
|
||||
{ "query", no_argument, NULL, 'Q' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "random-seed", required_argument, NULL, 'R' },
|
||||
{ "spec", required_argument, NULL, 's' },
|
||||
{ "test", no_argument, NULL, 'T' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
static const char *isa_usage_message = "\
|
||||
usage: %s [options] [command] [specfiles]...\n\
|
||||
Process an instruction set specification.\n\
|
||||
\n\
|
||||
Supported values for 'command' are:\n\
|
||||
decode Build an instruction stream decoder.\n\
|
||||
encode Build an instruction stream encoder.\n\
|
||||
query (default) Retrieve information about an instruction set.\n\
|
||||
\n\
|
||||
Supported global options are:\n\
|
||||
-a ARCH | --arch ARCH Process instruction specifications for ARCH.\n\
|
||||
-c CPU | --cpu CPU Process instruction specifications for CPU.\n\
|
||||
-n | --dry-run Exit after checking inputs for errors.\n\
|
||||
-s FILE | --spec FILE Read instruction specifications from FILE.\n\
|
||||
-q | --quiet Suppress warning messages.\n\
|
||||
-v | --verbose Be verbose.\n\
|
||||
-V | --version Display a version identifier and exit.\n\
|
||||
\n\
|
||||
Supported options for command 'decode' are:\n\
|
||||
-i FILE | --input FILE Read source to be expanded from FILE.\n\
|
||||
-o FILE | --output FILE Write generated output to FILE.\n\
|
||||
\n\
|
||||
Supported options for command 'encode' are:\n\
|
||||
-o FILE | --output FILE Write generated output to FILE.\n\
|
||||
-p STR | --prefix STR Use STR as a prefix for generated symbols.\n\
|
||||
\n\
|
||||
Supported options for command 'query' are:\n\
|
||||
-L | --list-instructions Generate a list of all known instructions.\n\
|
||||
-N NUM | --ntests NUM Specify the number of test sequences generated.\n\
|
||||
-R N | --random-seed N Use N as the random number generator seed.\n\
|
||||
-T | --test Generate test sequences.\n\
|
||||
";
|
||||
|
||||
void
|
||||
isa_usage(int iserror, const char *message, ...)
|
||||
{
|
||||
FILE *channel;
|
||||
va_list ap;
|
||||
|
||||
channel = iserror ? stderr : stdout;
|
||||
|
||||
if (message) {
|
||||
va_start(ap, message);
|
||||
(void) vfprintf(channel, message, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
(void) fprintf(channel, isa_usage_message, ELFTC_GETPROGNAME());
|
||||
exit(iserror != 0);
|
||||
}
|
||||
|
||||
void
|
||||
isa_unimplemented(int option, int option_index, struct option *options_table)
|
||||
{
|
||||
char msgbuf[ISA_MAX_LONG_OPTION_LENGTH];
|
||||
|
||||
if (option_index >= 0)
|
||||
(void) snprintf(msgbuf, sizeof(msgbuf), "\"--%s\"",
|
||||
options_table[option_index].name);
|
||||
else
|
||||
(void) snprintf(msgbuf, sizeof(msgbuf), "'-%c'",
|
||||
option);
|
||||
errx(1, "ERROR: option %s is unimplemented.", msgbuf);
|
||||
}
|
||||
|
||||
struct isa_option *
|
||||
isa_make_option(const char *arg)
|
||||
{
|
||||
struct isa_option *isa_opt;
|
||||
|
||||
if ((isa_opt = malloc(sizeof(*isa_opt))) == NULL)
|
||||
return (NULL);
|
||||
isa_opt->isa_option = optarg;
|
||||
|
||||
return (isa_opt);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int option, option_index;
|
||||
struct isa_option *isa_opt;
|
||||
struct isa_config config;
|
||||
|
||||
(void) memset(&config, 0, sizeof(config));
|
||||
config.isa_mode = ISA_MODE_QUERY;
|
||||
config.isa_arch = config.isa_input = config.isa_output =
|
||||
config.isa_prefix = NULL;
|
||||
SLIST_INIT(&config.isa_cpus);
|
||||
SLIST_INIT(&config.isa_specs);
|
||||
|
||||
for (option_index = -1;
|
||||
(option = getopt_long(argc, argv, "a:c:hi:no:p:qs:vDELN:QR:TV",
|
||||
isa_long_options, &option_index)) != -1;
|
||||
option_index = -1) {
|
||||
switch (option) {
|
||||
case 'h':
|
||||
isa_usage(0, NULL);
|
||||
break;
|
||||
case 'V':
|
||||
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(),
|
||||
elftc_version());
|
||||
exit(0);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
config.isa_arch = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
if ((isa_opt = isa_make_option(optarg)) == NULL)
|
||||
goto error;
|
||||
SLIST_INSERT_HEAD(&config.isa_cpus, isa_opt, isa_next);
|
||||
break;
|
||||
case 'i':
|
||||
config.isa_input = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
config.isa_flags |= ISA_OPT_DRY_RUN;
|
||||
break;
|
||||
case 'o':
|
||||
config.isa_output = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
config.isa_prefix = optarg;
|
||||
break;
|
||||
case 'q':
|
||||
config.isa_flags |= ISA_OPT_NO_WARNINGS;
|
||||
break;
|
||||
case 's':
|
||||
if ((isa_opt = isa_make_option(optarg)) == NULL)
|
||||
goto error;
|
||||
SLIST_INSERT_HEAD(&config.isa_specs, isa_opt,
|
||||
isa_next);
|
||||
break;
|
||||
case 'v':
|
||||
config.isa_flags |= ISA_OPT_VERBOSE;
|
||||
break;
|
||||
case 'D':
|
||||
config.isa_mode = ISA_MODE_DECODE;
|
||||
break;
|
||||
case 'E':
|
||||
config.isa_mode = ISA_MODE_ENCODE;
|
||||
break;
|
||||
case 'L':
|
||||
config.isa_submode = ISA_SUBMODE_LIST_INSTRUCTIONS;
|
||||
break;
|
||||
case 'N':
|
||||
config.isa_ntests = atoi(optarg);
|
||||
break;
|
||||
case 'Q':
|
||||
config.isa_mode = ISA_MODE_QUERY;
|
||||
break;
|
||||
case 'R':
|
||||
config.isa_seed = atoi(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
config.isa_submode = ISA_SUBMODE_GENERATE_TESTS;
|
||||
break;
|
||||
default:
|
||||
isa_usage(1, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the canonical list of specification files to
|
||||
* be processed.
|
||||
*/
|
||||
for (;optind < argc; optind++) {
|
||||
if ((isa_opt = isa_make_option(argv[optind])) == NULL)
|
||||
goto error;
|
||||
SLIST_INSERT_HEAD(&config.isa_specs, isa_opt,
|
||||
isa_next);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
error:
|
||||
err(1, "ERROR: Invocation failed");
|
||||
}
|
||||
|
49
ld/Makefile
Normal file
49
ld/Makefile
Normal file
|
@ -0,0 +1,49 @@
|
|||
# $Id: Makefile 2910 2013-02-03 06:06:23Z kaiwang27 $
|
||||
|
||||
TOP= ..
|
||||
|
||||
PROG= ld
|
||||
WARNS?= 6
|
||||
|
||||
SRCS= amd64.c \
|
||||
amd64_script.c \
|
||||
i386.c \
|
||||
i386_script.c \
|
||||
ld_arch.c \
|
||||
ld_dynamic.c \
|
||||
ld_ehframe.c \
|
||||
ld_error.c \
|
||||
ld_exp.c \
|
||||
ld_file.c \
|
||||
ld_hash.c \
|
||||
ld_input.c \
|
||||
ld_layout.c \
|
||||
ld_main.c \
|
||||
ld_options.c \
|
||||
ld_output.c \
|
||||
ld_path.c \
|
||||
ld_reloc.c \
|
||||
ld_script.c \
|
||||
ld_script_lexer.l \
|
||||
ld_script_parser.y \
|
||||
ld_strtab.c \
|
||||
ld_symbols.c \
|
||||
ld_symver.c \
|
||||
y.tab.h
|
||||
|
||||
.SUFFIXES: .ld .c
|
||||
.ld.c:
|
||||
awk -f ld_script.awk ${.ALLSRC} > ${.TARGET}
|
||||
|
||||
GENSRCS= amd64_script.c i386_script.c
|
||||
|
||||
CLEANFILES+= y.tab.h ${GENSRCS}
|
||||
|
||||
DPADD= ${LIBELFTC} ${LIBELF} ${LIBDWARF}
|
||||
LDADD= -lelftc -ldwarf -lelf
|
||||
|
||||
CFLAGS+= -I. -I${.CURDIR}
|
||||
|
||||
NOMAN=
|
||||
|
||||
.include "${TOP}/mk/elftoolchain.prog.mk"
|
1363
ld/amd64.c
Normal file
1363
ld/amd64.c
Normal file
File diff suppressed because it is too large
Load diff
31
ld/amd64.h
Normal file
31
ld/amd64.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: amd64.h 2500 2012-04-29 18:07:43Z kaiwang27 $
|
||||
*/
|
||||
|
||||
char *amd64_script;
|
||||
|
||||
void amd64_register(struct ld *);
|
151
ld/amd64_script.ld
Normal file
151
ld/amd64_script.ld
Normal file
|
@ -0,0 +1,151 @@
|
|||
/* $Id: amd64_script.ld 2806 2012-12-24 08:23:59Z kaiwang27 $ */
|
||||
|
||||
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
|
||||
SECTIONS {
|
||||
PROVIDE(__executable_start = 0x400000);
|
||||
. = 0x400000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.dyn :
|
||||
{
|
||||
*(.rel.init)
|
||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
||||
*(.rel.fini)
|
||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
||||
*(.rel.ctors)
|
||||
*(.rel.dtors)
|
||||
*(.rel.got)
|
||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
||||
}
|
||||
.rela.dyn :
|
||||
{
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP(*(.init))
|
||||
} = 0x90909090
|
||||
.plt : { *(.plt) }
|
||||
.text :
|
||||
{
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
} = 0x90909090
|
||||
.fini :
|
||||
{
|
||||
KEEP(*(.fini))
|
||||
} = 0x90909090
|
||||
PROVIDE(__etext = .);
|
||||
PROVIDE(_etext = .);
|
||||
PROVIDE(etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||
.eh_frame : { KEEP(*(.eh_frame)) }
|
||||
.gcc_except_table : { *(.gcc_except_table) }
|
||||
. = ALIGN (CONSTANT(MAXPAGESIZE)) - ((CONSTANT(MAXPAGESIZE) - .) & (CONSTANT(MAXPAGESIZE) - 1));
|
||||
. = DATA_SEGMENT_ALIGN (CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE));
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
PROVIDE(__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE(__preinit_array_end = .);
|
||||
PROVIDE(__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE(__init_array_end = .);
|
||||
PROVIDE(__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE(__fini_array_end = .);
|
||||
.ctors :
|
||||
{
|
||||
KEEP(*crtbegin*.o(.ctors))
|
||||
KEEP(*(EXCLUDE_FILE (*crtend*.o ) .ctors))
|
||||
KEEP(*(SORT(.ctors.*)))
|
||||
KEEP(*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP(*crtbegin*.o(.dtors))
|
||||
KEEP(*(EXCLUDE_FILE (*crtend*.o ) .dtors))
|
||||
KEEP(*(SORT(.dtors.*)))
|
||||
KEEP(*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP(*(.jcr)) }
|
||||
.data.rel.ro : {
|
||||
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
|
||||
*(.data.rel.ro* .gnu.linkonce.d.rel.ro.*)
|
||||
}
|
||||
.dynamic : { *(.dynamic) }
|
||||
.got : { *(.got) }
|
||||
.got.plt : { *(.got.plt) }
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
_edata = .;
|
||||
PROVIDE(edata = .);
|
||||
__bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(64 / 8);
|
||||
}
|
||||
. = ALIGN(64 / 8);
|
||||
_end = .;
|
||||
PROVIDE(end = .);
|
||||
. = DATA_SEGMENT_END (.);
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
|
||||
/* DWARF1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
||||
/* GNU DWARF1 Extension */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
|
||||
/* DWARF2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
}
|
624
ld/i386.c
Normal file
624
ld/i386.c
Normal file
|
@ -0,0 +1,624 @@
|
|||
/*-
|
||||
* Copyright (c) 2012,2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "ld_dynamic.h"
|
||||
#include "ld_input.h"
|
||||
#include "ld_output.h"
|
||||
#include "ld_reloc.h"
|
||||
#include "ld_symbols.h"
|
||||
#include "ld_utils.h"
|
||||
#include "i386.h"
|
||||
|
||||
ELFTC_VCSID("$Id: i386.c 2967 2013-10-12 23:58:13Z kaiwang27 $");
|
||||
|
||||
static void _create_plt_reloc(struct ld *ld, struct ld_symbol *lsb,
|
||||
uint64_t offset);
|
||||
static void _create_got_reloc(struct ld *ld, struct ld_symbol *lsb,
|
||||
uint64_t type, uint64_t offset);
|
||||
static void _create_copy_reloc(struct ld *ld, struct ld_symbol *lsb);
|
||||
static void _create_dynamic_reloc(struct ld *ld, struct ld_input_section *is,
|
||||
struct ld_symbol *lsb, uint64_t type, uint64_t offset);
|
||||
static void _scan_reloc(struct ld *ld, struct ld_input_section *is,
|
||||
struct ld_reloc_entry *lre);
|
||||
static struct ld_input_section *_find_and_create_got_section(struct ld *ld,
|
||||
int create);
|
||||
static struct ld_input_section *_find_and_create_gotplt_section(struct ld *ld,
|
||||
int create);
|
||||
static struct ld_input_section *_find_and_create_plt_section(struct ld *ld,
|
||||
int create);
|
||||
static uint64_t _get_max_page_size(struct ld *ld);
|
||||
static uint64_t _get_common_page_size(struct ld *ld);
|
||||
static void _process_reloc(struct ld *ld, struct ld_input_section *is,
|
||||
struct ld_reloc_entry *lre, struct ld_symbol *lsb, uint8_t *buf);
|
||||
static const char *_reloc2str(uint64_t r);
|
||||
static void _reserve_got_entry(struct ld *ld, struct ld_symbol *lsb, int num);
|
||||
static void _reserve_gotplt_entry(struct ld *ld, struct ld_symbol *lsb);
|
||||
static void _reserve_plt_entry(struct ld *ld, struct ld_symbol *lsb);
|
||||
static int _is_absolute_reloc(uint64_t r);
|
||||
static int _is_relative_reloc(uint64_t r);
|
||||
static void _warn_pic(struct ld *ld, struct ld_reloc_entry *lre);
|
||||
static uint32_t _got_offset(struct ld *ld, struct ld_symbol *lsb);
|
||||
|
||||
static uint64_t
|
||||
_get_max_page_size(struct ld *ld)
|
||||
{
|
||||
|
||||
(void) ld;
|
||||
return (0x1000);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
_get_common_page_size(struct ld *ld)
|
||||
{
|
||||
|
||||
(void) ld;
|
||||
return (0x1000);
|
||||
}
|
||||
|
||||
static const char *
|
||||
_reloc2str(uint64_t r)
|
||||
{
|
||||
static char s[32];
|
||||
|
||||
switch (r) {
|
||||
case 0: return "R_386_NONE";
|
||||
case 1: return "R_386_32";
|
||||
case 2: return "R_386_PC32";
|
||||
case 3: return "R_386_GOT32";
|
||||
case 4: return "R_386_PLT32";
|
||||
case 5: return "R_386_COPY";
|
||||
case 6: return "R_386_GLOB_DAT";
|
||||
case 7: return "R_386_JMP_SLOT";
|
||||
case 8: return "R_386_RELATIVE";
|
||||
case 9: return "R_386_GOTOFF";
|
||||
case 10: return "R_386_GOTPC";
|
||||
case 14: return "R_386_TLS_TPOFF";
|
||||
case 15: return "R_386_TLS_IE";
|
||||
case 16: return "R_386_TLS_GOTI";
|
||||
case 17: return "R_386_TLS_LE";
|
||||
case 18: return "R_386_TLS_GD";
|
||||
case 19: return "R_386_TLS_LDM";
|
||||
case 24: return "R_386_TLS_GD_32";
|
||||
case 25: return "R_386_TLS_GD_PUSH";
|
||||
case 26: return "R_386_TLS_GD_CALL";
|
||||
case 27: return "R_386_TLS_GD_POP";
|
||||
case 28: return "R_386_TLS_LDM_32";
|
||||
case 29: return "R_386_TLS_LDM_PUSH";
|
||||
case 30: return "R_386_TLS_LDM_CALL";
|
||||
case 31: return "R_386_TLS_LDM_POP";
|
||||
case 32: return "R_386_TLS_LDO_32";
|
||||
case 33: return "R_386_TLS_IE_32";
|
||||
case 34: return "R_386_TLS_LE_32";
|
||||
case 35: return "R_386_TLS_DTPMOD32";
|
||||
case 36: return "R_386_TLS_DTPOFF32";
|
||||
case 37: return "R_386_TLS_TPOFF32";
|
||||
|
||||
default:
|
||||
snprintf(s, sizeof(s), "<unkown: %ju>", r);
|
||||
return (s);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_is_absolute_reloc(uint64_t r)
|
||||
{
|
||||
|
||||
if (r == R_386_32)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
_is_relative_reloc(uint64_t r)
|
||||
{
|
||||
|
||||
if (r == R_386_RELATIVE)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
_warn_pic(struct ld *ld, struct ld_reloc_entry *lre)
|
||||
{
|
||||
struct ld_symbol *lsb;
|
||||
|
||||
lsb = lre->lre_sym;
|
||||
|
||||
if (lsb->lsb_bind != STB_LOCAL)
|
||||
ld_warn(ld, "relocation %s against `%s' can not be used"
|
||||
" by runtime linker; recompile with -fPIC",
|
||||
_reloc2str(lre->lre_type), lsb->lsb_name);
|
||||
else
|
||||
ld_warn(ld, "relocation %s can not be used by runtime linker;"
|
||||
" recompile with -fPIC", _reloc2str(lre->lre_type));
|
||||
}
|
||||
|
||||
static struct ld_input_section *
|
||||
_find_and_create_got_section(struct ld *ld, int create)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
|
||||
/* Check if the GOT section is already created. */
|
||||
is = ld_input_find_internal_section(ld, ".got");
|
||||
if (is != NULL)
|
||||
return (is);
|
||||
|
||||
if (create) {
|
||||
is = ld_input_add_internal_section(ld, ".got");
|
||||
is->is_entsize = 4;
|
||||
is->is_align = 4;
|
||||
is->is_type = SHT_PROGBITS;
|
||||
is->is_flags = SHF_ALLOC | SHF_WRITE;
|
||||
}
|
||||
|
||||
return (is);
|
||||
}
|
||||
|
||||
static struct ld_input_section *
|
||||
_find_and_create_gotplt_section(struct ld *ld, int create)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
|
||||
/* Check if the GOT (for PLT) section is already created. */
|
||||
is = ld_input_find_internal_section(ld, ".got.plt");
|
||||
if (is != NULL)
|
||||
return (is);
|
||||
|
||||
if (create) {
|
||||
is = ld_input_add_internal_section(ld, ".got.plt");
|
||||
is->is_entsize = 4;
|
||||
is->is_align = 4;
|
||||
is->is_type = SHT_PROGBITS;
|
||||
is->is_flags = SHF_ALLOC | SHF_WRITE;
|
||||
|
||||
/* Reserve space for the initial entries. */
|
||||
(void) ld_input_reserve_ibuf(is, 3);
|
||||
|
||||
/* Create _GLOBAL_OFFSET_TABLE_ symbol. */
|
||||
ld_symbols_add_internal(ld, "_GLOBAL_OFFSET_TABLE_", 0, 0,
|
||||
is->is_index, STB_LOCAL, STT_OBJECT, STV_HIDDEN, is, NULL);
|
||||
}
|
||||
|
||||
return (is);
|
||||
}
|
||||
|
||||
static struct ld_input_section *
|
||||
_find_and_create_plt_section(struct ld *ld, int create)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
|
||||
/* Check if the PLT section is already created. */
|
||||
is = ld_input_find_internal_section(ld, ".plt");
|
||||
if (is != NULL)
|
||||
return (is);
|
||||
|
||||
if (create) {
|
||||
is = ld_input_add_internal_section(ld, ".plt");
|
||||
is->is_entsize = 4;
|
||||
is->is_align = 4;
|
||||
is->is_type = SHT_PROGBITS;
|
||||
is->is_flags = SHF_ALLOC | SHF_EXECINSTR;
|
||||
|
||||
/* Reserve space for the initial entry. */
|
||||
(void) ld_input_reserve_ibuf(is, 1);
|
||||
}
|
||||
|
||||
return (is);
|
||||
}
|
||||
|
||||
static void
|
||||
_reserve_got_entry(struct ld *ld, struct ld_symbol *lsb, int num)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
|
||||
is = _find_and_create_got_section(ld, 1);
|
||||
|
||||
/* Check if the entry already has a GOT entry. */
|
||||
if (lsb->lsb_got)
|
||||
return;
|
||||
|
||||
/* Reserve GOT entries. */
|
||||
lsb->lsb_got_off = ld_input_reserve_ibuf(is, num);
|
||||
lsb->lsb_got = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_reserve_gotplt_entry(struct ld *ld, struct ld_symbol *lsb)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
uint64_t off;
|
||||
|
||||
is = _find_and_create_gotplt_section(ld, 1);
|
||||
|
||||
/* Reserve a GOT entry for PLT. */
|
||||
off = ld_input_reserve_ibuf(is, 1);
|
||||
|
||||
/*
|
||||
* Record a R_386_JMP_SLOT entry for this symbol. Note that
|
||||
* we don't need to record the offset (relative to the GOT section)
|
||||
* here, since the PLT relocations will be sorted later and we
|
||||
* will generate GOT section according to the new order.
|
||||
*/
|
||||
_create_plt_reloc(ld, lsb, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
_reserve_plt_entry(struct ld *ld, struct ld_symbol *lsb)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
|
||||
is = _find_and_create_plt_section(ld, 1);
|
||||
|
||||
(void) ld_input_reserve_ibuf(is, 1);
|
||||
lsb->lsb_plt = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_create_plt_reloc(struct ld *ld, struct ld_symbol *lsb, uint64_t offset)
|
||||
{
|
||||
|
||||
ld_reloc_create_entry(ld, ".rel.plt", NULL, R_386_JMP_SLOT,
|
||||
lsb, offset, 0);
|
||||
|
||||
lsb->lsb_dynrel = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_create_got_reloc(struct ld *ld, struct ld_symbol *lsb, uint64_t type,
|
||||
uint64_t offset)
|
||||
{
|
||||
struct ld_input_section *tis;
|
||||
|
||||
tis = _find_and_create_got_section(ld, 0);
|
||||
assert(tis != NULL);
|
||||
|
||||
ld_reloc_create_entry(ld, ".rel.got", tis, type, lsb, offset, 0);
|
||||
|
||||
if (type != R_386_RELATIVE)
|
||||
lsb->lsb_dynrel = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_create_copy_reloc(struct ld *ld, struct ld_symbol *lsb)
|
||||
{
|
||||
struct ld_input_section *tis;
|
||||
|
||||
ld_dynamic_reserve_dynbss_entry(ld, lsb);
|
||||
|
||||
tis = ld_input_find_internal_section(ld, ".dynbss");
|
||||
assert(tis != NULL);
|
||||
|
||||
ld_reloc_create_entry(ld, ".rel.bss", tis, R_386_COPY, lsb,
|
||||
lsb->lsb_value, 0);
|
||||
|
||||
lsb->lsb_dynrel = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_create_dynamic_reloc(struct ld *ld, struct ld_input_section *is,
|
||||
struct ld_symbol *lsb, uint64_t type, uint64_t offset)
|
||||
{
|
||||
|
||||
if (lsb->lsb_bind == STB_LOCAL) {
|
||||
if (is->is_flags & SHF_WRITE)
|
||||
ld_reloc_create_entry(ld, ".rel.data.rel.local",
|
||||
is, type, lsb, offset, 0);
|
||||
else
|
||||
ld_reloc_create_entry(ld, ".rel.data.rel.ro.local",
|
||||
is, type, lsb, offset, 0);
|
||||
} else {
|
||||
if (is->is_flags & SHF_WRITE)
|
||||
ld_reloc_create_entry(ld, ".rel.data.rel",
|
||||
is, type, lsb, offset, 0);
|
||||
else
|
||||
ld_reloc_create_entry(ld, ".rel.data.rel.ro",
|
||||
is, type, lsb, offset, 0);
|
||||
}
|
||||
|
||||
if (type != R_386_RELATIVE)
|
||||
lsb->lsb_dynrel = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_scan_reloc(struct ld *ld, struct ld_input_section *is,
|
||||
struct ld_reloc_entry *lre)
|
||||
{
|
||||
struct ld_symbol *lsb;
|
||||
|
||||
lsb = ld_symbols_ref(lre->lre_sym);
|
||||
|
||||
switch (lre->lre_type) {
|
||||
case R_386_NONE:
|
||||
break;
|
||||
|
||||
case R_386_32:
|
||||
/*
|
||||
* For a local symbol, if te linker output a PIE or DSO,
|
||||
* we should generate a R_386_RELATIVE reloc for R_386_32.
|
||||
*/
|
||||
if (lsb->lsb_bind == STB_LOCAL) {
|
||||
if (ld->ld_pie || ld->ld_dso)
|
||||
_create_dynamic_reloc(ld, is, lsb,
|
||||
R_386_RELATIVE, lre->lre_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a global symbol, we probably need to generate PLE entry
|
||||
* and/ore a dynamic relocation.
|
||||
*
|
||||
* Note here, normally the compiler will generate a PC-relative
|
||||
* relocation for function calls. However, if the code retrieve
|
||||
* the address of a function and call it indirectly, assembler
|
||||
* will generate absolute relocation instead. That's why we
|
||||
* should check if we need to create a PLT entry here. Also, if
|
||||
* we're going to create the PLT entry, we should also set the
|
||||
* symbol value to the address of PLT entry just in case the
|
||||
* function address is used to compare with other function
|
||||
* addresses. (If PLT address is used, function will have
|
||||
* unified address in the main executable and DSOs)
|
||||
*/
|
||||
if (ld_reloc_require_plt(ld, lre)) {
|
||||
if (!lsb->lsb_plt) {
|
||||
_reserve_gotplt_entry(ld, lsb);
|
||||
_reserve_plt_entry(ld, lsb);
|
||||
}
|
||||
/*
|
||||
* Note here even if we have generated PLT for this
|
||||
* function before, we still need to set this flag.
|
||||
* It's possible that we first see the relative
|
||||
* relocation then this absolute relocation, in
|
||||
* other words, the same function can be called in
|
||||
* different ways.
|
||||
*/
|
||||
lsb->lsb_func_addr = 1;
|
||||
}
|
||||
|
||||
if (ld_reloc_require_copy_reloc(ld, lre) &&
|
||||
!lsb->lsb_copy_reloc)
|
||||
_create_copy_reloc(ld, lsb);
|
||||
else if (ld_reloc_require_dynamic_reloc(ld, lre)) {
|
||||
/*
|
||||
* Check if we can relax R_386_32 to
|
||||
* R_386_RELATIVE instead.
|
||||
*/
|
||||
if (ld_reloc_relative_relax(ld, lre))
|
||||
_create_dynamic_reloc(ld, is, lsb,
|
||||
R_386_RELATIVE, lre->lre_offset);
|
||||
else
|
||||
_create_dynamic_reloc(ld, is, lsb,
|
||||
R_386_32, lre->lre_offset);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case R_386_PLT32:
|
||||
/*
|
||||
* In some cases we don't really need to generate a PLT
|
||||
* entry, then a R_386_PLT32 relocation can be relaxed
|
||||
* to a R_386_PC32 relocation.
|
||||
*/
|
||||
if (lsb->lsb_bind == STB_LOCAL ||
|
||||
!ld_reloc_require_plt(ld, lre)) {
|
||||
lre->lre_type = R_386_PC32;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If linker outputs an normal executable and the symbol is
|
||||
* defined but is not defined inside a DSO, we can generate
|
||||
* a R_386_PC32 relocation instead.
|
||||
*/
|
||||
if (ld->ld_exec && lsb->lsb_shndx != SHN_UNDEF &&
|
||||
(lsb->lsb_input == NULL ||
|
||||
lsb->lsb_input->li_type != LIT_DSO)) {
|
||||
lre->lre_type = R_386_PC32;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create an PLT entry otherwise. */
|
||||
if (!lsb->lsb_plt) {
|
||||
_reserve_gotplt_entry(ld, lsb);
|
||||
_reserve_plt_entry(ld, lsb);
|
||||
}
|
||||
break;
|
||||
|
||||
case R_386_PC32:
|
||||
/*
|
||||
* When R_386_PC32 apply to a global symbol, we should
|
||||
* check if we need to generate PLT entry and/or a dynamic
|
||||
* relocation.
|
||||
*/
|
||||
if (lsb->lsb_bind != STB_LOCAL) {
|
||||
if (ld_reloc_require_plt(ld, lre) && !lsb->lsb_plt) {
|
||||
_reserve_gotplt_entry(ld, lsb);
|
||||
_reserve_plt_entry(ld, lsb);
|
||||
}
|
||||
|
||||
if (ld_reloc_require_copy_reloc(ld, lre) &&
|
||||
!lsb->lsb_copy_reloc)
|
||||
_create_copy_reloc(ld, lsb);
|
||||
else if (ld_reloc_require_dynamic_reloc(ld, lre)) {
|
||||
/*
|
||||
* We can not generate dynamic relocation for
|
||||
* these PC-relative relocation since they
|
||||
* are probably not supported by the runtime
|
||||
* linkers.
|
||||
*/
|
||||
_warn_pic(ld, lre);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case R_386_GOTOFF:
|
||||
case R_386_GOTPC:
|
||||
/*
|
||||
* These relocation types use GOT address as a base address
|
||||
* and instruct the linker to build a GOT.
|
||||
*/
|
||||
(void) _find_and_create_got_section(ld, 1);
|
||||
break;
|
||||
|
||||
case R_386_GOT32:
|
||||
/*
|
||||
* R_386_GOT32 relocation instructs the linker to build a
|
||||
* GOT and generate a GOT entry.
|
||||
*/
|
||||
if (!lsb->lsb_got) {
|
||||
_reserve_got_entry(ld, lsb, 1);
|
||||
/*
|
||||
* TODO: For now we always create a R_386_GLOB_DAT
|
||||
* relocation for a GOT entry. There are cases that
|
||||
* the symbol's address is known at link time and
|
||||
* the GOT entry value can be filled in by the program
|
||||
* linker instead.
|
||||
*/
|
||||
if (ld_reloc_require_glob_dat(ld, lre))
|
||||
_create_got_reloc(ld, lsb, R_386_GLOB_DAT,
|
||||
lsb->lsb_got_off);
|
||||
else
|
||||
_create_got_reloc(ld, lsb, R_386_RELATIVE,
|
||||
lsb->lsb_got_off);
|
||||
}
|
||||
|
||||
default:
|
||||
ld_warn(ld, "can not handle relocation %ju",
|
||||
lre->lre_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
_got_offset(struct ld *ld, struct ld_symbol *lsb)
|
||||
{
|
||||
struct ld_output_section *os;
|
||||
|
||||
assert(lsb->lsb_got);
|
||||
|
||||
if (ld->ld_got == NULL) {
|
||||
ld->ld_got = _find_and_create_got_section(ld, 0);
|
||||
assert(ld->ld_got != NULL);
|
||||
}
|
||||
|
||||
os = ld->ld_got->is_output;
|
||||
|
||||
return (os->os_addr + ld->ld_got->is_reloff + lsb->lsb_got_off);
|
||||
}
|
||||
|
||||
static void
|
||||
_process_reloc(struct ld *ld, struct ld_input_section *is,
|
||||
struct ld_reloc_entry *lre, struct ld_symbol *lsb, uint8_t *buf)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_output *lo;
|
||||
uint32_t p, s, l, g, got;
|
||||
int32_t a, v;
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
l = lsb->lsb_plt_off;
|
||||
p = lre->lre_offset + is->is_output->os_addr + is->is_reloff;
|
||||
got = ld->ld_got->is_output->os_addr;
|
||||
s = (uint32_t) lsb->lsb_value;
|
||||
READ_32(buf + lre->lre_offset, a);
|
||||
|
||||
switch (lre->lre_type) {
|
||||
case R_386_NONE:
|
||||
break;
|
||||
|
||||
case R_386_32:
|
||||
v = s + a;
|
||||
WRITE_32(buf + lre->lre_offset, v);
|
||||
break;
|
||||
|
||||
case R_386_PC32:
|
||||
if (lsb->lsb_plt)
|
||||
v = l + a - p;
|
||||
else
|
||||
v = s + a - p;
|
||||
WRITE_32(buf + lre->lre_offset, v);
|
||||
break;
|
||||
|
||||
case R_386_PLT32:
|
||||
if (!ls->ls_ignore_next_plt) {
|
||||
v = l + a - p;
|
||||
WRITE_32(buf + lre->lre_offset, v);
|
||||
} else
|
||||
ls->ls_ignore_next_plt = 0;
|
||||
break;
|
||||
|
||||
case R_386_GOT32:
|
||||
g = _got_offset(ld, lsb);
|
||||
v = g + a;
|
||||
WRITE_32(buf + lre->lre_offset, v);
|
||||
break;
|
||||
|
||||
case R_386_GOTOFF:
|
||||
v = s + a - got;
|
||||
WRITE_32(buf + lre->lre_offset, v);
|
||||
break;
|
||||
|
||||
case R_386_GOTPC:
|
||||
v = got + a - p;
|
||||
WRITE_32(buf + lre->lre_offset, v);
|
||||
break;
|
||||
|
||||
default:
|
||||
ld_fatal(ld, "Relocation %d not supported", lre->lre_type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
i386_register(struct ld *ld)
|
||||
{
|
||||
struct ld_arch *i386_arch;
|
||||
|
||||
if ((i386_arch = calloc(1, sizeof(*i386_arch))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
snprintf(i386_arch->name, sizeof(i386_arch->name), "%s", "i386");
|
||||
|
||||
i386_arch->script = i386_script;
|
||||
i386_arch->get_max_page_size = _get_max_page_size;
|
||||
i386_arch->get_common_page_size = _get_common_page_size;
|
||||
i386_arch->scan_reloc = _scan_reloc;
|
||||
i386_arch->process_reloc = _process_reloc;
|
||||
i386_arch->is_absolute_reloc = _is_absolute_reloc;
|
||||
i386_arch->is_relative_reloc = _is_relative_reloc;
|
||||
i386_arch->reloc_is_64bit = 0;
|
||||
i386_arch->reloc_is_rela = 0;
|
||||
i386_arch->reloc_entsize = sizeof(Elf32_Rel);
|
||||
|
||||
HASH_ADD_STR(ld->ld_arch_list, name, i386_arch);
|
||||
}
|
31
ld/i386.h
Normal file
31
ld/i386.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: i386.h 2500 2012-04-29 18:07:43Z kaiwang27 $
|
||||
*/
|
||||
|
||||
char *i386_script;
|
||||
|
||||
void i386_register(struct ld *);
|
148
ld/i386_script.ld
Normal file
148
ld/i386_script.ld
Normal file
|
@ -0,0 +1,148 @@
|
|||
/* $Id: i386_script.ld 2664 2012-11-04 08:39:22Z kaiwang27 $ */
|
||||
|
||||
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
|
||||
OUTPUT_ARCH(i386)
|
||||
ENTRY(_start)
|
||||
SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
|
||||
SECTIONS {
|
||||
PROVIDE (__executable_start = 0x08048000);
|
||||
. = 0x08048000 + SIZEOF_HEADERS;
|
||||
.interp : { *(.interp) }
|
||||
.hash : { *(.hash) }
|
||||
.dynsym : { *(.dynsym) }
|
||||
.dynstr : { *(.dynstr) }
|
||||
.gnu.version : { *(.gnu.version) }
|
||||
.gnu.version_d : { *(.gnu.version_d) }
|
||||
.gnu.version_r : { *(.gnu.version_r) }
|
||||
.rel.dyn :
|
||||
{
|
||||
*(.rel.init)
|
||||
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
|
||||
*(.rel.fini)
|
||||
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
|
||||
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
|
||||
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
|
||||
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
|
||||
*(.rel.ctors)
|
||||
*(.rel.dtors)
|
||||
*(.rel.got)
|
||||
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
|
||||
}
|
||||
.rela.dyn :
|
||||
{
|
||||
*(.rela.init)
|
||||
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||
*(.rela.fini)
|
||||
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||
*(.rela.ctors)
|
||||
*(.rela.dtors)
|
||||
*(.rela.got)
|
||||
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||
}
|
||||
.rel.plt : { *(.rel.plt) }
|
||||
.rela.plt : { *(.rela.plt) }
|
||||
.init :
|
||||
{
|
||||
KEEP(*(.init))
|
||||
} = 0x90909090
|
||||
.plt : { *(.plt) }
|
||||
.text :
|
||||
{
|
||||
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||
} = 0x90909090
|
||||
.fini :
|
||||
{
|
||||
KEEP(*(.fini))
|
||||
} = 0x90909090
|
||||
PROVIDE(__etext = .);
|
||||
PROVIDE(_etext = .);
|
||||
PROVIDE(etext = .);
|
||||
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||
.rodata1 : { *(.rodata1) }
|
||||
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||
.eh_frame : { KEEP(*(.eh_frame)) }
|
||||
.gcc_except_table : { *(.gcc_except_table) }
|
||||
. = ALIGN (CONSTANT(COMMONPAGESIZE)) - ((CONSTANT(COMMONPAGESIZE) - .) & (CONSTANT(COMMONPAGESIZE) - 1));
|
||||
. = DATA_SEGMENT_ALIGN (CONSTANT(COMMONPAGESIZE), CONSTANT(COMMONPAGESIZE));
|
||||
. = ALIGN(32 / 8);
|
||||
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||
PROVIDE(__preinit_array_start = .);
|
||||
.preinit_array : { *(.preinit_array) }
|
||||
PROVIDE(__preinit_array_end = .);
|
||||
PROVIDE(__init_array_start = .);
|
||||
.init_array : { *(.init_array) }
|
||||
PROVIDE(__init_array_end = .);
|
||||
PROVIDE(__fini_array_start = .);
|
||||
.fini_array : { *(.fini_array) }
|
||||
PROVIDE(__fini_array_end = .);
|
||||
.dynamic : { *(.dynamic) }
|
||||
.ctors :
|
||||
{
|
||||
KEEP(*crtbegin*.o(.ctors))
|
||||
KEEP(*(EXCLUDE_FILE (*crtend*.o ) .ctors))
|
||||
KEEP(*(SORT(.ctors.*)))
|
||||
KEEP(*(.ctors))
|
||||
}
|
||||
.dtors :
|
||||
{
|
||||
KEEP(*crtbegin*.o(.dtors))
|
||||
KEEP(*(EXCLUDE_FILE (*crtend*.o ) .dtors))
|
||||
KEEP(*(SORT(.dtors.*)))
|
||||
KEEP(*(.dtors))
|
||||
}
|
||||
.jcr : { KEEP(*(.jcr)) }
|
||||
.got : { *(.got.plt) *(.got) }
|
||||
.data :
|
||||
{
|
||||
*(.data .data.* .gnu.linkonce.d.*)
|
||||
SORT(CONSTRUCTORS)
|
||||
}
|
||||
.data1 : { *(.data1) }
|
||||
_edata = .;
|
||||
PROVIDE(edata = .);
|
||||
__bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.dynbss)
|
||||
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||
*(COMMON)
|
||||
. = ALIGN(32 / 8);
|
||||
}
|
||||
. = ALIGN(32 / 8);
|
||||
_end = .;
|
||||
PROVIDE(end = .);
|
||||
. = DATA_SEGMENT_END (.);
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
.stabstr 0 : { *(.stabstr) }
|
||||
.stab.excl 0 : { *(.stab.excl) }
|
||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||
.stab.index 0 : { *(.stab.index) }
|
||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||
.comment 0 : { *(.comment) }
|
||||
|
||||
/* DWARF1 */
|
||||
.debug 0 : { *(.debug) }
|
||||
.line 0 : { *(.line) }
|
||||
|
||||
/* GNU DWARF1 Extension */
|
||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||
|
||||
/* DWARF2 */
|
||||
.debug_aranges 0 : { *(.debug_aranges) }
|
||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||
.debug_line 0 : { *(.debug_line) }
|
||||
.debug_frame 0 : { *(.debug_frame) }
|
||||
.debug_str 0 : { *(.debug_str) }
|
||||
.debug_loc 0 : { *(.debug_loc) }
|
||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||
|
||||
/DISCARD/ : { *(.note.GNU-stack) }
|
||||
}
|
158
ld/ld.h
Normal file
158
ld/ld.h
Normal file
|
@ -0,0 +1,158 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld.h 2940 2013-05-04 22:22:10Z kaiwang27 $
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ar.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <gelf.h>
|
||||
#include <inttypes.h>
|
||||
#include <libelftc.h>
|
||||
#include <libgen.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "dwarf.h"
|
||||
#define oom() ld_fatal(ld, "out of memory")
|
||||
#include "utarray.h"
|
||||
#define uthash_fatal(msg) ld_fatal(ld, msg)
|
||||
#include "uthash.h"
|
||||
#include "_elftc.h"
|
||||
|
||||
struct ld_file;
|
||||
struct ld_input_section_head;
|
||||
struct ld_path;
|
||||
struct ld_symbol;
|
||||
struct ld_symbol_head;
|
||||
struct ld_output_data_buffer;
|
||||
struct ld_wildcard_match;
|
||||
struct ld_ehframe_cie_head;
|
||||
struct ld_ehframe_fde_head;
|
||||
struct ld_section_group;
|
||||
|
||||
#define LD_MAX_NESTED_GROUP 16
|
||||
|
||||
struct ld_state {
|
||||
Elftc_Bfd_Target *ls_itgt; /* input bfd target set by -b */
|
||||
struct ld_file *ls_file; /* current open file */
|
||||
unsigned ls_static; /* use static library */
|
||||
unsigned ls_whole_archive; /* include whole archive */
|
||||
unsigned ls_as_needed; /* DT_NEEDED */
|
||||
unsigned ls_group_level; /* archive group level */
|
||||
unsigned ls_extracted[LD_MAX_NESTED_GROUP + 1];
|
||||
/* extracted from archive group */
|
||||
unsigned ls_search_dir; /* search library directories */
|
||||
uint64_t ls_loc_counter; /* location counter */
|
||||
uint64_t ls_offset; /* cur. output section file offset */
|
||||
STAILQ_HEAD(, ld_path) ls_lplist; /* search path list */
|
||||
STAILQ_HEAD(, ld_path) ls_rplist; /* rpath list */
|
||||
STAILQ_HEAD(, ld_path) ls_rllist; /* rpath-link list */
|
||||
unsigned ls_arch_conflict; /* input arch conflict with output */
|
||||
unsigned ls_first_elf_object; /* first ELF object to process */
|
||||
unsigned ls_rerun; /* ld(1) restarted */
|
||||
unsigned ls_archive_mb_header; /* extracted list header printed */
|
||||
unsigned ls_first_output_sec; /* flag indicates 1st output section */
|
||||
unsigned ls_ignore_next_plt; /* ignore next PLT relocation */
|
||||
unsigned ls_version_local; /* version entry is local */
|
||||
uint64_t ls_relative_reloc; /* number of *_RELATIVE relocations */
|
||||
struct ld_input_section_head *ls_gc;
|
||||
/* garbage collection search list */
|
||||
};
|
||||
|
||||
struct ld {
|
||||
const char *ld_progname; /* ld(1) program name */
|
||||
struct ld_arch *ld_arch; /* arch-specific callbacks */
|
||||
struct ld_arch *ld_arch_list; /* list of supported archs */
|
||||
Elftc_Bfd_Target *ld_otgt; /* default output format */
|
||||
Elftc_Bfd_Target *ld_otgt_be; /* big-endian output format */
|
||||
Elftc_Bfd_Target *ld_otgt_le; /* little-endian output format */
|
||||
char *ld_otgt_name; /* output format name */
|
||||
char *ld_otgt_be_name; /* big-endian output format name */
|
||||
char *ld_otgt_le_name; /* little-endian output format name */
|
||||
struct ld_output *ld_output; /* output object */
|
||||
char *ld_output_file; /* output file name */
|
||||
char *ld_entry; /* entry point set by -e */
|
||||
char *ld_scp_entry; /* entry point set by linker script */
|
||||
char *ld_interp; /* dynamic linker */
|
||||
char *ld_soname; /* DT_SONAME */
|
||||
struct ld_script *ld_scp; /* linker script */
|
||||
struct ld_state ld_state; /* linker state */
|
||||
struct ld_strtab *ld_shstrtab; /* section name table */
|
||||
struct ld_symbol_head *ld_ext_symbols; /* -u/EXTERN symbols */
|
||||
struct ld_symbol_head *ld_var_symbols; /* ldscript var symbols */
|
||||
struct ld_symbol *ld_sym; /* internal symbol table */
|
||||
struct ld_symbol *ld_symtab_import; /* hash for import symbols */
|
||||
struct ld_symbol *ld_symtab_export; /* hash for export symbols */
|
||||
struct ld_symbol_defver *ld_defver; /* default version table */
|
||||
struct ld_symbol_table *ld_symtab; /* .symtab symbol table */
|
||||
struct ld_strtab *ld_strtab; /* .strtab string table */
|
||||
struct ld_symbol_table *ld_dynsym; /* .dynsym symbol table */
|
||||
struct ld_strtab *ld_dynstr; /* .dynstr string table */
|
||||
struct ld_symbol_head *ld_dyn_symbols; /* dynamic symbol list */
|
||||
struct ld_wildcard_match *ld_wm; /* wildcard hash table */
|
||||
struct ld_input_section *ld_dynbss; /* .dynbss section */
|
||||
struct ld_input_section *ld_got; /* .got section */
|
||||
struct ld_ehframe_cie_head *ld_cie; /* ehframe CIE list */
|
||||
struct ld_ehframe_fde_head *ld_fde; /* ehframe FDE list */
|
||||
struct ld_section_group *ld_sg; /* included section groups */
|
||||
unsigned char ld_common_alloc; /* always alloc space for common sym */
|
||||
unsigned char ld_common_no_alloc; /* never alloc space for common sym */
|
||||
unsigned char ld_emit_reloc; /* emit relocations */
|
||||
unsigned char ld_gen_gnustack; /* generate PT_GNUSTACK */
|
||||
unsigned char ld_print_linkmap; /* print link map */
|
||||
unsigned char ld_stack_exec; /* stack executable */
|
||||
unsigned char ld_stack_exec_set; /* stack executable override */
|
||||
unsigned char ld_exec; /* output normal executable */
|
||||
unsigned char ld_pie; /* position-independent executable */
|
||||
unsigned char ld_dso; /* output shared library */
|
||||
unsigned char ld_reloc; /* output relocatable object */
|
||||
unsigned char ld_dynamic_link; /* perform dynamic linking */
|
||||
unsigned char ld_print_version; /* linker version printed */
|
||||
unsigned char ld_gc; /* perform garbage collection */
|
||||
unsigned char ld_gc_print; /* print removed sections */
|
||||
unsigned char ld_ehframe_hdr; /* create .eh_frame_hdr section */
|
||||
STAILQ_HEAD(ld_input_head, ld_input) ld_lilist; /* input object list */
|
||||
TAILQ_HEAD(ld_file_head, ld_file) ld_lflist; /* input file list */
|
||||
};
|
||||
|
||||
void ld_err(struct ld *, const char *, ...);
|
||||
void ld_fatal(struct ld *, const char *, ...);
|
||||
void ld_fatal_std(struct ld *, const char *, ...);
|
||||
void ld_warn(struct ld *, const char *, ...);
|
||||
void ld_info(struct ld *, const char *, ...);
|
209
ld/ld_arch.c
Normal file
209
ld/ld_arch.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*-
|
||||
* Copyright (c) 2011,2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "i386.h"
|
||||
#include "amd64.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_arch.c 2515 2012-06-06 23:05:00Z kaiwang27 $");
|
||||
|
||||
#define LD_DEFAULT_ARCH "amd64"
|
||||
|
||||
static struct ld_arch *_get_arch_from_target(struct ld *ld, char *target);
|
||||
|
||||
void
|
||||
ld_arch_init(struct ld *ld)
|
||||
{
|
||||
char *end;
|
||||
char arch[MAX_ARCH_NAME_LEN + 1], target[MAX_TARGET_NAME_LEN + 1];
|
||||
size_t len;
|
||||
|
||||
/*
|
||||
* Register supported architectures.
|
||||
*/
|
||||
|
||||
i386_register(ld);
|
||||
amd64_register(ld);
|
||||
|
||||
/*
|
||||
* Find out default arch for output object.
|
||||
*/
|
||||
|
||||
if ((end = strrchr(ld->ld_progname, '-')) != NULL &&
|
||||
end != ld->ld_progname) {
|
||||
len = end - ld->ld_progname + 1;
|
||||
if (len > MAX_TARGET_NAME_LEN)
|
||||
return;
|
||||
strncpy(target, ld->ld_progname, len);
|
||||
target[len] = '\0';
|
||||
ld->ld_arch = _get_arch_from_target(ld, target);
|
||||
}
|
||||
|
||||
if (ld->ld_arch == NULL) {
|
||||
snprintf(arch, sizeof(arch), "%s", LD_DEFAULT_ARCH);
|
||||
ld->ld_arch = ld_arch_find(ld, arch);
|
||||
if (ld->ld_arch == NULL)
|
||||
ld_fatal(ld, "Internal: could not determine output"
|
||||
" object architecture");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_arch_set(struct ld *ld, char *arch)
|
||||
{
|
||||
|
||||
ld->ld_arch = ld_arch_find(ld, arch);
|
||||
if (ld->ld_arch == NULL)
|
||||
ld_fatal(ld, "arch '%s' is not supported", arch);
|
||||
}
|
||||
|
||||
void
|
||||
ld_arch_set_from_target(struct ld *ld)
|
||||
{
|
||||
|
||||
if (ld->ld_otgt != NULL) {
|
||||
ld->ld_arch = _get_arch_from_target(ld, ld->ld_otgt_name);
|
||||
if (ld->ld_arch == NULL)
|
||||
ld_fatal(ld, "target '%s' is not supported",
|
||||
ld->ld_otgt_name);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ld_arch_equal(struct ld_arch *a1, struct ld_arch *a2)
|
||||
{
|
||||
|
||||
assert(a1 != NULL && a2 != NULL);
|
||||
|
||||
if (a1 == a2)
|
||||
return (1);
|
||||
|
||||
if (a1->alias == a2 || a2->alias == a1)
|
||||
return (1);
|
||||
|
||||
if (a1->alias != NULL && a1->alias == a2->alias)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ld_arch_verify(struct ld *ld, const char *name, int mach)
|
||||
{
|
||||
struct ld_arch *la;
|
||||
struct ld_state *ls;
|
||||
|
||||
assert(ld->ld_arch != NULL);
|
||||
ls = &ld->ld_state;
|
||||
|
||||
if ((la = ld_arch_guess_arch_name(ld, mach)) == NULL)
|
||||
ld_fatal(ld, "%s: ELF object architecture %#x not supported",
|
||||
name, mach);
|
||||
|
||||
if (!ld_arch_equal(la, ld->ld_arch)) {
|
||||
ls->ls_arch_conflict = 1;
|
||||
if (ls->ls_rerun || !ls->ls_first_elf_object)
|
||||
ld_fatal(ld, "%s: ELF object architecture `%s' "
|
||||
"conflicts with output object architecture `%s'",
|
||||
name, la->name, ld->ld_arch->name);
|
||||
ld->ld_arch = la;
|
||||
}
|
||||
|
||||
ls->ls_first_elf_object = 0;
|
||||
}
|
||||
|
||||
struct ld_arch *
|
||||
ld_arch_guess_arch_name(struct ld *ld, int mach)
|
||||
{
|
||||
char arch[MAX_ARCH_NAME_LEN + 1];
|
||||
|
||||
/* TODO: we should also consider elf class and endianess. */
|
||||
|
||||
switch (mach) {
|
||||
case EM_386:
|
||||
snprintf(arch, sizeof(arch), "%s", "i386");
|
||||
break;
|
||||
case EM_ARM:
|
||||
snprintf(arch, sizeof(arch), "%s", "arm");
|
||||
break;
|
||||
case EM_MIPS:
|
||||
case EM_MIPS_RS3_LE:
|
||||
snprintf(arch, sizeof(arch), "%s", "mips");
|
||||
break;
|
||||
case EM_PPC:
|
||||
case EM_PPC64:
|
||||
snprintf(arch, sizeof(arch), "%s", "ppc");
|
||||
break;
|
||||
case EM_SPARC:
|
||||
case EM_SPARCV9:
|
||||
snprintf(arch, sizeof(arch), "%s", "sparc");
|
||||
break;
|
||||
case EM_X86_64:
|
||||
snprintf(arch, sizeof(arch), "%s", "amd64");
|
||||
break;
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (ld_arch_find(ld, arch));
|
||||
}
|
||||
|
||||
static struct ld_arch *
|
||||
_get_arch_from_target(struct ld *ld, char *target)
|
||||
{
|
||||
struct ld_arch *la;
|
||||
char *begin, *end, name[MAX_TARGET_NAME_LEN + 1];
|
||||
|
||||
if ((begin = strchr(target, '-')) == NULL) {
|
||||
la = ld_arch_find(ld, target);
|
||||
return (la);
|
||||
}
|
||||
la = ld_arch_find(ld, begin + 1);
|
||||
if (la != NULL)
|
||||
return (la);
|
||||
|
||||
strncpy(name, begin + 1, sizeof(name) - 1);
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
while ((end = strrchr(name, '-')) != NULL) {
|
||||
*end = '\0';
|
||||
la = ld_arch_find(ld, name);
|
||||
if (la != NULL)
|
||||
return (la);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct ld_arch *
|
||||
ld_arch_find(struct ld *ld, char *arch)
|
||||
{
|
||||
struct ld_arch *la;
|
||||
|
||||
HASH_FIND_STR(ld->ld_arch_list, arch, la);
|
||||
|
||||
return (la);
|
||||
}
|
65
ld/ld_arch.h
Normal file
65
ld/ld_arch.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*-
|
||||
* Copyright (c) 2011,2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_arch.h 2913 2013-02-16 07:15:24Z kaiwang27 $
|
||||
*/
|
||||
|
||||
#define MAX_ARCH_NAME_LEN 64
|
||||
#define MAX_TARGET_NAME_LEN 128
|
||||
|
||||
struct ld_input_section;
|
||||
struct ld_reloc_entry;
|
||||
|
||||
struct ld_arch {
|
||||
char name[MAX_ARCH_NAME_LEN + 1];
|
||||
char *script;
|
||||
const char *interp;
|
||||
uint64_t (*get_max_page_size)(struct ld *);
|
||||
uint64_t (*get_common_page_size)(struct ld *);
|
||||
void (*scan_reloc)(struct ld *, struct ld_input_section *,
|
||||
struct ld_reloc_entry *);
|
||||
void (*adjust_reloc)(struct ld *, struct ld_input_section *,
|
||||
struct ld_reloc_entry *, struct ld_symbol *, uint8_t *);
|
||||
void (*process_reloc)(struct ld *, struct ld_input_section *,
|
||||
struct ld_reloc_entry *, struct ld_symbol *, uint8_t *);
|
||||
void (*finalize_reloc)(struct ld *, struct ld_input_section *,
|
||||
struct ld_reloc_entry *);
|
||||
void (*finalize_got_and_plt)(struct ld *);
|
||||
int (*is_absolute_reloc)(uint64_t);
|
||||
int (*is_relative_reloc)(uint64_t);
|
||||
unsigned char reloc_is_64bit;
|
||||
unsigned char reloc_is_rela;
|
||||
size_t reloc_entsize;
|
||||
UT_hash_handle hh;
|
||||
struct ld_arch *alias;
|
||||
};
|
||||
|
||||
void ld_arch_init(struct ld *);
|
||||
int ld_arch_equal(struct ld_arch *, struct ld_arch *);
|
||||
struct ld_arch *ld_arch_find(struct ld *, char *);
|
||||
struct ld_arch *ld_arch_guess_arch_name(struct ld *, int);
|
||||
void ld_arch_set(struct ld *, char *);
|
||||
void ld_arch_set_from_target(struct ld *);
|
||||
void ld_arch_verify(struct ld *, const char *, int);
|
610
ld/ld_dynamic.c
Normal file
610
ld/ld_dynamic.c
Normal file
|
@ -0,0 +1,610 @@
|
|||
/*-
|
||||
* Copyright (c) 2012,2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "ld_dynamic.h"
|
||||
#include "ld_file.h"
|
||||
#include "ld_hash.h"
|
||||
#include "ld_input.h"
|
||||
#include "ld_layout.h"
|
||||
#include "ld_output.h"
|
||||
#include "ld_path.h"
|
||||
#include "ld_symbols.h"
|
||||
#include "ld_symver.h"
|
||||
#include "ld_strtab.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_dynamic.c 2965 2013-09-10 02:46:29Z kaiwang27 $");
|
||||
|
||||
static void _check_dso_needed(struct ld *ld, struct ld_output *lo);
|
||||
static void _create_dynamic(struct ld *ld, struct ld_output *lo);
|
||||
static void _create_interp(struct ld *ld, struct ld_output *lo);
|
||||
static void _create_dynsym_and_dynstr_section(struct ld *ld,
|
||||
struct ld_output *lo);
|
||||
static void _finalize_dynamic(struct ld *ld, struct ld_output *lo);
|
||||
|
||||
void
|
||||
ld_dynamic_create(struct ld *ld)
|
||||
{
|
||||
struct ld_output *lo;
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
/* Check how many DSOs is needed for output object. */
|
||||
_check_dso_needed(ld, lo);
|
||||
|
||||
/* Link statically if we don't use DSOs? */
|
||||
if (lo->lo_dso_needed == 0)
|
||||
return;
|
||||
|
||||
ld->ld_dynamic_link = 1;
|
||||
|
||||
/* Create .interp section. */
|
||||
if (!ld->ld_dso)
|
||||
_create_interp(ld, lo);
|
||||
|
||||
/* Create .dynamic section. */
|
||||
_create_dynamic(ld, lo);
|
||||
|
||||
/* Create .dynsym and .dynstr sections. */
|
||||
_create_dynsym_and_dynstr_section(ld, lo);
|
||||
|
||||
/* Create .hash section. */
|
||||
ld_hash_create_svr4_hash_section(ld);
|
||||
|
||||
/*
|
||||
* Create .gnu.version_d section if the linker creats a shared
|
||||
* library and version script is provided.
|
||||
*/
|
||||
lo->lo_version_index = 2;
|
||||
if (ld->ld_dso)
|
||||
ld_symver_create_verdef_section(ld);
|
||||
|
||||
/* Create .gnu.version_r section. */
|
||||
ld_symver_create_verneed_section(ld);
|
||||
|
||||
/* Create .gnu.version section. */
|
||||
ld_symver_create_versym_section(ld);
|
||||
}
|
||||
|
||||
void
|
||||
ld_dynamic_finalize(struct ld *ld)
|
||||
{
|
||||
struct ld_output *lo;
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
if (lo->lo_dso_needed == 0)
|
||||
return;
|
||||
|
||||
/* Finalize .dynamic section */
|
||||
_finalize_dynamic(ld, lo);
|
||||
}
|
||||
|
||||
void
|
||||
ld_dynamic_load_dso_dynamic(struct ld *ld, struct ld_input *li, Elf *e,
|
||||
Elf_Scn *scn, size_t strndx)
|
||||
{
|
||||
GElf_Shdr shdr;
|
||||
GElf_Dyn dyn;
|
||||
Elf_Data *d;
|
||||
int elferr, i, len;
|
||||
const char *name;
|
||||
|
||||
if (strndx == SHN_UNDEF)
|
||||
return;
|
||||
|
||||
if (gelf_getshdr(scn, &shdr) != &shdr) {
|
||||
ld_warn(ld, "%s: gelf_getshdr failed: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
(void) elf_errno();
|
||||
if ((d = elf_getdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
ld_warn(ld, "%s: elf_getdata failed: %s", li->li_name,
|
||||
elf_errmsg(elferr));
|
||||
return;
|
||||
}
|
||||
|
||||
len = d->d_size / shdr.sh_entsize;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (gelf_getdyn(d, i, &dyn) != &dyn) {
|
||||
ld_warn(ld, "%s: gelf_getdyn failed: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
switch (dyn.d_tag) {
|
||||
case DT_SONAME:
|
||||
name = elf_strptr(e, strndx, dyn.d_un.d_ptr);
|
||||
if (name != NULL &&
|
||||
(li->li_soname = strdup(name)) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
break;
|
||||
case DT_NEEDED:
|
||||
name = elf_strptr(e, strndx, dyn.d_un.d_ptr);
|
||||
if (name != NULL)
|
||||
ld_path_search_dso_needed(ld, li->li_file,
|
||||
name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_dynamic_reserve_dynbss_entry(struct ld *ld, struct ld_symbol *lsb)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_input_section *dynbss, *is;
|
||||
uint64_t a;
|
||||
|
||||
/* Create .dynbss section if it doesn't yet exist. */
|
||||
dynbss = ld_input_find_internal_section(ld, ".dynbss");
|
||||
if (dynbss == NULL) {
|
||||
dynbss = ld_input_add_internal_section(ld, ".dynbss");
|
||||
dynbss->is_type = SHT_NOBITS;
|
||||
}
|
||||
|
||||
li = lsb->lsb_input;
|
||||
assert(li != NULL && li->li_type == LIT_DSO);
|
||||
|
||||
/*
|
||||
* TODO: we don't have to create copy relocation
|
||||
* for every import object. Some import objects
|
||||
* are read-only, in that case we can create other
|
||||
* dynamic relocations for them.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If the section to which the symbols belong has a larger
|
||||
* alignment requirement, we increase .dynbss section alignment
|
||||
* accordingly. XXX What if it is a DSO common symbol?
|
||||
*/
|
||||
is = NULL;
|
||||
if (lsb->lsb_shndx != SHN_COMMON) {
|
||||
assert(lsb->lsb_shndx < li->li_shnum - 1);
|
||||
is = &li->li_is[lsb->lsb_shndx];
|
||||
if (is->is_align > dynbss->is_align)
|
||||
dynbss->is_align = is->is_align;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the alignment for this object.
|
||||
*/
|
||||
if (is != NULL) {
|
||||
for (a = is->is_align; a > 1; a >>= 1) {
|
||||
if ((lsb->lsb_value - is->is_off) % a == 0)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
a = 1;
|
||||
|
||||
if (a > 1)
|
||||
dynbss->is_size = roundup(dynbss->is_size, a);
|
||||
|
||||
lsb->lsb_value = dynbss->is_size;
|
||||
lsb->lsb_copy_reloc = 1;
|
||||
lsb->lsb_input = dynbss->is_input;
|
||||
lsb->lsb_shndx = dynbss->is_index;
|
||||
lsb->lsb_is = dynbss;
|
||||
|
||||
dynbss->is_size += lsb->lsb_size;
|
||||
}
|
||||
|
||||
static void
|
||||
_create_interp(struct ld *ld, struct ld_output *lo)
|
||||
{
|
||||
struct ld_output_section *os;
|
||||
struct ld_output_data_buffer *odb;
|
||||
const char *interp;
|
||||
char interp_name[] = ".interp";
|
||||
|
||||
HASH_FIND_STR(lo->lo_ostbl, interp_name, os);
|
||||
if (os == NULL)
|
||||
os = ld_layout_insert_output_section(ld, interp_name,
|
||||
SHF_ALLOC);
|
||||
os->os_type = SHT_PROGBITS;
|
||||
os->os_align = 1;
|
||||
os->os_entsize = 0;
|
||||
os->os_flags = SHF_ALLOC;
|
||||
|
||||
lo->lo_interp = os;
|
||||
|
||||
if (ld->ld_interp != NULL)
|
||||
interp = ld->ld_interp;
|
||||
else
|
||||
interp = ld->ld_arch->interp;
|
||||
assert(interp != NULL);
|
||||
|
||||
if ((odb = calloc(1, sizeof(*odb))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
odb->odb_size = strlen(interp) + 1;
|
||||
odb->odb_align = 1;
|
||||
odb->odb_type = ELF_T_BYTE;
|
||||
|
||||
if ((odb->odb_buf = calloc(odb->odb_size, 1)) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
strncpy(odb->odb_buf, interp, strlen(interp));
|
||||
odb->odb_buf[strlen(interp)] = '\0';
|
||||
|
||||
(void) ld_output_create_section_element(ld, os, OET_DATA_BUFFER, odb,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
_create_dynamic(struct ld *ld, struct ld_output *lo)
|
||||
{
|
||||
struct ld_output_section *os, *_os;
|
||||
struct ld_output_data_buffer *odb;
|
||||
char dynamic_name[] = ".dynamic";
|
||||
char init_name[] = ".init";
|
||||
char fini_name[] = ".fini";
|
||||
char *rpath;
|
||||
int entries;
|
||||
|
||||
HASH_FIND_STR(lo->lo_ostbl, dynamic_name, os);
|
||||
if (os == NULL)
|
||||
os = ld_layout_insert_output_section(ld, dynamic_name,
|
||||
SHF_ALLOC | SHF_WRITE);
|
||||
os->os_type = SHT_DYNAMIC;
|
||||
os->os_flags = SHF_ALLOC | SHF_WRITE;
|
||||
if (lo->lo_ec == ELFCLASS32) {
|
||||
os->os_entsize = 8;
|
||||
os->os_align = 4;
|
||||
} else {
|
||||
os->os_entsize = 16;
|
||||
os->os_align = 8;
|
||||
}
|
||||
|
||||
lo->lo_dynamic = os;
|
||||
|
||||
/* .dynamic section should link to .dynstr section. */
|
||||
if ((os->os_link = strdup(".dynstr")) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
|
||||
/* DT_NEEDED */
|
||||
entries = lo->lo_dso_needed;
|
||||
|
||||
/* DT_SONAME. */
|
||||
if (ld->ld_soname != NULL) {
|
||||
lo->lo_soname_nameindex = ld_strtab_insert_no_suffix(ld,
|
||||
ld->ld_dynstr, ld->ld_soname);
|
||||
entries++;
|
||||
}
|
||||
|
||||
/* DT_INIT */
|
||||
HASH_FIND_STR(lo->lo_ostbl, init_name, _os);
|
||||
if (_os != NULL && !_os->os_empty) {
|
||||
lo->lo_init = _os;
|
||||
entries++;
|
||||
}
|
||||
|
||||
/* DT_FINI */
|
||||
HASH_FIND_STR(lo->lo_ostbl, fini_name, _os);
|
||||
if (_os != NULL && !_os->os_empty) {
|
||||
lo->lo_fini = _os;
|
||||
entries++;
|
||||
}
|
||||
|
||||
/* DT_HASH, DT_STRTAB, DT_SYMTAB, DT_STRSZ and DT_SYMENT */
|
||||
if (ld->ld_dynsym)
|
||||
entries += 5;
|
||||
|
||||
/* DT_RPATH. */
|
||||
if (!STAILQ_EMPTY(&ld->ld_state.ls_rplist)) {
|
||||
rpath = ld_path_join_rpath(ld);
|
||||
lo->lo_rpath_nameindex = ld_strtab_insert_no_suffix(ld,
|
||||
ld->ld_dynstr, rpath);
|
||||
entries++;
|
||||
}
|
||||
|
||||
/*
|
||||
* DT_DEBUG. dynamic linker changes this at runtime, gdb uses
|
||||
* it to find all the loaded DSOs. (thus .dynamic has to be
|
||||
* writable)
|
||||
*/
|
||||
if (!ld->ld_dso)
|
||||
entries++;
|
||||
|
||||
/* DT_PLTGOT, DT_PLTRELSZ, DT_PLTREL and DT_JMPREL. */
|
||||
entries += 4;
|
||||
|
||||
/* DT_REL/DT_RELA, DT_RELSZ/DT_RELASZ and DT_RELENT/DT_RELAENT */
|
||||
entries += 3;
|
||||
|
||||
/*
|
||||
* DT_VERNEED, DT_VERNEEDNUM, DT_VERDEF, DT_VERDEFNUM and DT_VERSYM.
|
||||
*/
|
||||
entries += 5;
|
||||
|
||||
/* DT_RELCOUNT/DT_RELACOUNT. */
|
||||
if (ld->ld_state.ls_relative_reloc > 0)
|
||||
entries++;
|
||||
|
||||
/* DT_NULL. TODO: Reserve multiple DT_NULL entries for DT_RPATH? */
|
||||
entries++;
|
||||
|
||||
/*
|
||||
* Reserve space for .dynamic section, based on number of entries.
|
||||
*/
|
||||
if ((odb = calloc(1, sizeof(*odb))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
odb->odb_size = entries * os->os_entsize;
|
||||
if ((odb->odb_buf = malloc(odb->odb_size)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
odb->odb_align = os->os_align;
|
||||
odb->odb_type = ELF_T_DYN;
|
||||
|
||||
(void) ld_output_create_section_element(ld, os, OET_DATA_BUFFER, odb,
|
||||
NULL);
|
||||
|
||||
lo->lo_dynamic_odb = odb;
|
||||
|
||||
/* Create _DYNAMIC symobl. */
|
||||
ld_symbols_add_internal(ld, "_DYNAMIC", 0, 0, SHN_ABS, STB_LOCAL,
|
||||
STT_OBJECT, STV_HIDDEN, NULL, os);
|
||||
}
|
||||
|
||||
#define DT_ENTRY_VAL(tag,val) \
|
||||
do { \
|
||||
if (lo->lo_ec == ELFCLASS32) { \
|
||||
assert(dt32 < end32); \
|
||||
dt32->d_tag = (int32_t) (tag); \
|
||||
dt32->d_un.d_val = (uint32_t) (val); \
|
||||
dt32++; \
|
||||
} else { \
|
||||
assert(dt64 < end64); \
|
||||
dt64->d_tag = (tag); \
|
||||
dt64->d_un.d_val = (val); \
|
||||
dt64++; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define DT_ENTRY_PTR(tag,ptr) \
|
||||
do { \
|
||||
if (lo->lo_ec == ELFCLASS32) { \
|
||||
assert(dt32 < end32); \
|
||||
dt32->d_tag = (int32_t) (tag); \
|
||||
dt32->d_un.d_ptr = (uint32_t) (ptr); \
|
||||
dt32++; \
|
||||
} else { \
|
||||
assert(dt64 < end64); \
|
||||
dt64->d_tag = (tag); \
|
||||
dt64->d_un.d_ptr = (ptr); \
|
||||
dt64++; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define DT_ENTRY_NULL \
|
||||
do { \
|
||||
if (lo->lo_ec == ELFCLASS32) { \
|
||||
assert(dt32 < end32); \
|
||||
while (dt32 < end32) \
|
||||
DT_ENTRY_VAL(DT_NULL, 0); \
|
||||
assert(dt32 == end32); \
|
||||
} else { \
|
||||
assert(dt64 < end64); \
|
||||
while (dt64 < end64) \
|
||||
DT_ENTRY_VAL(DT_NULL, 0); \
|
||||
assert(dt64 == end64); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
static void
|
||||
_finalize_dynamic(struct ld *ld, struct ld_output *lo)
|
||||
{
|
||||
struct ld_output_data_buffer *odb;
|
||||
Elf32_Dyn *dt32, *end32;
|
||||
Elf64_Dyn *dt64, *end64;
|
||||
int *p;
|
||||
|
||||
odb = lo->lo_dynamic_odb;
|
||||
assert(odb != NULL);
|
||||
|
||||
dt32 = (Elf32_Dyn *) (uintptr_t) odb->odb_buf;
|
||||
dt64 = (Elf64_Dyn *) (uintptr_t) odb->odb_buf;
|
||||
end32 = (Elf32_Dyn *) (uintptr_t) (odb->odb_buf + odb->odb_size);
|
||||
end64 = (Elf64_Dyn *) (uintptr_t) (odb->odb_buf + odb->odb_size);
|
||||
|
||||
/* DT_NEEDED. */
|
||||
for (p = (int *) (uintptr_t) utarray_front(lo->lo_dso_nameindex);
|
||||
p != NULL;
|
||||
p = (int *) (uintptr_t) utarray_next(lo->lo_dso_nameindex, p))
|
||||
DT_ENTRY_VAL(DT_NEEDED, *p);
|
||||
|
||||
/* DT_SONAME. */
|
||||
if (ld->ld_soname != NULL)
|
||||
DT_ENTRY_VAL(DT_SONAME, lo->lo_soname_nameindex);
|
||||
|
||||
/* DT_INIT and DT_FINI */
|
||||
if (lo->lo_init != NULL)
|
||||
DT_ENTRY_PTR(DT_INIT, lo->lo_init->os_addr);
|
||||
if (lo->lo_fini != NULL)
|
||||
DT_ENTRY_PTR(DT_FINI, lo->lo_fini->os_addr);
|
||||
|
||||
/* DT_HASH */
|
||||
if (lo->lo_hash != NULL)
|
||||
DT_ENTRY_PTR(DT_HASH, lo->lo_hash->os_addr);
|
||||
|
||||
/* DT_HASH, DT_STRTAB, DT_SYMTAB, DT_STRSZ and DT_SYMENT */
|
||||
if (lo->lo_dynsym != NULL && lo->lo_dynstr != NULL) {
|
||||
DT_ENTRY_PTR(DT_STRTAB, lo->lo_dynstr->os_addr);
|
||||
DT_ENTRY_PTR(DT_SYMTAB, lo->lo_dynsym->os_addr);
|
||||
DT_ENTRY_VAL(DT_STRSZ, ld_strtab_getsize(ld->ld_dynstr));
|
||||
DT_ENTRY_VAL(DT_SYMENT,
|
||||
lo->lo_ec == ELFCLASS32 ? sizeof(Elf32_Sym) :
|
||||
sizeof(Elf64_Sym));
|
||||
}
|
||||
|
||||
/* DT_RPATH */
|
||||
if (!STAILQ_EMPTY(&ld->ld_state.ls_rplist))
|
||||
DT_ENTRY_VAL(DT_RPATH, lo->lo_rpath_nameindex);
|
||||
|
||||
/* DT_DEBUG */
|
||||
if (!ld->ld_dso)
|
||||
DT_ENTRY_VAL(DT_DEBUG, 0);
|
||||
|
||||
/* DT_PLTGOT, DT_PLTRELSZ, DT_PLTREL and DT_JMPREL. */
|
||||
if (lo->lo_gotplt != NULL)
|
||||
DT_ENTRY_PTR(DT_PLTGOT, lo->lo_gotplt->os_addr);
|
||||
if (lo->lo_rel_plt != NULL) {
|
||||
DT_ENTRY_VAL(DT_PLTRELSZ, lo->lo_rel_plt->os_size);
|
||||
DT_ENTRY_VAL(DT_PLTREL,
|
||||
ld->ld_arch->reloc_is_rela ? DT_RELA : DT_REL);
|
||||
DT_ENTRY_PTR(DT_JMPREL, lo->lo_rel_plt->os_addr);
|
||||
}
|
||||
|
||||
/* DT_REL/DT_RELA, DT_RELSZ/DT_RELASZ and DT_RELENT/DT_RELAENT */
|
||||
if (lo->lo_rel_dyn != NULL) {
|
||||
if (!ld->ld_arch->reloc_is_rela) {
|
||||
DT_ENTRY_PTR(DT_REL, lo->lo_rel_dyn->os_addr);
|
||||
DT_ENTRY_VAL(DT_RELSZ, lo->lo_rel_dyn->os_size);
|
||||
DT_ENTRY_VAL(DT_RELENT, ld->ld_arch->reloc_entsize);
|
||||
} else {
|
||||
DT_ENTRY_PTR(DT_RELA, lo->lo_rel_dyn->os_addr);
|
||||
DT_ENTRY_VAL(DT_RELASZ, lo->lo_rel_dyn->os_size);
|
||||
DT_ENTRY_VAL(DT_RELAENT, ld->ld_arch->reloc_entsize);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DT_VERNEED, DT_VERNEEDNUM, DT_VERDEF, DT_VERDEFNUM and
|
||||
* DT_VERSYM.
|
||||
*/
|
||||
if (lo->lo_verdef != NULL) {
|
||||
DT_ENTRY_PTR(DT_VERDEF, lo->lo_verdef->os_addr);
|
||||
DT_ENTRY_VAL(DT_VERDEFNUM, lo->lo_verdef_num);
|
||||
}
|
||||
if (lo->lo_verneed != NULL) {
|
||||
DT_ENTRY_PTR(DT_VERNEED, lo->lo_verneed->os_addr);
|
||||
DT_ENTRY_VAL(DT_VERNEEDNUM, lo->lo_verneed_num);
|
||||
}
|
||||
if (lo->lo_versym != NULL)
|
||||
DT_ENTRY_PTR(DT_VERSYM, lo->lo_versym->os_addr);
|
||||
|
||||
/* DT_RELCOUNT/DT_RELACOUNT. */
|
||||
if (ld->ld_state.ls_relative_reloc > 0)
|
||||
DT_ENTRY_VAL(ld->ld_arch->reloc_is_rela ? DT_RELACOUNT :
|
||||
DT_RELCOUNT, ld->ld_state.ls_relative_reloc);
|
||||
|
||||
/* Fill in the space left with DT_NULL entries */
|
||||
DT_ENTRY_NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_create_dynsym_and_dynstr_section(struct ld *ld, struct ld_output *lo)
|
||||
{
|
||||
struct ld_output_section *os;
|
||||
char dynsym_name[] = ".dynsym";
|
||||
char dynstr_name[] = ".dynstr";
|
||||
|
||||
/*
|
||||
* Create .dynsym section.
|
||||
*/
|
||||
|
||||
HASH_FIND_STR(lo->lo_ostbl, dynsym_name, os);
|
||||
if (os == NULL)
|
||||
os = ld_layout_insert_output_section(ld, dynsym_name,
|
||||
SHF_ALLOC);
|
||||
os->os_type = SHT_DYNSYM;
|
||||
os->os_flags = SHF_ALLOC;
|
||||
if (lo->lo_ec == ELFCLASS32) {
|
||||
os->os_entsize = sizeof(Elf32_Sym);
|
||||
os->os_align = 4;
|
||||
} else {
|
||||
os->os_entsize = sizeof(Elf64_Sym);
|
||||
os->os_align = 8;
|
||||
}
|
||||
lo->lo_dynsym = os;
|
||||
|
||||
(void) ld_output_create_section_element(ld, os, OET_SYMTAB,
|
||||
ld->ld_dynsym, NULL);
|
||||
|
||||
/*
|
||||
* Create .dynstr section.
|
||||
*/
|
||||
|
||||
HASH_FIND_STR(lo->lo_ostbl, dynstr_name, os);
|
||||
if (os == NULL)
|
||||
os = ld_layout_insert_output_section(ld, dynstr_name,
|
||||
SHF_ALLOC);
|
||||
os->os_type = SHT_STRTAB;
|
||||
os->os_flags = SHF_ALLOC;
|
||||
os->os_entsize = 0;
|
||||
os->os_align = 1;
|
||||
lo->lo_dynstr = os;
|
||||
|
||||
(void) ld_output_create_section_element(ld, os, OET_STRTAB,
|
||||
ld->ld_dynstr, NULL);
|
||||
|
||||
if ((lo->lo_dynsym->os_link = strdup(".dynstr")) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
}
|
||||
|
||||
static void
|
||||
_check_dso_needed(struct ld *ld, struct ld_output *lo)
|
||||
{
|
||||
struct ld_input *li;
|
||||
char *bn;
|
||||
int ndx;
|
||||
|
||||
lo->lo_dso_needed = 0;
|
||||
|
||||
STAILQ_FOREACH(li, &ld->ld_lilist, li_next) {
|
||||
if (li->li_type != LIT_DSO)
|
||||
continue;
|
||||
|
||||
if (li->li_dso_refcnt > 0 || !li->li_file->lf_as_needed) {
|
||||
lo->lo_dso_needed++;
|
||||
|
||||
if (ld->ld_dynstr == NULL)
|
||||
ld->ld_dynstr = ld_strtab_alloc(ld, 0);
|
||||
|
||||
/* Insert DSO name to the .dynstr string table. */
|
||||
if (li->li_soname != NULL)
|
||||
bn = li->li_soname;
|
||||
else {
|
||||
if ((bn = strrchr(li->li_name, '/')) == NULL)
|
||||
bn = li->li_name;
|
||||
else
|
||||
bn++;
|
||||
}
|
||||
ndx = ld_strtab_insert_no_suffix(ld, ld->ld_dynstr,
|
||||
bn);
|
||||
|
||||
/* Save the generated name index for later use. */
|
||||
if (lo->lo_dso_nameindex == NULL)
|
||||
utarray_new(lo->lo_dso_nameindex, &ut_int_icd);
|
||||
utarray_push_back(lo->lo_dso_nameindex, &ndx);
|
||||
}
|
||||
}
|
||||
}
|
34
ld/ld_dynamic.h
Normal file
34
ld/ld_dynamic.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_dynamic.h 2784 2012-12-15 19:19:48Z kaiwang27 $
|
||||
*/
|
||||
|
||||
void ld_dynamic_create(struct ld *);
|
||||
void ld_dynamic_finalize(struct ld *);
|
||||
void ld_dynamic_load_dso_dynamic(struct ld *, struct ld_input *, Elf *,
|
||||
Elf_Scn *, size_t);
|
||||
void ld_dynamic_create_copy_reloc(struct ld *);
|
||||
void ld_dynamic_reserve_dynbss_entry(struct ld *, struct ld_symbol *);
|
770
ld/ld_ehframe.c
Normal file
770
ld/ld_ehframe.c
Normal file
|
@ -0,0 +1,770 @@
|
|||
/*-
|
||||
* Copyright (c) 2009-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "ld_ehframe.h"
|
||||
#include "ld_input.h"
|
||||
#include "ld_output.h"
|
||||
#include "ld_reloc.h"
|
||||
#include "ld_utils.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_ehframe.c 2964 2013-09-10 02:46:06Z kaiwang27 $");
|
||||
|
||||
struct ld_ehframe_cie {
|
||||
uint64_t cie_off; /* offset in section */
|
||||
uint64_t cie_off_orig; /* orignial offset (before optimze) */
|
||||
uint64_t cie_size; /* CIE size (include length field) */
|
||||
uint8_t *cie_content; /* CIE content */
|
||||
uint8_t cie_fde_encode; /* FDE PC start/range encode. */
|
||||
struct ld_ehframe_cie *cie_dup; /* duplicate entry */
|
||||
STAILQ_ENTRY(ld_ehframe_cie) cie_next;
|
||||
};
|
||||
|
||||
STAILQ_HEAD(ld_ehframe_cie_head, ld_ehframe_cie);
|
||||
|
||||
struct ld_ehframe_fde {
|
||||
struct ld_ehframe_cie *fde_cie; /* associated CIE */
|
||||
uint64_t fde_off; /* offset in section */
|
||||
uint64_t fde_off_pcbegin; /* section offset of "PC Begin" field */
|
||||
int32_t fde_pcrel; /* relative offset to "PC Begin" */
|
||||
int32_t fde_datarel; /* relative offset to FDE entry */
|
||||
STAILQ_ENTRY(ld_ehframe_fde) fde_next;
|
||||
};
|
||||
|
||||
STAILQ_HEAD(ld_ehframe_fde_head, ld_ehframe_fde);
|
||||
|
||||
static int64_t _decode_sleb128(uint8_t **dp);
|
||||
static uint64_t _decode_uleb128(uint8_t **dp);
|
||||
static void _process_ehframe_section(struct ld *ld, struct ld_output *lo,
|
||||
struct ld_input_section *is);
|
||||
static int _read_encoded(struct ld *ld, struct ld_output *lo, uint64_t *val,
|
||||
uint8_t *data, uint8_t encode, uint64_t pc);
|
||||
static int _cmp_fde(struct ld_ehframe_fde *a, struct ld_ehframe_fde *b);
|
||||
|
||||
void
|
||||
ld_ehframe_adjust(struct ld *ld, struct ld_input_section *is)
|
||||
{
|
||||
struct ld_output *lo;
|
||||
uint8_t *p, *d, *end, *s;
|
||||
uint64_t length, length_size, remain, adjust;
|
||||
uint32_t cie_id;
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
/*
|
||||
* If the .eh_frame section is unchanged, we don't need to
|
||||
* do much.
|
||||
*/
|
||||
assert(is->is_ehframe != NULL);
|
||||
if (is->is_shrink == 0) {
|
||||
is->is_ehframe = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise the section is shrinked becase some FDE's are
|
||||
* discarded. We copy the section content to a buffer while
|
||||
* skipping those discarded FDE's.
|
||||
*/
|
||||
|
||||
if ((is->is_ibuf = malloc(is->is_size - is->is_shrink)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
d = is->is_ibuf;
|
||||
end = d + is->is_size - is->is_shrink;
|
||||
p = is->is_ehframe;
|
||||
adjust = 0;
|
||||
remain = is->is_size;
|
||||
while (remain > 0) {
|
||||
|
||||
s = p;
|
||||
|
||||
/* Read CIE/FDE length field. */
|
||||
READ_32(p, length);
|
||||
p += 4;
|
||||
if (length == 0xffffffff) {
|
||||
READ_64(p, length);
|
||||
p += 8;
|
||||
length_size = 8;
|
||||
} else
|
||||
length_size = 4;
|
||||
|
||||
/* Check for terminator */
|
||||
if (length == 0) {
|
||||
memset(d, 0, 4);
|
||||
d += 4;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read CIE ID/Pointer field. */
|
||||
READ_32(p, cie_id);
|
||||
|
||||
/* Clear adjustment if CIE is found. */
|
||||
if (cie_id == 0)
|
||||
adjust = 0;
|
||||
|
||||
/* Check for our special mark. */
|
||||
if (cie_id != 0xFFFFFFFF) {
|
||||
if (cie_id != 0) {
|
||||
/* Adjust FDE pointer. */
|
||||
assert(cie_id > adjust);
|
||||
cie_id -= adjust;
|
||||
WRITE_32(p, cie_id);
|
||||
}
|
||||
memcpy(d, s, length + length_size);
|
||||
d += length + length_size;
|
||||
} else {
|
||||
/* Discard FDE and increate adjustment. */
|
||||
adjust += length + length_size;
|
||||
}
|
||||
|
||||
/* Next entry. */
|
||||
p += length;
|
||||
remain -= length + length_size;
|
||||
}
|
||||
|
||||
is->is_size -= is->is_shrink;
|
||||
is->is_shrink = 0;
|
||||
assert(d == end);
|
||||
free(is->is_ehframe);
|
||||
is->is_ehframe = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ld_ehframe_scan(struct ld *ld)
|
||||
{
|
||||
struct ld_output *lo;
|
||||
struct ld_output_section *os;
|
||||
struct ld_output_element *oe;
|
||||
struct ld_input_section *is;
|
||||
struct ld_input_section_head *islist;
|
||||
uint64_t ehframe_off;
|
||||
char ehframe_name[] = ".eh_frame";
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
/*
|
||||
* Search for .eh_frame output section. Nothing needs to be done
|
||||
* if .eh_frame section not exist or is empty.
|
||||
*/
|
||||
HASH_FIND_STR(lo->lo_ostbl, ehframe_name, os);
|
||||
if (os == NULL || os->os_empty)
|
||||
return;
|
||||
|
||||
if ((ld->ld_cie = malloc(sizeof(*ld->ld_cie))) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
STAILQ_INIT(ld->ld_cie);
|
||||
|
||||
/*
|
||||
* Remove duplicate CIE from each input .eh_frame section.
|
||||
*/
|
||||
ehframe_off = 0;
|
||||
STAILQ_FOREACH(oe, &os->os_e, oe_next) {
|
||||
/*
|
||||
* XXX We currently do not support .eh_frame section which
|
||||
* contains elements other than OET_INPUT_SECTION_LIST.
|
||||
*/
|
||||
if (oe->oe_type != OET_INPUT_SECTION_LIST)
|
||||
continue;
|
||||
|
||||
islist = oe->oe_islist;
|
||||
STAILQ_FOREACH(is, islist, is_next) {
|
||||
/*
|
||||
* Process each input .eh_frame section and search
|
||||
* for duplicate CIE's. The input section relative
|
||||
* offset in the output section is resync'ed since
|
||||
* the input section might be shrinked.
|
||||
*/
|
||||
is->is_reloff = ehframe_off;
|
||||
_process_ehframe_section(ld, lo, is);
|
||||
ehframe_off += is->is_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate the size of .eh_frame_hdr section. */
|
||||
if (ld->ld_ehframe_hdr) {
|
||||
is = ld_input_find_internal_section(ld, ".eh_frame_hdr");
|
||||
assert(is != NULL);
|
||||
if (lo->lo_fde_num > 0)
|
||||
is->is_size += 4 + lo->lo_fde_num * 8;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_ehframe_create_hdr(struct ld *ld)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
|
||||
is = ld_input_add_internal_section(ld, ".eh_frame_hdr");
|
||||
is->is_type = SHT_PROGBITS;
|
||||
is->is_size = 8; /* initial size */
|
||||
is->is_align = 4;
|
||||
is->is_entsize = 0;
|
||||
}
|
||||
|
||||
void
|
||||
ld_ehframe_finalize_hdr(struct ld *ld)
|
||||
{
|
||||
struct ld_input_section *is, *hdr_is;
|
||||
struct ld_input_section_head *islist;
|
||||
struct ld_output *lo;
|
||||
struct ld_output_section *os, *hdr_os;
|
||||
struct ld_output_element *oe;
|
||||
struct ld_ehframe_fde *fde, *_fde;
|
||||
char ehframe_name[] = ".eh_frame";
|
||||
uint64_t pcbegin;
|
||||
int32_t pcrel;
|
||||
uint8_t *p, *end;
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
hdr_is = ld_input_find_internal_section(ld, ".eh_frame_hdr");
|
||||
assert(hdr_is != NULL);
|
||||
hdr_os = hdr_is->is_output;
|
||||
lo->lo_ehframe_hdr = hdr_os;
|
||||
|
||||
if (hdr_is->is_discard || hdr_os == NULL)
|
||||
return;
|
||||
|
||||
p = hdr_is->is_ibuf;
|
||||
end = p + hdr_is->is_size;
|
||||
|
||||
/* Find .eh_frame output section. */
|
||||
HASH_FIND_STR(lo->lo_ostbl, ehframe_name, os);
|
||||
assert(os != NULL);
|
||||
|
||||
/* .eh_frame_hdr version */
|
||||
*p++ = 1;
|
||||
|
||||
/*
|
||||
* eh_frame_ptr_enc: encoding format for eh_frame_ptr field.
|
||||
* Usually a signed 4-byte PC relateive offset is used here.
|
||||
*/
|
||||
*p++ = DW_EH_PE_pcrel | DW_EH_PE_sdata4;
|
||||
|
||||
/*
|
||||
* fde_count_enc: encoding format for fde_count field. Unsigned
|
||||
* 4 byte encoding should be used here. Note that If the binary
|
||||
* search table is not present, DW_EH_PE_omit should be used
|
||||
* instead.
|
||||
*/
|
||||
*p++ = lo->lo_fde_num == 0 ? DW_EH_PE_omit : DW_EH_PE_udata4;
|
||||
|
||||
/*
|
||||
* table_enc: encoding format for the binary search table entry.
|
||||
* Signed 4 byte table relative offset is used here. Note that
|
||||
* if the binary search table is not present, DW_EH_PE_omit should
|
||||
* be used instaed.
|
||||
*/
|
||||
*p++ = lo->lo_fde_num == 0 ? DW_EH_PE_omit :
|
||||
(DW_EH_PE_datarel | DW_EH_PE_sdata4);
|
||||
|
||||
/* Write 4 byte PC relative offset to the .eh_frame section. */
|
||||
pcrel = os->os_addr - hdr_os->os_addr - 4;
|
||||
WRITE_32(p, pcrel);
|
||||
p += 4;
|
||||
|
||||
/* Write the total number of FDE's. */
|
||||
WRITE_32(p, lo->lo_fde_num);
|
||||
p += 4;
|
||||
|
||||
/* Allocate global FDE list. */
|
||||
if (ld->ld_fde == NULL) {
|
||||
if ((ld->ld_fde = calloc(1, sizeof(ld->ld_fde))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
STAILQ_INIT(ld->ld_fde);
|
||||
}
|
||||
|
||||
/* Link together the FDE's from each input object. */
|
||||
STAILQ_FOREACH(oe, &os->os_e, oe_next) {
|
||||
if (oe->oe_type != OET_INPUT_SECTION_LIST)
|
||||
continue;
|
||||
|
||||
islist = oe->oe_islist;
|
||||
STAILQ_FOREACH(is, islist, is_next) {
|
||||
if (is->is_fde == NULL || STAILQ_EMPTY(is->is_fde))
|
||||
continue;
|
||||
STAILQ_FOREACH_SAFE(fde, is->is_fde, fde_next, _fde) {
|
||||
(void) _read_encoded(ld, lo, &pcbegin,
|
||||
(uint8_t *) is->is_ibuf +
|
||||
fde->fde_off_pcbegin,
|
||||
fde->fde_cie->cie_fde_encode, os->os_addr);
|
||||
fde->fde_pcrel = pcbegin - hdr_os->os_addr;
|
||||
fde->fde_datarel = os->os_addr +
|
||||
is->is_reloff + fde->fde_off -
|
||||
hdr_os->os_addr;
|
||||
STAILQ_REMOVE(is->is_fde, fde, ld_ehframe_fde,
|
||||
fde_next);
|
||||
STAILQ_INSERT_TAIL(ld->ld_fde, fde, fde_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Sort the binary search table in an increasing order by pcrel. */
|
||||
STAILQ_SORT(ld->ld_fde, ld_ehframe_fde, fde_next, _cmp_fde);
|
||||
|
||||
/* Write binary search table. */
|
||||
STAILQ_FOREACH(fde, ld->ld_fde, fde_next) {
|
||||
WRITE_32(p, fde->fde_pcrel);
|
||||
p += 4;
|
||||
WRITE_32(p, fde->fde_datarel);
|
||||
p += 4;
|
||||
}
|
||||
|
||||
assert(p == end);
|
||||
}
|
||||
|
||||
static int
|
||||
_cmp_fde(struct ld_ehframe_fde *a, struct ld_ehframe_fde *b)
|
||||
{
|
||||
|
||||
if (a->fde_pcrel < b->fde_pcrel)
|
||||
return (-1);
|
||||
else if (a->fde_pcrel == b->fde_pcrel)
|
||||
return (0);
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
_parse_cie_augment(struct ld *ld, struct ld_ehframe_cie *cie, uint8_t *aug_p,
|
||||
uint8_t *augdata_p, uint64_t auglen)
|
||||
{
|
||||
uint64_t dummy;
|
||||
uint8_t encode, *augdata_end;
|
||||
int len;
|
||||
|
||||
assert(aug_p != NULL && *aug_p == 'z');
|
||||
|
||||
augdata_end = augdata_p + auglen;
|
||||
|
||||
/*
|
||||
* Here we're only interested in the presence of augment 'R'
|
||||
* and associated CIE augment data, which describes the
|
||||
* encoding scheme of FDE PC begin and range.
|
||||
*/
|
||||
aug_p++;
|
||||
while (*aug_p != '\0') {
|
||||
switch (*aug_p) {
|
||||
case 'L':
|
||||
/* Skip one augment in augment data. */
|
||||
augdata_p++;
|
||||
break;
|
||||
case 'P':
|
||||
/* Skip two augments in augment data. */
|
||||
encode = *augdata_p++;
|
||||
len = _read_encoded(ld, ld->ld_output, &dummy,
|
||||
augdata_p, encode, 0);
|
||||
augdata_p += len;
|
||||
break;
|
||||
case 'R':
|
||||
cie->cie_fde_encode = *augdata_p++;
|
||||
break;
|
||||
default:
|
||||
ld_warn(ld, "unsupported eh_frame augmentation `%c'",
|
||||
*aug_p);
|
||||
return;
|
||||
}
|
||||
aug_p++;
|
||||
}
|
||||
|
||||
if (augdata_p > augdata_end)
|
||||
ld_warn(ld, "invalid eh_frame augmentation");
|
||||
}
|
||||
|
||||
static void
|
||||
_process_ehframe_section(struct ld *ld, struct ld_output *lo,
|
||||
struct ld_input_section *is)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_output_section *os;
|
||||
struct ld_ehframe_cie *cie, *_cie;
|
||||
struct ld_ehframe_cie_head cie_h;
|
||||
struct ld_ehframe_fde *fde;
|
||||
struct ld_reloc_entry *lre, *_lre;
|
||||
uint64_t length, es, off, off_orig, remain, shrink, auglen;
|
||||
uint32_t cie_id, cie_pointer, length_size;
|
||||
uint8_t *p, *et, cie_version, *augment;
|
||||
|
||||
li = is->is_input;
|
||||
os = is->is_output;
|
||||
|
||||
STAILQ_INIT(&cie_h);
|
||||
|
||||
/*
|
||||
* .eh_frame section content should already be preloaded
|
||||
* in is->is_ibuf.
|
||||
*/
|
||||
assert(is->is_ibuf != NULL && is->is_size > 0);
|
||||
|
||||
shrink = 0;
|
||||
p = is->is_ibuf;
|
||||
off = off_orig = 0;
|
||||
remain = is->is_size;
|
||||
while (remain > 0) {
|
||||
|
||||
et = p;
|
||||
off = et - (uint8_t *) is->is_ibuf;
|
||||
|
||||
/* Read CIE/FDE length field. */
|
||||
READ_32(p, length);
|
||||
p += 4;
|
||||
es = length + 4;
|
||||
if (length == 0xffffffff) {
|
||||
READ_64(p, length);
|
||||
p += 8;
|
||||
es += 8;
|
||||
length_size = 8;
|
||||
} else
|
||||
length_size = 4;
|
||||
|
||||
/* Check for terminator */
|
||||
if (length == 0)
|
||||
break;
|
||||
|
||||
/* Read CIE ID/Pointer field. */
|
||||
READ_32(p, cie_id);
|
||||
p += 4;
|
||||
|
||||
if (cie_id == 0) {
|
||||
|
||||
/* This is a Common Information Entry (CIE). */
|
||||
if ((cie = calloc(1, sizeof(*cie))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
cie->cie_off = off;
|
||||
cie->cie_off_orig = off_orig;
|
||||
cie->cie_size = es;
|
||||
cie->cie_content = et;
|
||||
cie->cie_dup = NULL;
|
||||
STAILQ_INSERT_TAIL(&cie_h, cie, cie_next);
|
||||
|
||||
/*
|
||||
* This is a Common Information Entry (CIE). Search
|
||||
* in the CIE list see if we can found a duplicate
|
||||
* entry.
|
||||
*/
|
||||
STAILQ_FOREACH(_cie, ld->ld_cie, cie_next) {
|
||||
if (memcmp(et, _cie->cie_content, es) == 0) {
|
||||
cie->cie_dup = _cie;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_cie != NULL) {
|
||||
/*
|
||||
* We found a duplicate entry. It should be
|
||||
* removed and the subsequent FDE's should
|
||||
* point to the previously stored CIE.
|
||||
*/
|
||||
memmove(et, et + es, remain - es);
|
||||
shrink += es;
|
||||
p = et;
|
||||
} else {
|
||||
/*
|
||||
* This is a new CIE entry which should be
|
||||
* kept. Read its augmentation which is
|
||||
* used to parse assoicated FDE's later.
|
||||
*/
|
||||
cie_version = *p++;
|
||||
if (cie_version != 1) {
|
||||
ld_warn(ld, "unsupported CIE version");
|
||||
goto ignore_cie;
|
||||
}
|
||||
augment = p;
|
||||
if (*p != 'z') {
|
||||
ld_warn(ld, "unsupported CIE "
|
||||
"augmentation");
|
||||
goto ignore_cie;
|
||||
}
|
||||
while (*p++ != '\0')
|
||||
;
|
||||
|
||||
/* Skip EH Data field. */
|
||||
if (strstr((char *)augment, "eh") != NULL)
|
||||
p += lo->lo_ec == ELFCLASS32 ? 4 : 8;
|
||||
|
||||
/* Skip CAF and DAF. */
|
||||
(void) _decode_uleb128(&p);
|
||||
(void) _decode_sleb128(&p);
|
||||
|
||||
/* Skip RA. */
|
||||
p++;
|
||||
|
||||
/* Parse augmentation data. */
|
||||
auglen = _decode_uleb128(&p);
|
||||
_parse_cie_augment(ld, cie, augment, p,
|
||||
auglen);
|
||||
|
||||
ignore_cie:
|
||||
p = et + es;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/*
|
||||
* This is a Frame Description Entry (FDE). First
|
||||
* Search for the associated CIE.
|
||||
*/
|
||||
STAILQ_FOREACH(cie, &cie_h, cie_next) {
|
||||
if (cie->cie_off_orig ==
|
||||
off_orig + length_size - cie_id)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we can not found the associated CIE, this FDE
|
||||
* is invalid and we ignore it.
|
||||
*/
|
||||
if (cie == NULL) {
|
||||
ld_warn(ld, "%s(%s): malformed FDE",
|
||||
li->li_name, is->is_name);
|
||||
p = et + es;
|
||||
goto next_entry;
|
||||
}
|
||||
|
||||
/* Allocate new FDE entry. */
|
||||
if ((fde = calloc(1, sizeof(*fde))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
fde->fde_off = off;
|
||||
fde->fde_off_pcbegin = off + length_size + 4;
|
||||
if (is->is_fde == NULL) {
|
||||
is->is_fde = calloc(1, sizeof(*is->is_fde));
|
||||
if (is->is_fde == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
STAILQ_INIT(is->is_fde);
|
||||
}
|
||||
STAILQ_INSERT_TAIL(is->is_fde, fde, fde_next);
|
||||
lo->lo_fde_num++;
|
||||
|
||||
/* Calculate the new CIE pointer value. */
|
||||
if (cie->cie_dup != NULL) {
|
||||
cie_pointer = off + length_size +
|
||||
is->is_reloff - cie->cie_dup->cie_off;
|
||||
fde->fde_cie = cie->cie_dup;
|
||||
} else {
|
||||
cie_pointer = off + length_size - cie->cie_off;
|
||||
fde->fde_cie = cie;
|
||||
}
|
||||
|
||||
/* Rewrite CIE pointer value. */
|
||||
if (cie_id != cie_pointer) {
|
||||
p -= 4;
|
||||
WRITE_32(p, cie_pointer);
|
||||
}
|
||||
|
||||
p = et + es;
|
||||
}
|
||||
|
||||
next_entry:
|
||||
off_orig += es;
|
||||
remain -= es;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the relocation entry offsets since we shrinked the
|
||||
* section content.
|
||||
*/
|
||||
if (shrink > 0 && is->is_ris != NULL && is->is_ris->is_reloc != NULL) {
|
||||
STAILQ_FOREACH_SAFE(lre, is->is_ris->is_reloc, lre_next,
|
||||
_lre) {
|
||||
STAILQ_FOREACH(cie, &cie_h, cie_next) {
|
||||
if (cie->cie_off_orig > lre->lre_offset)
|
||||
break;
|
||||
if (cie->cie_dup == NULL)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Remove relocations for the duplicated CIE
|
||||
* entries.
|
||||
*/
|
||||
if (lre->lre_offset <
|
||||
cie->cie_off_orig + cie->cie_size) {
|
||||
STAILQ_REMOVE(is->is_ris->is_reloc,
|
||||
lre, ld_reloc_entry, lre_next);
|
||||
is->is_ris->is_num_reloc--;
|
||||
is->is_ris->is_size -=
|
||||
ld->ld_arch->reloc_entsize;
|
||||
if (os->os_r != NULL)
|
||||
os->os_r->os_size -=
|
||||
ld->ld_arch->reloc_entsize;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Adjust relocation offset for FDE entries. */
|
||||
lre->lre_offset -= cie->cie_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert newly found non-duplicate CIE's to the global CIE list. */
|
||||
STAILQ_FOREACH_SAFE(cie, &cie_h, cie_next, _cie) {
|
||||
STAILQ_REMOVE(&cie_h, cie, ld_ehframe_cie, cie_next);
|
||||
if (cie->cie_dup == NULL) {
|
||||
cie->cie_off += is->is_reloff;
|
||||
STAILQ_INSERT_TAIL(ld->ld_cie, cie, cie_next);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the size of input .eh_frame section */
|
||||
is->is_size -= shrink;
|
||||
}
|
||||
|
||||
static int
|
||||
_read_encoded(struct ld *ld, struct ld_output *lo, uint64_t *val,
|
||||
uint8_t *data, uint8_t encode, uint64_t pc)
|
||||
{
|
||||
int16_t s16;
|
||||
int32_t s32;
|
||||
uint8_t application, *begin;
|
||||
int len;
|
||||
|
||||
if (encode == DW_EH_PE_omit)
|
||||
return (0);
|
||||
|
||||
application = encode & 0xf0;
|
||||
encode &= 0x0f;
|
||||
|
||||
len = 0;
|
||||
begin = data;
|
||||
|
||||
switch (encode) {
|
||||
case DW_EH_PE_absptr:
|
||||
if (lo->lo_ec == ELFCLASS32)
|
||||
READ_32(data, *val);
|
||||
else
|
||||
READ_64(data, *val);
|
||||
break;
|
||||
case DW_EH_PE_uleb128:
|
||||
*val = _decode_uleb128(&data);
|
||||
len = data - begin;
|
||||
break;
|
||||
case DW_EH_PE_udata2:
|
||||
READ_16(data, *val);
|
||||
len = 2;
|
||||
break;
|
||||
case DW_EH_PE_udata4:
|
||||
READ_32(data, *val);
|
||||
len = 4;
|
||||
break;
|
||||
case DW_EH_PE_udata8:
|
||||
READ_64(data, *val);
|
||||
len = 8;
|
||||
break;
|
||||
case DW_EH_PE_sleb128:
|
||||
*val = _decode_sleb128(&data);
|
||||
len = data - begin;
|
||||
break;
|
||||
case DW_EH_PE_sdata2:
|
||||
READ_16(data, s16);
|
||||
*val = s16;
|
||||
len = 2;
|
||||
break;
|
||||
case DW_EH_PE_sdata4:
|
||||
READ_32(data, s32);
|
||||
*val = s32;
|
||||
len = 4;
|
||||
break;
|
||||
case DW_EH_PE_sdata8:
|
||||
READ_64(data, *val);
|
||||
len = 8;
|
||||
break;
|
||||
default:
|
||||
ld_warn(ld, "unsupported eh_frame encoding");
|
||||
break;
|
||||
}
|
||||
|
||||
if (application == DW_EH_PE_pcrel) {
|
||||
/*
|
||||
* Value is relative to .eh_frame section virtual addr.
|
||||
*/
|
||||
switch (encode) {
|
||||
case DW_EH_PE_uleb128:
|
||||
case DW_EH_PE_udata2:
|
||||
case DW_EH_PE_udata4:
|
||||
case DW_EH_PE_udata8:
|
||||
*val += pc;
|
||||
break;
|
||||
case DW_EH_PE_sleb128:
|
||||
case DW_EH_PE_sdata2:
|
||||
case DW_EH_PE_sdata4:
|
||||
case DW_EH_PE_sdata8:
|
||||
*val = pc + (int64_t) *val;
|
||||
break;
|
||||
default:
|
||||
/* DW_EH_PE_absptr is absolute value. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX Applications other than DW_EH_PE_pcrel are not handled. */
|
||||
|
||||
return (len);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_decode_sleb128(uint8_t **dp)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
uint8_t b;
|
||||
int shift = 0;
|
||||
|
||||
uint8_t *src = *dp;
|
||||
|
||||
do {
|
||||
b = *src++;
|
||||
ret |= ((b & 0x7f) << shift);
|
||||
shift += 7;
|
||||
} while ((b & 0x80) != 0);
|
||||
|
||||
if (shift < 32 && (b & 0x40) != 0)
|
||||
ret |= (-1 << shift);
|
||||
|
||||
*dp = src;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
_decode_uleb128(uint8_t **dp)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint8_t b;
|
||||
int shift = 0;
|
||||
|
||||
uint8_t *src = *dp;
|
||||
|
||||
do {
|
||||
b = *src++;
|
||||
ret |= ((b & 0x7f) << shift);
|
||||
shift += 7;
|
||||
} while ((b & 0x80) != 0);
|
||||
|
||||
*dp = src;
|
||||
|
||||
return (ret);
|
||||
}
|
32
ld/ld_ehframe.h
Normal file
32
ld/ld_ehframe.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-
|
||||
* Copyright (c) 2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_ehframe.h 2960 2013-08-25 03:13:07Z kaiwang27 $
|
||||
*/
|
||||
|
||||
void ld_ehframe_adjust(struct ld *, struct ld_input_section *);
|
||||
void ld_ehframe_scan(struct ld *);
|
||||
void ld_ehframe_create_hdr(struct ld *);
|
||||
void ld_ehframe_finalize_hdr(struct ld *);
|
95
ld/ld_error.c
Normal file
95
ld/ld_error.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_error.c 2895 2013-01-15 23:05:31Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* Support routines for error and warning message generation.
|
||||
*/
|
||||
|
||||
void
|
||||
ld_fatal(struct ld *ld, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s: ", ld->ld_progname);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
ld_fatal_std(struct ld *ld, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s: ", ld->ld_progname);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, ": %s\n", strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void
|
||||
ld_err(struct ld *ld, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s: ", ld->ld_progname);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
void
|
||||
ld_warn(struct ld *ld, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stderr, "%s: warning: ", ld->ld_progname);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
|
||||
void
|
||||
ld_info(struct ld *ld, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
fprintf(stdout, "%s: ", ld->ld_progname);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stdout, fmt, ap);
|
||||
va_end(ap);
|
||||
fputc('\n', stdout);
|
||||
}
|
714
ld/ld_exp.c
Normal file
714
ld/ld_exp.c
Normal file
|
@ -0,0 +1,714 @@
|
|||
/*-
|
||||
* Copyright (c) 2011,2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "ld_script.h"
|
||||
#include "ld_exp.h"
|
||||
#include "ld_layout.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_exp.c 2526 2012-07-17 17:43:30Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* Support routines for ldscript expression.
|
||||
*/
|
||||
|
||||
static struct ld_exp *_alloc_exp(struct ld *ld);
|
||||
static int64_t _assignment(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_addr(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_align(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_alignof(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_data_segment_align(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_data_segment_end(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_data_segment_relro_end(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_defined(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_length(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_loadaddr(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_max(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_min(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_next(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_origin(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_segment_start(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_sizeof(struct ld *ld, struct ld_exp *le);
|
||||
static int64_t _func_sizeof_headers(struct ld *ld);
|
||||
static int64_t _symbol_val(struct ld *ld, char *name);
|
||||
static int64_t _symbolic_constant(struct ld *ld, const char *name);
|
||||
|
||||
#define _EXP_EVAL(x) ld_exp_eval(ld, (x))
|
||||
#define _EXP_DUMP(x) ld_exp_dump(ld, (x))
|
||||
|
||||
void
|
||||
ld_exp_free(struct ld_exp *le)
|
||||
{
|
||||
|
||||
if (le == NULL)
|
||||
return;
|
||||
|
||||
ld_exp_free(le->le_e1);
|
||||
ld_exp_free(le->le_e2);
|
||||
ld_exp_free(le->le_e3);
|
||||
if (le->le_assign != NULL)
|
||||
ld_script_assign_free(le->le_assign);
|
||||
if (le->le_name != NULL)
|
||||
free(le->le_name);
|
||||
free(le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_unary(struct ld *ld, enum ld_exp_op op, struct ld_exp *e1)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = op;
|
||||
le->le_e1 = e1;
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_binary(struct ld *ld, enum ld_exp_op op, struct ld_exp *e1,
|
||||
struct ld_exp *e2)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = op;
|
||||
le->le_e1 = e1;
|
||||
le->le_e2 = e2;
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_trinary(struct ld *ld, struct ld_exp *e1, struct ld_exp *e2,
|
||||
struct ld_exp *e3)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_TRINARY;
|
||||
le->le_e1 = e1;
|
||||
le->le_e2 = e2;
|
||||
le->le_e3 = e3;
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_sizeof_headers(struct ld *ld)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_SIZEOF_HEADERS;
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_constant(struct ld *ld, int64_t val)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_CONSTANT;
|
||||
le->le_val = val;
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_symbolic_constant(struct ld *ld, const char *name)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_SYMBOLIC_CONSTANT;
|
||||
le->le_name = strdup(name);
|
||||
if (le->le_name == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_symbol(struct ld *ld, const char *name)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_SYMBOL;
|
||||
le->le_name = strdup(name);
|
||||
if (le->le_name == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_name(struct ld *ld, const char *name)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_SECTION_NAME;
|
||||
le->le_name = strdup(name);
|
||||
if (le->le_name == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
struct ld_exp *
|
||||
ld_exp_assign(struct ld *ld, struct ld_script_assign *assign)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
le = _alloc_exp(ld);
|
||||
le->le_op = LEOP_ASSIGN;
|
||||
le->le_assign = assign;
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
int64_t
|
||||
ld_exp_eval(struct ld* ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
assert(le != NULL);
|
||||
switch (le->le_op) {
|
||||
case LEOP_ABS:
|
||||
return (abs(_EXP_EVAL(le->le_e1)));
|
||||
case LEOP_ADD:
|
||||
return (_EXP_EVAL(le->le_e1) + _EXP_EVAL(le->le_e2));
|
||||
case LEOP_ADDR:
|
||||
return (_func_addr(ld, le));
|
||||
case LEOP_ALIGN:
|
||||
case LEOP_BLOCK:
|
||||
return (_func_align(ld, le));
|
||||
case LEOP_ALIGNOF:
|
||||
return (_func_alignof(ld, le));
|
||||
case LEOP_AND:
|
||||
return (_EXP_EVAL(le->le_e1) & _EXP_EVAL(le->le_e2));
|
||||
case LEOP_ASSIGN:
|
||||
return (_assignment(ld, le));
|
||||
case LEOP_CONSTANT:
|
||||
return (le->le_val);
|
||||
case LEOP_DIV:
|
||||
return (_EXP_EVAL(le->le_e1) / _EXP_EVAL(le->le_e2));
|
||||
case LEOP_DSA:
|
||||
return (_func_data_segment_align(ld, le));
|
||||
case LEOP_DSE:
|
||||
return (_func_data_segment_end(ld, le));
|
||||
case LEOP_DSRE:
|
||||
return (_func_data_segment_relro_end(ld, le));
|
||||
case LEOP_DEFINED:
|
||||
return (_func_defined(ld, le));
|
||||
case LEOP_EQUAL:
|
||||
return (_EXP_EVAL(le->le_e1) == _EXP_EVAL(le->le_e2));
|
||||
case LEOP_GE:
|
||||
return (_EXP_EVAL(le->le_e1) >= _EXP_EVAL(le->le_e2));
|
||||
case LEOP_GREATER:
|
||||
return (_EXP_EVAL(le->le_e1) > _EXP_EVAL(le->le_e2));
|
||||
case LEOP_LENGTH:
|
||||
return (_func_length(ld, le));
|
||||
case LEOP_LOADADDR:
|
||||
return (_func_loadaddr(ld, le));
|
||||
case LEOP_LOGICAL_AND:
|
||||
return (_EXP_EVAL(le->le_e1) && _EXP_EVAL(le->le_e2));
|
||||
case LEOP_LOGICAL_OR:
|
||||
return (_EXP_EVAL(le->le_e1) || _EXP_EVAL(le->le_e2));
|
||||
case LEOP_LSHIFT:
|
||||
return (_EXP_EVAL(le->le_e1) << _EXP_EVAL(le->le_e2));
|
||||
case LEOP_MAX:
|
||||
return (_func_max(ld, le));
|
||||
case LEOP_MIN:
|
||||
return (_func_min(ld, le));
|
||||
case LEOP_MINUS:
|
||||
return (-(_EXP_EVAL(le->le_e1)));
|
||||
case LEOP_MOD:
|
||||
return (_EXP_EVAL(le->le_e1) % _EXP_EVAL(le->le_e2));
|
||||
case LEOP_MUL:
|
||||
return (_EXP_EVAL(le->le_e1) * _EXP_EVAL(le->le_e2));
|
||||
case LEOP_NE:
|
||||
return (_EXP_EVAL(le->le_e1) != _EXP_EVAL(le->le_e2));
|
||||
case LEOP_NEGATION:
|
||||
return (~(_EXP_EVAL(le->le_e1)));
|
||||
case LEOP_NEXT:
|
||||
return (_func_next(ld, le));
|
||||
case LEOP_NOT:
|
||||
return (!(_EXP_EVAL(le->le_e1)));
|
||||
case LEOP_OR:
|
||||
return (_EXP_EVAL(le->le_e1) | _EXP_EVAL(le->le_e2));
|
||||
case LEOP_ORIGIN:
|
||||
return (_func_origin(ld, le));
|
||||
case LEOP_RSHIFT:
|
||||
return (_EXP_EVAL(le->le_e1) >> _EXP_EVAL(le->le_e2));
|
||||
case LEOP_SEGMENT_START:
|
||||
return (_func_segment_start(ld, le));
|
||||
case LEOP_SIZEOF:
|
||||
return (_func_sizeof(ld, le));
|
||||
case LEOP_SIZEOF_HEADERS:
|
||||
return (_func_sizeof_headers(ld));
|
||||
case LEOP_SUBSTRACT:
|
||||
return (_EXP_EVAL(le->le_e1) - _EXP_EVAL(le->le_e2));
|
||||
case LEOP_SYMBOL:
|
||||
return (_symbol_val(ld, le->le_name));
|
||||
case LEOP_SYMBOLIC_CONSTANT:
|
||||
return (_symbolic_constant(ld, le->le_name));
|
||||
case LEOP_TRINARY:
|
||||
return (_EXP_EVAL(le->le_e1) ? _EXP_EVAL(le->le_e2) :
|
||||
_EXP_EVAL(le->le_e3));
|
||||
default:
|
||||
ld_fatal(ld, "internal: unknown ldscript expression op");
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ld_exp_dump(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
assert(le != NULL);
|
||||
|
||||
if (le->le_par)
|
||||
printf("(");
|
||||
|
||||
switch (le->le_op) {
|
||||
case LEOP_ABS:
|
||||
printf("ABS(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_ADD:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" + ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_ADDR:
|
||||
printf("ADDR(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_ALIGN:
|
||||
case LEOP_BLOCK:
|
||||
printf("ALIGN(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
if (le->le_e2 != NULL) {
|
||||
printf(", ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
}
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_ALIGNOF:
|
||||
printf("ALIGNOF(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_AND:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" & ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_ASSIGN:
|
||||
printf("0x%jx", (uintmax_t) le->le_assign->lda_res);
|
||||
break;
|
||||
case LEOP_CONSTANT:
|
||||
printf("0x%jx", (uintmax_t) le->le_val);
|
||||
break;
|
||||
case LEOP_DIV:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" / ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_DSA:
|
||||
printf("DATA_SEGMENT_ALIGN(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(", ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_DSE:
|
||||
printf("DATA_SEGMENT_END(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_DSRE:
|
||||
printf("DATA_SEGMENT_RELRO_END(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(", ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_DEFINED:
|
||||
printf("DEFINED(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_EQUAL:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" == ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_GE:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" >= ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_GREATER:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" > ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_LENGTH:
|
||||
printf("LENGTH(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_LOADADDR:
|
||||
printf("LOADADDR(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_LOGICAL_AND:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" && ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_LOGICAL_OR:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" || ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_LSHIFT:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" << ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_MAX:
|
||||
printf("MAX(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(", ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_MIN:
|
||||
printf("MIN(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(", ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_MINUS:
|
||||
printf("-");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
break;
|
||||
case LEOP_MOD:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" %% ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_MUL:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" * ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_NE:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" != ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_NEGATION:
|
||||
printf("~");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
break;
|
||||
case LEOP_NEXT:
|
||||
printf("NEXT(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_NOT:
|
||||
printf("!");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
break;
|
||||
case LEOP_OR:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" | ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_ORIGIN:
|
||||
printf("ORIGIN(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_RSHIFT:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" >> ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_SEGMENT_START:
|
||||
printf("SEGMENT_START(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(", ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_SIZEOF:
|
||||
printf("SIZEOF(");
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(")");
|
||||
break;
|
||||
case LEOP_SIZEOF_HEADERS:
|
||||
printf("SIZEOF_HEADERS");
|
||||
break;
|
||||
case LEOP_SUBSTRACT:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" - ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
break;
|
||||
case LEOP_SYMBOL:
|
||||
printf("%s", le->le_name);
|
||||
break;
|
||||
case LEOP_SYMBOLIC_CONSTANT:
|
||||
printf("0x%jx",
|
||||
(uintmax_t) _symbolic_constant(ld, le->le_name));
|
||||
break;
|
||||
case LEOP_TRINARY:
|
||||
_EXP_DUMP(le->le_e1);
|
||||
printf(" ? ");
|
||||
_EXP_DUMP(le->le_e2);
|
||||
printf(" : ");
|
||||
_EXP_DUMP(le->le_e3);
|
||||
break;
|
||||
default:
|
||||
ld_fatal(ld, "internal: unknown ldscript expression op");
|
||||
}
|
||||
|
||||
if (le->le_par)
|
||||
printf(")");
|
||||
}
|
||||
|
||||
static struct ld_exp *
|
||||
_alloc_exp(struct ld *ld)
|
||||
{
|
||||
struct ld_exp *le;
|
||||
|
||||
if ((le = calloc(1, sizeof(*le))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
return (le);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_assignment(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
struct ld_exp *var;
|
||||
|
||||
assert(le->le_assign != NULL);
|
||||
ld_script_process_assign(ld, le->le_assign);
|
||||
var = le->le_assign->lda_var;
|
||||
return (ld_script_variable_value(ld, var->le_name));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_addr(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_align(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
|
||||
ls = &ld->ld_state;
|
||||
if (le->le_e2 != NULL)
|
||||
return (roundup(_EXP_EVAL(le->le_e1), _EXP_EVAL(le->le_e2)));
|
||||
else
|
||||
return (roundup(ls->ls_loc_counter, _EXP_EVAL(le->le_e1)));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_alignof(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_data_segment_align(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
uint64_t maxpagesize, commonpagesize;
|
||||
|
||||
/*
|
||||
* TODO: test if align to common page size use less number
|
||||
* of pages.
|
||||
*/
|
||||
ls = &ld->ld_state;
|
||||
maxpagesize = _EXP_EVAL(le->le_e1);
|
||||
commonpagesize = _EXP_EVAL(le->le_e2);
|
||||
|
||||
return (roundup(ls->ls_loc_counter, maxpagesize) +
|
||||
(ls->ls_loc_counter & (maxpagesize - 1)));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_data_segment_end(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
return (_EXP_EVAL(le->le_e1));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_data_segment_relro_end(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_defined(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_length(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_loadaddr(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_max(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
uint64_t val1, val2;
|
||||
|
||||
val1 = _EXP_EVAL(le->le_e1);
|
||||
val2 = _EXP_EVAL(le->le_e2);
|
||||
|
||||
return (val1 > val2 ? val1 : val2);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_min(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
uint64_t val1, val2;
|
||||
|
||||
val1 = _EXP_EVAL(le->le_e1);
|
||||
val2 = _EXP_EVAL(le->le_e2);
|
||||
|
||||
return (val1 > val2 ? val2 : val1);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_next(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_origin(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_segment_start(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_sizeof(struct ld *ld, struct ld_exp *le)
|
||||
{
|
||||
|
||||
/* TODO */
|
||||
(void) ld; (void) le;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_func_sizeof_headers(struct ld *ld)
|
||||
{
|
||||
|
||||
return (ld_layout_calc_header_size(ld));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_symbol_val(struct ld *ld, char *name)
|
||||
{
|
||||
|
||||
return (ld_script_variable_value(ld, name));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
_symbolic_constant(struct ld *ld, const char *name)
|
||||
{
|
||||
|
||||
if (ld->ld_arch == NULL)
|
||||
return (0);
|
||||
|
||||
if (strcmp(name, "COMMONPAGESIZE") == 0)
|
||||
return (ld->ld_arch->get_common_page_size(ld));
|
||||
else if (strcmp(name, "MAXPAGESIZE") == 0)
|
||||
return (ld->ld_arch->get_max_page_size(ld));
|
||||
|
||||
return (0);
|
||||
}
|
100
ld/ld_exp.h
Normal file
100
ld/ld_exp.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*-
|
||||
* Copyright (c) 2011,2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_exp.h 2525 2012-07-17 17:36:19Z kaiwang27 $
|
||||
*/
|
||||
|
||||
enum ld_exp_op {
|
||||
LEOP_ABS,
|
||||
LEOP_ADD,
|
||||
LEOP_ADDR,
|
||||
LEOP_ALIGN,
|
||||
LEOP_ALIGNOF,
|
||||
LEOP_AND,
|
||||
LEOP_ASSIGN,
|
||||
LEOP_BLOCK,
|
||||
LEOP_CONSTANT,
|
||||
LEOP_DIV,
|
||||
LEOP_DSA,
|
||||
LEOP_DSE,
|
||||
LEOP_DSRE,
|
||||
LEOP_DEFINED,
|
||||
LEOP_EQUAL,
|
||||
LEOP_GE,
|
||||
LEOP_GREATER,
|
||||
LEOP_LENGTH,
|
||||
LEOP_LE,
|
||||
LEOP_LESSER,
|
||||
LEOP_LOADADDR,
|
||||
LEOP_LOGICAL_AND,
|
||||
LEOP_LOGICAL_OR,
|
||||
LEOP_LSHIFT,
|
||||
LEOP_MAX,
|
||||
LEOP_MIN,
|
||||
LEOP_MINUS,
|
||||
LEOP_MOD,
|
||||
LEOP_MUL,
|
||||
LEOP_NE,
|
||||
LEOP_NEGATION,
|
||||
LEOP_NEXT,
|
||||
LEOP_NOT,
|
||||
LEOP_OR,
|
||||
LEOP_ORIGIN,
|
||||
LEOP_RSHIFT,
|
||||
LEOP_SEGMENT_START,
|
||||
LEOP_SIZEOF,
|
||||
LEOP_SIZEOF_HEADERS,
|
||||
LEOP_SECTION_NAME,
|
||||
LEOP_SUBSTRACT,
|
||||
LEOP_SYMBOL,
|
||||
LEOP_SYMBOLIC_CONSTANT,
|
||||
LEOP_TRINARY,
|
||||
};
|
||||
|
||||
struct ld_exp {
|
||||
enum ld_exp_op le_op; /* expression operator */
|
||||
struct ld_exp *le_e1; /* fisrt operand */
|
||||
struct ld_exp *le_e2; /* second operand */
|
||||
struct ld_exp *le_e3; /* third operand */
|
||||
struct ld_script_assign *le_assign; /* assignment */
|
||||
char *le_name; /* symbol/section name */
|
||||
unsigned le_par; /* parenthesis */
|
||||
int64_t le_val; /* constant value */
|
||||
};
|
||||
|
||||
struct ld_exp *ld_exp_assign(struct ld *, struct ld_script_assign *);
|
||||
struct ld_exp *ld_exp_binary(struct ld *, enum ld_exp_op, struct ld_exp *,
|
||||
struct ld_exp *);
|
||||
struct ld_exp *ld_exp_constant(struct ld *, int64_t);
|
||||
int64_t ld_exp_eval(struct ld *, struct ld_exp *);
|
||||
void ld_exp_dump(struct ld *, struct ld_exp *);
|
||||
struct ld_exp *ld_exp_name(struct ld *, const char *);
|
||||
struct ld_exp *ld_exp_sizeof_headers(struct ld *);
|
||||
struct ld_exp *ld_exp_symbol(struct ld *, const char *);
|
||||
struct ld_exp *ld_exp_symbolic_constant(struct ld *, const char *);
|
||||
struct ld_exp *ld_exp_trinary(struct ld *, struct ld_exp *, struct ld_exp *,
|
||||
struct ld_exp *);
|
||||
struct ld_exp *ld_exp_unary(struct ld *, enum ld_exp_op, struct ld_exp *);
|
||||
void ld_exp_free(struct ld_exp *);
|
233
ld/ld_file.c
Normal file
233
ld/ld_file.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "ld_file.h"
|
||||
#include "ld_path.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_file.c 2930 2013-03-17 22:54:26Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* Support routines for input file handling.
|
||||
*/
|
||||
|
||||
static void _add_file(struct ld *ld, const char *name, enum ld_file_type type,
|
||||
int first, struct ld_file *after);
|
||||
|
||||
void
|
||||
ld_file_cleanup(struct ld *ld)
|
||||
{
|
||||
struct ld_file *lf, *_lf;
|
||||
struct ld_archive_member *lam, *_lam;
|
||||
|
||||
TAILQ_FOREACH_SAFE(lf, &ld->ld_lflist, lf_next, _lf) {
|
||||
TAILQ_REMOVE(&ld->ld_lflist, lf, lf_next);
|
||||
free(lf->lf_name);
|
||||
if (lf->lf_ar != NULL) {
|
||||
HASH_ITER(hh, lf->lf_ar->la_m, lam, _lam) {
|
||||
HASH_DEL(lf->lf_ar->la_m, lam);
|
||||
free(lam->lam_name);
|
||||
free(lam);
|
||||
}
|
||||
free(lf->lf_ar);
|
||||
}
|
||||
free(lf);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_file_add(struct ld *ld, const char *name, enum ld_file_type type)
|
||||
{
|
||||
|
||||
_add_file(ld, name, type, 0, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ld_file_add_first(struct ld *ld, const char *name, enum ld_file_type type)
|
||||
{
|
||||
|
||||
_add_file(ld, name, type, 1, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
ld_file_add_after(struct ld *ld, const char *name, enum ld_file_type type,
|
||||
struct ld_file *after)
|
||||
{
|
||||
|
||||
_add_file(ld, name, type, 0, after);
|
||||
}
|
||||
|
||||
void
|
||||
ld_file_load(struct ld *ld, struct ld_file *lf)
|
||||
{
|
||||
struct ld_archive *la;
|
||||
struct ld_state *ls;
|
||||
struct stat sb;
|
||||
Elf_Kind k;
|
||||
GElf_Ehdr ehdr;
|
||||
int fd;
|
||||
|
||||
assert(lf != NULL && lf->lf_name != NULL);
|
||||
|
||||
ls = &ld->ld_state;
|
||||
if (ls->ls_file == lf)
|
||||
return;
|
||||
|
||||
if ((fd = open(lf->lf_name, O_RDONLY)) < 0)
|
||||
ld_fatal_std(ld, "%s: open", lf->lf_name);
|
||||
|
||||
if (fstat(fd, &sb) < 0)
|
||||
ld_fatal_std(ld, "%s: stat", lf->lf_name);
|
||||
if (sb.st_size == 0)
|
||||
ld_fatal(ld, "%s: File truncated", lf->lf_name);
|
||||
|
||||
lf->lf_size = sb.st_size;
|
||||
if ((lf->lf_mmap = mmap(NULL, lf->lf_size, PROT_READ, MAP_PRIVATE, fd,
|
||||
(off_t) 0)) == MAP_FAILED)
|
||||
ld_fatal_std(ld, "%s: mmap", lf->lf_name);
|
||||
close(fd);
|
||||
|
||||
if (lf->lf_type == LFT_BINARY)
|
||||
return;
|
||||
|
||||
if ((lf->lf_elf = elf_memory(lf->lf_mmap, lf->lf_size)) == NULL)
|
||||
ld_fatal(ld, "%s: elf_memory failed: %s", lf->lf_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
k = elf_kind(lf->lf_elf);
|
||||
|
||||
if (k == ELF_K_AR) {
|
||||
lf->lf_type = LFT_ARCHIVE;
|
||||
if (lf->lf_ar == NULL) {
|
||||
if ((la = calloc(1, sizeof(*la))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
lf->lf_ar = la;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
assert(k != ELF_K_AR);
|
||||
if (k == ELF_K_NONE)
|
||||
ld_fatal(ld, "%s: File format not recognized", lf->lf_name);
|
||||
|
||||
if (gelf_getehdr(lf->lf_elf, &ehdr) == NULL)
|
||||
ld_fatal(ld, "%s: gelf_getehdr failed: %s", lf->lf_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
switch (ehdr.e_type) {
|
||||
case ET_NONE:
|
||||
ld_fatal(ld, "%s: ELF type ET_NONE not supported", lf->lf_name);
|
||||
case ET_REL:
|
||||
lf->lf_type = LFT_RELOCATABLE;
|
||||
break;
|
||||
case ET_EXEC:
|
||||
ld_fatal(ld, "%s: ELF type ET_EXEC not supported yet",
|
||||
lf->lf_name);
|
||||
case ET_DYN:
|
||||
lf->lf_type = LFT_DSO;
|
||||
break;
|
||||
case ET_CORE:
|
||||
ld_fatal(ld, "%s: ELF type ET_NONE not supported", lf->lf_name);
|
||||
default:
|
||||
ld_fatal(ld, "%s: unknown ELF type %u", ehdr.e_type);
|
||||
}
|
||||
|
||||
ld_arch_verify(ld, lf->lf_name, ehdr.e_machine);
|
||||
}
|
||||
|
||||
void
|
||||
ld_file_unload(struct ld *ld, struct ld_file *lf)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
if (lf->lf_type != LFT_BINARY)
|
||||
elf_end(lf->lf_elf);
|
||||
|
||||
if (lf->lf_mmap != NULL) {
|
||||
if (munmap(lf->lf_mmap, lf->lf_size) < 0)
|
||||
ld_fatal_std(ld, "%s: munmap", lf->lf_name);
|
||||
}
|
||||
|
||||
if (ls->ls_file == lf)
|
||||
ls->ls_file = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_add_file(struct ld *ld, const char *name, enum ld_file_type type,
|
||||
int first, struct ld_file *after)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_file *lf;
|
||||
int fd;
|
||||
|
||||
assert(ld != NULL && name != NULL);
|
||||
|
||||
if (!strncmp(name, "-l", 2)) {
|
||||
ld_path_search_library(ld, &name[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
if ((lf = calloc(1, sizeof(*lf))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
if ((lf->lf_name = strdup(name)) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
|
||||
lf->lf_type = type;
|
||||
lf->lf_whole_archive = ls->ls_whole_archive;
|
||||
lf->lf_as_needed = ls->ls_as_needed;
|
||||
lf->lf_group_level = ls->ls_group_level;
|
||||
lf->lf_search_dir = ls->ls_search_dir;
|
||||
|
||||
if ((fd = open(lf->lf_name, O_RDONLY)) < 0) {
|
||||
if (!lf->lf_search_dir)
|
||||
ld_fatal_std(ld, "%s: open", lf->lf_name);
|
||||
|
||||
/* Search library path for this file. */
|
||||
ld_path_search_file(ld, lf);
|
||||
} else
|
||||
(void) close(fd);
|
||||
|
||||
if (lf->lf_type == LFT_UNKNOWN && ls->ls_itgt != NULL) {
|
||||
if (elftc_bfd_target_flavor(ls->ls_itgt) == ETF_BINARY)
|
||||
lf->lf_type = LFT_BINARY;
|
||||
}
|
||||
|
||||
if (lf->lf_type == LFT_DSO)
|
||||
ld->ld_dynamic_link = 1;
|
||||
|
||||
if (after != NULL)
|
||||
TAILQ_INSERT_AFTER(&ld->ld_lflist, after, lf, lf_next);
|
||||
else if (first)
|
||||
TAILQ_INSERT_HEAD(&ld->ld_lflist, lf, lf_next);
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&ld->ld_lflist, lf, lf_next);
|
||||
}
|
70
ld/ld_file.h
Normal file
70
ld/ld_file.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_file.h 2930 2013-03-17 22:54:26Z kaiwang27 $
|
||||
*/
|
||||
|
||||
enum ld_file_type {
|
||||
LFT_UNKNOWN,
|
||||
LFT_RELOCATABLE,
|
||||
LFT_DSO,
|
||||
LFT_ARCHIVE,
|
||||
LFT_BINARY
|
||||
};
|
||||
|
||||
struct ld_archive_member {
|
||||
char *lam_ar_name; /* archive name */
|
||||
char *lam_name; /* archive member name */
|
||||
off_t lam_off; /* archive member offset */
|
||||
struct ld_input *lam_input; /* input object */
|
||||
UT_hash_handle hh; /* hash handle */
|
||||
};
|
||||
|
||||
struct ld_archive {
|
||||
struct ld_archive_member *la_m; /* extracted member list. */
|
||||
};
|
||||
|
||||
struct ld_file {
|
||||
char *lf_name; /* input file name */
|
||||
enum ld_file_type lf_type; /* input file type */
|
||||
void *lf_mmap; /* input file image */
|
||||
size_t lf_size; /* input file size */
|
||||
Elf *lf_elf; /* input file ELF descriptor */
|
||||
struct ld_archive *lf_ar; /* input archive */
|
||||
struct ld_input *lf_input; /* input object */
|
||||
unsigned lf_whole_archive; /* include whole archive */
|
||||
unsigned lf_as_needed; /* DT_NEEDED */
|
||||
unsigned lf_group_level; /* archive group level */
|
||||
unsigned lf_search_dir; /* search library directories */
|
||||
TAILQ_ENTRY(ld_file) lf_next; /* next input file */
|
||||
};
|
||||
|
||||
void ld_file_add(struct ld *, const char *, enum ld_file_type);
|
||||
void ld_file_add_first(struct ld *, const char *, enum ld_file_type);
|
||||
void ld_file_add_after(struct ld *, const char *, enum ld_file_type,
|
||||
struct ld_file *);
|
||||
void ld_file_cleanup(struct ld *);
|
||||
void ld_file_load(struct ld *, struct ld_file *);
|
||||
void ld_file_unload(struct ld *, struct ld_file *);
|
126
ld/ld_hash.c
Normal file
126
ld/ld_hash.c
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_hash.h"
|
||||
#include "ld_layout.h"
|
||||
#include "ld_output.h"
|
||||
#include "ld_symbols.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_hash.c 2917 2013-02-16 07:16:02Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* The number of buckets to use for a certain number of symbols.
|
||||
* If there are less than 3 symbols, 1 bucket will be used. If
|
||||
* there are less than 17 symbols, 3 buckets will be used, and so
|
||||
* forth. The bucket numbers are defined by GNU ld. We use the
|
||||
* same rules here so we generate hash sections with the same
|
||||
* size as those generated by GNU ld.
|
||||
*/
|
||||
static unsigned hash_buckets[] = {
|
||||
1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209,
|
||||
16411, 32771, 65537, 131101, 262147
|
||||
};
|
||||
|
||||
void
|
||||
ld_hash_create_svr4_hash_section(struct ld *ld)
|
||||
{
|
||||
struct ld_output *lo;
|
||||
struct ld_output_section *os;
|
||||
struct ld_output_data_buffer *odb;
|
||||
struct ld_symbol *lsb;
|
||||
char hash_name[] = ".hash";
|
||||
uint32_t *buf, *buckets, *chains, nbuckets, nchains;
|
||||
int i, j;
|
||||
|
||||
lo = ld->ld_output;
|
||||
assert(lo != NULL);
|
||||
|
||||
HASH_FIND_STR(lo->lo_ostbl, hash_name, os);
|
||||
if (os == NULL)
|
||||
os = ld_layout_insert_output_section(ld, hash_name, SHF_ALLOC);
|
||||
os->os_type = SHT_HASH;
|
||||
os->os_flags = SHF_ALLOC;
|
||||
os->os_entsize = 4;
|
||||
if (lo->lo_ec == ELFCLASS32)
|
||||
os->os_align = 4;
|
||||
else
|
||||
os->os_align = 8;
|
||||
|
||||
if ((os->os_link = strdup(".dynsym")) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
|
||||
lo->lo_hash = os;
|
||||
|
||||
assert(ld->ld_dynsym != NULL && ld->ld_dynsym->sy_size > 0);
|
||||
|
||||
nchains = ld->ld_dynsym->sy_size;
|
||||
nbuckets = 0;
|
||||
for (i = 1;
|
||||
(size_t) i < sizeof(hash_buckets) / sizeof(hash_buckets[0]);
|
||||
i++) {
|
||||
if (nchains < hash_buckets[i]) {
|
||||
nbuckets = hash_buckets[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nbuckets == 0)
|
||||
nbuckets = hash_buckets[i - 1];
|
||||
|
||||
if ((buf = calloc(nbuckets + nchains + 2, sizeof(uint32_t))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
buf[0] = nbuckets;
|
||||
buf[1] = nchains;
|
||||
buckets = &buf[2];
|
||||
chains = &buf[2 + nbuckets];
|
||||
|
||||
assert(ld->ld_dyn_symbols != NULL);
|
||||
|
||||
i = 1;
|
||||
STAILQ_FOREACH(lsb, ld->ld_dyn_symbols, lsb_dyn) {
|
||||
if (lsb->lsb_name == NULL) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
j = elf_hash(lsb->lsb_name) % nbuckets;
|
||||
chains[i] = buckets[j];
|
||||
buckets[j] = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
if ((odb = calloc(1, sizeof(*odb))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
odb->odb_buf = (void *) buf;
|
||||
odb->odb_size = (nbuckets + nchains + 2) * sizeof(uint32_t);
|
||||
odb->odb_align = os->os_align;
|
||||
odb->odb_type = ELF_T_WORD; /* enable libelf translation */
|
||||
|
||||
(void) ld_output_create_section_element(ld, os, OET_DATA_BUFFER,
|
||||
odb, NULL);
|
||||
}
|
29
ld/ld_hash.h
Normal file
29
ld/ld_hash.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*-
|
||||
* Copyright (c) 2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_hash.h 2669 2012-11-11 13:20:43Z kaiwang27 $
|
||||
*/
|
||||
|
||||
void ld_hash_create_svr4_hash_section(struct ld *);
|
653
ld/ld_input.c
Normal file
653
ld/ld_input.c
Normal file
|
@ -0,0 +1,653 @@
|
|||
/*-
|
||||
* Copyright (c) 2011-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_file.h"
|
||||
#include "ld_input.h"
|
||||
#include "ld_symbols.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_input.c 2960 2013-08-25 03:13:07Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* Support routines for input section handling.
|
||||
*/
|
||||
|
||||
static void _discard_section_group(struct ld *ld, struct ld_input *li,
|
||||
Elf_Scn *scn);
|
||||
static off_t _offset_sort(struct ld_archive_member *a,
|
||||
struct ld_archive_member *b);
|
||||
|
||||
#define _MAX_INTERNAL_SECTIONS 16
|
||||
|
||||
void
|
||||
ld_input_init(struct ld *ld)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_input_section *is;
|
||||
|
||||
assert(STAILQ_EMPTY(&ld->ld_lilist));
|
||||
|
||||
/*
|
||||
* Create an internal pseudo input object to hold internal
|
||||
* input sections.
|
||||
*/
|
||||
|
||||
li = ld_input_alloc(ld, NULL, NULL);
|
||||
|
||||
li->li_is = calloc(_MAX_INTERNAL_SECTIONS,
|
||||
sizeof(struct ld_input_section));
|
||||
if (li->li_is == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
STAILQ_INSERT_TAIL(&ld->ld_lilist, li, li_next);
|
||||
|
||||
/*
|
||||
* Create an initial SHT_NULL section for the pseudo input object,
|
||||
* so all the internal sections will have valid section index.
|
||||
* (other than SHN_UNDEF)
|
||||
*/
|
||||
is = &li->li_is[li->li_shnum];
|
||||
if ((is->is_name = strdup("")) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
is->is_input = li;
|
||||
is->is_type = SHT_NULL;
|
||||
is->is_index = li->li_shnum;
|
||||
li->li_shnum++;
|
||||
}
|
||||
|
||||
struct ld_input_section *
|
||||
ld_input_add_internal_section(struct ld *ld, const char *name)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_input_section *is;
|
||||
|
||||
li = STAILQ_FIRST(&ld->ld_lilist);
|
||||
assert(li != NULL);
|
||||
|
||||
if (li->li_shnum >= _MAX_INTERNAL_SECTIONS)
|
||||
ld_fatal(ld, "Internal: not enough buffer for internal "
|
||||
"sections");
|
||||
|
||||
is = &li->li_is[li->li_shnum];
|
||||
if ((is->is_name = strdup(name)) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
is->is_input = li;
|
||||
is->is_index = li->li_shnum;
|
||||
|
||||
/* Use a hash table to accelerate lookup for internal sections. */
|
||||
HASH_ADD_KEYPTR(hh, li->li_istbl, is->is_name, strlen(is->is_name),
|
||||
is);
|
||||
|
||||
li->li_shnum++;
|
||||
|
||||
return (is);
|
||||
}
|
||||
|
||||
struct ld_input_section *
|
||||
ld_input_find_internal_section(struct ld *ld, const char *name)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_input_section *is;
|
||||
char _name[32];
|
||||
|
||||
li = STAILQ_FIRST(&ld->ld_lilist);
|
||||
assert(li != NULL);
|
||||
|
||||
snprintf(_name, sizeof(_name), "%s", name);
|
||||
HASH_FIND_STR(li->li_istbl, _name, is);
|
||||
|
||||
return (is);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
ld_input_reserve_ibuf(struct ld_input_section *is, uint64_t n)
|
||||
{
|
||||
uint64_t off;
|
||||
|
||||
assert(is->is_entsize != 0);
|
||||
|
||||
off = is->is_size;
|
||||
is->is_size += n * is->is_entsize;
|
||||
|
||||
return (off);
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_alloc_internal_section_buffers(struct ld *ld)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_input_section *is;
|
||||
int i;
|
||||
|
||||
li = STAILQ_FIRST(&ld->ld_lilist);
|
||||
assert(li != NULL);
|
||||
|
||||
for (i = 0; (uint64_t) i < li->li_shnum; i++) {
|
||||
is = &li->li_is[i];
|
||||
|
||||
if (is->is_type == SHT_NOBITS || is->is_size == 0 ||
|
||||
is->is_dynrel)
|
||||
continue;
|
||||
|
||||
if ((is->is_ibuf = malloc(is->is_size)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_cleanup(struct ld *ld)
|
||||
{
|
||||
struct ld_input *li, *_li;
|
||||
int i;
|
||||
|
||||
STAILQ_FOREACH_SAFE(li, &ld->ld_lilist, li_next, _li) {
|
||||
STAILQ_REMOVE(&ld->ld_lilist, li, ld_input, li_next);
|
||||
if (li->li_symindex)
|
||||
free(li->li_symindex);
|
||||
if (li->li_local)
|
||||
free(li->li_local);
|
||||
if (li->li_versym)
|
||||
free(li->li_versym);
|
||||
if (li->li_vername) {
|
||||
for (i = 0; (size_t) i < li->li_vername_sz; i++)
|
||||
if (li->li_vername[i])
|
||||
free(li->li_vername[i]);
|
||||
free(li->li_vername);
|
||||
}
|
||||
if (li->li_is)
|
||||
free(li->li_is);
|
||||
if (li->li_fullname)
|
||||
free(li->li_fullname);
|
||||
if (li->li_name)
|
||||
free(li->li_name);
|
||||
if (li->li_soname)
|
||||
free(li->li_soname);
|
||||
free(li);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_add_symbol(struct ld *ld, struct ld_input *li, struct ld_symbol *lsb)
|
||||
{
|
||||
|
||||
if (li->li_symindex == NULL) {
|
||||
assert(li->li_symnum != 0);
|
||||
li->li_symindex = calloc(li->li_symnum,
|
||||
sizeof(*li->li_symindex));
|
||||
if (li->li_symindex == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
}
|
||||
|
||||
li->li_symindex[lsb->lsb_index] = lsb;
|
||||
|
||||
if (lsb->lsb_bind == STB_LOCAL) {
|
||||
if (li->li_local == NULL) {
|
||||
li->li_local = calloc(1, sizeof(*li->li_local));
|
||||
if (li->li_local == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
STAILQ_INIT(li->li_local);
|
||||
}
|
||||
STAILQ_INSERT_TAIL(li->li_local, lsb, lsb_next);
|
||||
}
|
||||
}
|
||||
|
||||
struct ld_input *
|
||||
ld_input_alloc(struct ld *ld, struct ld_file *lf, const char *name)
|
||||
{
|
||||
struct ld_input *li;
|
||||
|
||||
if ((li = calloc(1, sizeof(*li))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
if (name != NULL && (li->li_name = strdup(name)) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
|
||||
li->li_file = lf;
|
||||
|
||||
if (lf != NULL) {
|
||||
switch (lf->lf_type) {
|
||||
case LFT_ARCHIVE:
|
||||
case LFT_RELOCATABLE:
|
||||
li->li_type = LIT_RELOCATABLE;
|
||||
break;
|
||||
case LFT_DSO:
|
||||
li->li_type = LIT_DSO;
|
||||
break;
|
||||
case LFT_BINARY:
|
||||
case LFT_UNKNOWN:
|
||||
default:
|
||||
li->li_type = LIT_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
li->li_type = LIT_RELOCATABLE;
|
||||
|
||||
return (li);
|
||||
}
|
||||
|
||||
char *
|
||||
ld_input_get_fullname(struct ld *ld, struct ld_input *li)
|
||||
{
|
||||
struct ld_archive_member *lam;
|
||||
size_t len;
|
||||
|
||||
if (li->li_fullname != NULL)
|
||||
return (li->li_fullname);
|
||||
|
||||
if (li->li_lam == NULL)
|
||||
return (li->li_name);
|
||||
|
||||
lam = li->li_lam;
|
||||
len = strlen(lam->lam_ar_name) + strlen(lam->lam_name) + 3;
|
||||
if ((li->li_fullname = malloc(len)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
snprintf(li->li_fullname, len, "%s(%s)", lam->lam_ar_name,
|
||||
lam->lam_name);
|
||||
|
||||
return (li->li_fullname);
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_link_objects(struct ld *ld)
|
||||
{
|
||||
struct ld_file *lf;
|
||||
struct ld_archive_member *lam, *tmp;
|
||||
struct ld_input *li;
|
||||
|
||||
TAILQ_FOREACH(lf, &ld->ld_lflist, lf_next) {
|
||||
if (lf->lf_ar != NULL) {
|
||||
HASH_SORT(lf->lf_ar->la_m, _offset_sort);
|
||||
HASH_ITER(hh, lf->lf_ar->la_m, lam, tmp) {
|
||||
li = lam->lam_input;
|
||||
if (li != NULL)
|
||||
STAILQ_INSERT_TAIL(&ld->ld_lilist, li,
|
||||
li_next);
|
||||
}
|
||||
} else {
|
||||
li = lf->lf_input;
|
||||
if (li != NULL)
|
||||
STAILQ_INSERT_TAIL(&ld->ld_lilist, li, li_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
ld_input_get_section_rawdata(struct ld *ld, struct ld_input_section *is)
|
||||
{
|
||||
Elf *e;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *d;
|
||||
struct ld_input *li;
|
||||
char *buf;
|
||||
int elferr;
|
||||
|
||||
li = is->is_input;
|
||||
e = li->li_elf;
|
||||
assert(e != NULL);
|
||||
|
||||
if ((scn = elf_getscn(e, is->is_index)) == NULL)
|
||||
ld_fatal(ld, "%s(%s): elf_getscn failed: %s", li->li_name,
|
||||
is->is_name, elf_errmsg(-1));
|
||||
|
||||
(void) elf_errno();
|
||||
if ((d = elf_rawdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
ld_warn(ld, "%s(%s): elf_rawdata failed: %s",
|
||||
li->li_name, is->is_name, elf_errmsg(elferr));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (d->d_buf == NULL || d->d_size == 0)
|
||||
return (NULL);
|
||||
|
||||
if ((buf = malloc(d->d_size)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
|
||||
memcpy(buf, d->d_buf, d->d_size);
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_load(struct ld *ld, struct ld_input *li)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_file *lf;
|
||||
struct ld_archive_member *lam;
|
||||
|
||||
if (li->li_file == NULL)
|
||||
return;
|
||||
|
||||
assert(li->li_elf == NULL);
|
||||
ls = &ld->ld_state;
|
||||
if (li->li_file != ls->ls_file) {
|
||||
if (ls->ls_file != NULL)
|
||||
ld_file_unload(ld, ls->ls_file);
|
||||
ld_file_load(ld, li->li_file);
|
||||
}
|
||||
lf = li->li_file;
|
||||
if (lf->lf_ar != NULL) {
|
||||
assert(li->li_lam != NULL);
|
||||
lam = li->li_lam;
|
||||
if (elf_rand(lf->lf_elf, lam->lam_off) != lam->lam_off)
|
||||
ld_fatal(ld, "%s: elf_rand: %s", lf->lf_name,
|
||||
elf_errmsg(-1));
|
||||
if ((li->li_elf = elf_begin(-1, ELF_C_READ, lf->lf_elf)) ==
|
||||
NULL)
|
||||
ld_fatal(ld, "%s: elf_begin: %s", lf->lf_name,
|
||||
elf_errmsg(-1));
|
||||
} else
|
||||
li->li_elf = lf->lf_elf;
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_unload(struct ld *ld, struct ld_input *li)
|
||||
{
|
||||
struct ld_file *lf;
|
||||
|
||||
(void) ld;
|
||||
|
||||
if (li->li_file == NULL)
|
||||
return;
|
||||
|
||||
assert(li->li_elf != NULL);
|
||||
lf = li->li_file;
|
||||
if (lf->lf_ar != NULL)
|
||||
(void) elf_end(li->li_elf);
|
||||
li->li_elf = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_init_sections(struct ld *ld, struct ld_input *li, Elf *e)
|
||||
{
|
||||
struct ld_input_section *is;
|
||||
struct ld_section_group *sg;
|
||||
Elf_Scn *scn, *_scn;
|
||||
Elf_Data *d, *_d;
|
||||
char *name;
|
||||
GElf_Shdr sh;
|
||||
GElf_Sym sym;
|
||||
size_t shstrndx, strndx, ndx;
|
||||
int elferr;
|
||||
|
||||
_d = NULL;
|
||||
strndx = 0;
|
||||
|
||||
if (elf_getshdrnum(e, &li->li_shnum) < 0)
|
||||
ld_fatal(ld, "%s: elf_getshdrnum: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Allocate one more pseudo section to hold common symbols */
|
||||
li->li_shnum++;
|
||||
|
||||
assert(li->li_is == NULL);
|
||||
if ((li->li_is = calloc(li->li_shnum, sizeof(*is))) == NULL)
|
||||
ld_fatal_std(ld, "%s: calloc: %s", li->li_name);
|
||||
|
||||
if (elf_getshdrstrndx(e, &shstrndx) < 0)
|
||||
ld_fatal(ld, "%s: elf_getshdrstrndx: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
(void) elf_errno();
|
||||
scn = NULL;
|
||||
while ((scn = elf_nextscn(e, scn)) != NULL) {
|
||||
if (gelf_getshdr(scn, &sh) != &sh)
|
||||
ld_fatal(ld, "%s: gelf_getshdr: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((name = elf_strptr(e, shstrndx, sh.sh_name)) == NULL)
|
||||
ld_fatal(ld, "%s: elf_strptr: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF)
|
||||
ld_fatal(ld, "%s: elf_ndxscn: %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
|
||||
if (ndx >= li->li_shnum - 1)
|
||||
ld_fatal(ld, "%s: section index of '%s' section is"
|
||||
" invalid", li->li_name, name);
|
||||
|
||||
is = &li->li_is[ndx];
|
||||
if ((is->is_name = strdup(name)) == NULL)
|
||||
ld_fatal_std(ld, "%s: calloc", li->li_name);
|
||||
is->is_off = sh.sh_offset;
|
||||
is->is_size = sh.sh_size;
|
||||
is->is_entsize = sh.sh_entsize;
|
||||
is->is_addr = sh.sh_addr;
|
||||
is->is_align = sh.sh_addralign;
|
||||
is->is_type = sh.sh_type;
|
||||
is->is_flags = sh.sh_flags;
|
||||
is->is_link = sh.sh_link;
|
||||
is->is_info = sh.sh_info;
|
||||
is->is_index = elf_ndxscn(scn);
|
||||
is->is_shrink = 0;
|
||||
is->is_input = li;
|
||||
|
||||
/*
|
||||
* Section groups are identified by their signatures.
|
||||
* A section group's signature is used to compare with the
|
||||
* the section groups that are already added. If a match
|
||||
* is found, the sections included in this section group
|
||||
* should be discarded.
|
||||
*
|
||||
* Note that since signatures are stored in the symbol
|
||||
* table, in order to handle that here we have to load
|
||||
* the symbol table earlier.
|
||||
*/
|
||||
if (is->is_type == SHT_GROUP) {
|
||||
is->is_discard = 1;
|
||||
if (_d == NULL) {
|
||||
_scn = elf_getscn(e, is->is_link);
|
||||
if (_scn == NULL) {
|
||||
ld_warn(ld, "%s: elf_getscn failed"
|
||||
" with the `sh_link' of group"
|
||||
" section %ju as index: %s",
|
||||
li->li_name, ndx, elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if (gelf_getshdr(_scn, &sh) != &sh) {
|
||||
ld_warn(ld, "%s: gelf_getshdr: %s",
|
||||
li->li_name, elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
strndx = sh.sh_link;
|
||||
(void) elf_errno();
|
||||
_d = elf_getdata(_scn, NULL);
|
||||
if (_d == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
ld_warn(ld, "%s: elf_getdata"
|
||||
" failed: %s", li->li_name,
|
||||
elf_errmsg(elferr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (gelf_getsym(_d, is->is_info, &sym) != &sym) {
|
||||
ld_warn(ld, "%s: gelf_getsym failed (section"
|
||||
" group signature): %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
if ((name = elf_strptr(e, strndx, sym.st_name)) ==
|
||||
NULL) {
|
||||
ld_warn(ld, "%s: elf_strptr failed (section"
|
||||
" group signature): %s", li->li_name,
|
||||
elf_errmsg(-1));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search the currently added section groups for the
|
||||
* signature. If found, this section group should not
|
||||
* be added and the sections it contains should be
|
||||
* discarded. If not found, we add this section group
|
||||
* to the set.
|
||||
*/
|
||||
HASH_FIND_STR(ld->ld_sg, name, sg);
|
||||
if (sg != NULL)
|
||||
_discard_section_group(ld, li, scn);
|
||||
else {
|
||||
if ((sg = calloc(1, sizeof(*sg))) == NULL)
|
||||
ld_fatal_std(ld, "%s: calloc",
|
||||
li->li_name);
|
||||
if ((sg->sg_name = strdup(name)) == NULL)
|
||||
ld_fatal_std(ld, "%s: strdup",
|
||||
li->li_name);
|
||||
HASH_ADD_KEYPTR(hh, ld->ld_sg, sg->sg_name,
|
||||
strlen(sg->sg_name), sg);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for informational sections which should not
|
||||
* be included in the output object, process them
|
||||
* and mark them as discarded if need.
|
||||
*/
|
||||
|
||||
if (strcmp(is->is_name, ".note.GNU-stack") == 0) {
|
||||
ld->ld_gen_gnustack = 1;
|
||||
if (is->is_flags & SHF_EXECINSTR)
|
||||
ld->ld_stack_exec = 1;
|
||||
is->is_discard = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* The content of input .eh_frame section is preloaded for
|
||||
* output .eh_frame optimization.
|
||||
*/
|
||||
if (strcmp(is->is_name, ".eh_frame") == 0) {
|
||||
if ((d = elf_rawdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
ld_warn(ld, "%s(%s): elf_rawdata "
|
||||
"failed: %s", li->li_name,
|
||||
is->is_name, elf_errmsg(elferr));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (d->d_buf == NULL || d->d_size == 0)
|
||||
continue;
|
||||
|
||||
if ((is->is_ehframe = malloc(d->d_size)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
|
||||
memcpy(is->is_ehframe, d->d_buf, d->d_size);
|
||||
is->is_ibuf = is->is_ehframe;
|
||||
}
|
||||
}
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
ld_fatal(ld, "%s: elf_nextscn failed: %s", li->li_name,
|
||||
elf_errmsg(elferr));
|
||||
}
|
||||
|
||||
void
|
||||
ld_input_alloc_common_symbol(struct ld *ld, struct ld_symbol *lsb)
|
||||
{
|
||||
struct ld_input *li;
|
||||
struct ld_input_section *is;
|
||||
|
||||
li = lsb->lsb_input;
|
||||
if (li == NULL)
|
||||
return; /* unlikely */
|
||||
|
||||
/*
|
||||
* Do not allocate memory for common symbols when the linker
|
||||
* creates a relocatable output object, unless option -d is
|
||||
* specified.
|
||||
*/
|
||||
if (ld->ld_reloc && !ld->ld_common_alloc)
|
||||
return;
|
||||
|
||||
is = &li->li_is[li->li_shnum - 1];
|
||||
if (is->is_name == NULL) {
|
||||
/*
|
||||
* Create a pseudo section named COMMON to keep track of
|
||||
* common symbols.
|
||||
*/
|
||||
if ((is->is_name = strdup("COMMON")) == NULL)
|
||||
ld_fatal_std(ld, "%s: calloc", li->li_name);
|
||||
is->is_off = 0;
|
||||
is->is_size = 0;
|
||||
is->is_entsize = 0;
|
||||
is->is_align = 1;
|
||||
is->is_type = SHT_NOBITS;
|
||||
is->is_flags = SHF_ALLOC | SHF_WRITE;
|
||||
is->is_link = 0;
|
||||
is->is_info = 0;
|
||||
is->is_index = SHN_COMMON;
|
||||
is->is_input = li;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate space for this symbol in the pseudo COMMON section.
|
||||
* Properly handle the alignment. (For common symbols, symbol
|
||||
* value stores the required alignment)
|
||||
*/
|
||||
if (lsb->lsb_value > is->is_align)
|
||||
is->is_align = lsb->lsb_value;
|
||||
is->is_size = roundup(is->is_size, is->is_align);
|
||||
lsb->lsb_value = is->is_size;
|
||||
is->is_size += lsb->lsb_size;
|
||||
}
|
||||
|
||||
static void
|
||||
_discard_section_group(struct ld *ld, struct ld_input *li, Elf_Scn *scn)
|
||||
{
|
||||
Elf_Data *d;
|
||||
uint32_t *w;
|
||||
int elferr, i;
|
||||
|
||||
(void) elf_errno();
|
||||
if ((d = elf_getdata(scn, NULL)) == NULL) {
|
||||
elferr = elf_errno();
|
||||
if (elferr != 0)
|
||||
ld_warn(ld, "%s: elf_getdata failed (section group):"
|
||||
" %s", li->li_name, elf_errmsg(elferr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->d_buf == NULL || d->d_size == 0)
|
||||
return;
|
||||
|
||||
w = d->d_buf;
|
||||
if ((*w & GRP_COMDAT) == 0)
|
||||
return;
|
||||
|
||||
for (i = 1; (size_t) i < d->d_size / 4; i++) {
|
||||
if (w[i] < li->li_shnum - 1)
|
||||
li->li_is[w[i]].is_discard = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static off_t
|
||||
_offset_sort(struct ld_archive_member *a, struct ld_archive_member *b)
|
||||
{
|
||||
|
||||
return (a->lam_off - b->lam_off);
|
||||
}
|
121
ld/ld_input.h
Normal file
121
ld/ld_input.h
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*-
|
||||
* Copyright (c) 2011-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_input.h 2960 2013-08-25 03:13:07Z kaiwang27 $
|
||||
*/
|
||||
|
||||
struct ld_reloc_entry_head;
|
||||
struct ld_ehframe_fde_head;
|
||||
|
||||
struct ld_section_group {
|
||||
char *sg_name;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
struct ld_input_section {
|
||||
char *is_name; /* section name */
|
||||
struct ld_input *is_input; /* containing input object */
|
||||
struct ld_output_section *is_output; /* containing output section */
|
||||
uint64_t is_off; /* section file offset */
|
||||
uint64_t is_reloff; /* relative offset in output section */
|
||||
uint64_t is_addr; /* section vma */
|
||||
uint64_t is_size; /* section file size */
|
||||
uint64_t is_shrink; /* section shrinked bytes */
|
||||
uint64_t is_entsize; /* seciton entry size */
|
||||
uint64_t is_align; /* section align */
|
||||
uint64_t is_type; /* section type */
|
||||
uint64_t is_flags; /* section flags */
|
||||
uint64_t is_link; /* section link */
|
||||
uint64_t is_info; /* section info */
|
||||
uint64_t is_index; /* section index */
|
||||
unsigned char is_discard; /* dicard section */
|
||||
unsigned char is_dynrel; /* section holds dynamic relocations */
|
||||
unsigned char is_pltrel; /* section holds PLT relocations */
|
||||
unsigned char is_refed; /* should not be gc'ed */
|
||||
unsigned char is_need_reloc; /* need apply relocation */
|
||||
void *is_data; /* output section data descriptor */
|
||||
void *is_ibuf; /* buffer for internal sections */
|
||||
void *is_ehframe; /* temp buffer for ehframe section. */
|
||||
struct ld_reloc_entry_head *is_reloc; /* list of relocation entries */
|
||||
uint64_t is_num_reloc; /* number of reloc entries */
|
||||
struct ld_input_section *is_tis; /* relocation target */
|
||||
struct ld_input_section *is_ris; /* relocation section */
|
||||
struct ld_ehframe_fde_head *is_fde; /* list of FDE */
|
||||
STAILQ_ENTRY(ld_input_section) is_next; /* next section */
|
||||
STAILQ_ENTRY(ld_input_section) is_gc_next; /* next gc search */
|
||||
UT_hash_handle hh; /* hash handle (internal section) */
|
||||
};
|
||||
|
||||
STAILQ_HEAD(ld_input_section_head, ld_input_section);
|
||||
|
||||
enum ld_input_type {
|
||||
LIT_UNKNOWN,
|
||||
LIT_RELOCATABLE,
|
||||
LIT_DSO,
|
||||
};
|
||||
|
||||
struct ld_symver_verdef_head;
|
||||
|
||||
struct ld_input {
|
||||
char *li_name; /* input object name */
|
||||
char *li_fullname; /* input object and archive name */
|
||||
char *li_soname; /* input object DT_SONAME. */
|
||||
Elf *li_elf; /* input object ELF descriptor */
|
||||
enum ld_input_type li_type; /* input object kind */
|
||||
struct ld_file *li_file; /* containing file */
|
||||
size_t li_shnum; /* num of sections in ELF object */
|
||||
struct ld_input_section *li_is; /* input section list */
|
||||
struct ld_input_section *li_istbl; /* internal section hash table */
|
||||
struct ld_archive_member *li_lam; /* archive member */
|
||||
struct ld_symbol_head *li_local; /* local symbol list */
|
||||
struct ld_symbol **li_symindex; /* symbol index table */
|
||||
size_t li_symnum; /* number of symbols */
|
||||
char **li_vername; /* version name array */
|
||||
size_t li_vername_sz; /* version name array size */
|
||||
uint16_t *li_versym; /* symbol version array */
|
||||
size_t li_versym_sz; /* symbol version array size */
|
||||
int li_dso_refcnt; /* symbol reference count (DSO) */
|
||||
struct ld_symver_verdef_head *li_verdef; /* version definition */
|
||||
STAILQ_ENTRY(ld_input) li_next; /* next input object */
|
||||
};
|
||||
|
||||
void ld_input_init(struct ld *);
|
||||
void ld_input_add_symbol(struct ld *, struct ld_input *,
|
||||
struct ld_symbol *);
|
||||
struct ld_input_section *ld_input_add_internal_section(struct ld *,
|
||||
const char *);
|
||||
struct ld_input_section *ld_input_find_internal_section(struct ld *,
|
||||
const char *);
|
||||
void ld_input_alloc_internal_section_buffers(struct ld *);
|
||||
struct ld_input *ld_input_alloc(struct ld *, struct ld_file *, const char *);
|
||||
void ld_input_alloc_common_symbol(struct ld *, struct ld_symbol *);
|
||||
void *ld_input_get_section_rawdata(struct ld *, struct ld_input_section *);
|
||||
void ld_input_cleanup(struct ld *);
|
||||
char *ld_input_get_fullname(struct ld *, struct ld_input *);
|
||||
void ld_input_init_sections(struct ld *, struct ld_input *, Elf *);
|
||||
void ld_input_link_objects(struct ld *);
|
||||
void ld_input_load(struct ld *, struct ld_input *);
|
||||
void ld_input_unload(struct ld *, struct ld_input *);
|
||||
uint64_t ld_input_reserve_ibuf(struct ld_input_section *, uint64_t);
|
1254
ld/ld_layout.c
Normal file
1254
ld/ld_layout.c
Normal file
File diff suppressed because it is too large
Load diff
33
ld/ld_layout.h
Normal file
33
ld/ld_layout.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*-
|
||||
* Copyright (c) 2011,2012 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_layout.h 2696 2012-11-24 17:12:24Z kaiwang27 $
|
||||
*/
|
||||
|
||||
void ld_layout_sections(struct ld *);
|
||||
off_t ld_layout_calc_header_size(struct ld *);
|
||||
struct ld_output_section *ld_layout_insert_output_section(struct ld *,
|
||||
const char *, uint64_t);
|
||||
void ld_layout_print_linkmap(struct ld *);
|
145
ld/ld_main.c
Normal file
145
ld/ld_main.c
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_arch.h"
|
||||
#include "ld_ehframe.h"
|
||||
#include "ld_options.h"
|
||||
#include "ld_reloc.h"
|
||||
#include "ld_script.h"
|
||||
#include "ld_file.h"
|
||||
#include "ld_input.h"
|
||||
#include "ld_layout.h"
|
||||
#include "ld_output.h"
|
||||
#include "ld_path.h"
|
||||
#include "ld_symbols.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_main.c 2959 2013-08-25 03:12:47Z kaiwang27 $");
|
||||
|
||||
static struct ld _ld;
|
||||
struct ld* ld = &_ld;
|
||||
|
||||
static void
|
||||
_init(void)
|
||||
{
|
||||
|
||||
if ((ld->ld_progname = ELFTC_GETPROGNAME()) == NULL)
|
||||
ld->ld_progname = "ld";
|
||||
|
||||
/* Initialise libelf. */
|
||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
||||
ld_fatal(ld, "ELF library initialization failed: %s",
|
||||
elf_errmsg(-1));
|
||||
|
||||
/* Initialise internal data structure. */
|
||||
TAILQ_INIT(&ld->ld_lflist);
|
||||
STAILQ_INIT(&ld->ld_lilist);
|
||||
STAILQ_INIT(&ld->ld_state.ls_lplist);
|
||||
STAILQ_INIT(&ld->ld_state.ls_rplist);
|
||||
STAILQ_INIT(&ld->ld_state.ls_rllist);
|
||||
}
|
||||
|
||||
static void
|
||||
_cleanup(void)
|
||||
{
|
||||
|
||||
ld_script_cleanup(ld);
|
||||
ld_symbols_cleanup(ld);
|
||||
ld_path_cleanup(ld);
|
||||
ld_input_cleanup(ld);
|
||||
ld_file_cleanup(ld);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
|
||||
_init();
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
ld->ld_progname = basename(argv[0]);
|
||||
|
||||
ld_arch_init(ld);
|
||||
|
||||
restart:
|
||||
|
||||
/* The linker generate an executable by default */
|
||||
ld->ld_exec = 1;
|
||||
|
||||
ld_script_init(ld);
|
||||
|
||||
ld_options_parse(ld, argc, argv);
|
||||
|
||||
ld_output_early_init(ld);
|
||||
|
||||
ls->ls_arch_conflict = 0;
|
||||
ls->ls_first_elf_object = 1;
|
||||
|
||||
ld_input_init(ld);
|
||||
|
||||
ld_symbols_resolve(ld);
|
||||
|
||||
if (ls->ls_arch_conflict) {
|
||||
_cleanup();
|
||||
ls->ls_rerun = 1;
|
||||
goto restart;
|
||||
}
|
||||
|
||||
ld_reloc_load(ld);
|
||||
|
||||
/*
|
||||
* Perform section garbage collection if command line option
|
||||
* -gc-sections is specified. Perform deferred relocation scan
|
||||
* after garbage sections are found.
|
||||
*/
|
||||
if (ld->ld_gc) {
|
||||
ld_reloc_gc_sections(ld);
|
||||
ld_reloc_deferred_scan(ld);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for undefined symbols and allocate space for common
|
||||
* symbols. Copy relevant symbols to the dynamic symbol table
|
||||
* if the linker is performing a dyanmic linking.
|
||||
*/
|
||||
ld_symbols_scan(ld);
|
||||
|
||||
/* Create .eh_frame_hdr section. */
|
||||
if (ld->ld_ehframe_hdr)
|
||||
ld_ehframe_create_hdr(ld);
|
||||
|
||||
ld_output_init(ld);
|
||||
|
||||
ld_layout_sections(ld);
|
||||
|
||||
ld_output_create(ld);
|
||||
|
||||
_cleanup();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
507
ld/ld_options.c
Normal file
507
ld/ld_options.c
Normal file
|
@ -0,0 +1,507 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_file.h"
|
||||
#include "ld_path.h"
|
||||
#include "ld_script.h"
|
||||
#include "ld_symbols.h"
|
||||
#include "ld_options.h"
|
||||
#include "ld_output.h"
|
||||
|
||||
ELFTC_VCSID("$Id: ld_options.c 2926 2013-03-17 22:53:54Z kaiwang27 $");
|
||||
|
||||
/*
|
||||
* Support routines for parsing command line options.
|
||||
*/
|
||||
|
||||
static const char *ld_short_opts =
|
||||
"b:c:de:Ef:Fgh:iI:l:L:m:MnNo:O::qrR:sStT:xXyY:u:vV()";
|
||||
|
||||
static struct ld_option ld_opts[] = {
|
||||
{"aarchive", KEY_STATIC, ONE_DASH, NO_ARG},
|
||||
{"adefault", KEY_DYNAMIC, ONE_DASH, NO_ARG},
|
||||
{"ashared", KEY_DYNAMIC, ONE_DASH, NO_ARG},
|
||||
{"accept-unknown-input-arch", KEY_ACCEPT_UNKNOWN, ANY_DASH, NO_ARG},
|
||||
{"allow-multiple-definition", KEY_Z_MULDEFS, ANY_DASH, NO_ARG},
|
||||
{"allow-shlib-undefined", KEY_ALLOW_SHLIB_UNDEF, ANY_DASH, NO_ARG},
|
||||
{"assert", KEY_ASSERT, ANY_DASH, NO_ARG},
|
||||
{"as-needed", KEY_AS_NEEDED, ANY_DASH, NO_ARG},
|
||||
{"auxiliary", 'f', ANY_DASH, REQ_ARG},
|
||||
{"build-id", KEY_BUILD_ID, ANY_DASH, OPT_ARG},
|
||||
{"call_shared", KEY_DYNAMIC, ONE_DASH, NO_ARG},
|
||||
{"check-sections", KEY_CHECK_SECTIONS, ANY_DASH, NO_ARG},
|
||||
{"cref", KEY_CREF, ANY_DASH, NO_ARG},
|
||||
{"defsym", KEY_DEFSYM, ANY_DASH, REQ_ARG},
|
||||
{"demangle", KEY_DEMANGLE, ANY_DASH, OPT_ARG},
|
||||
{"dc", 'd', ONE_DASH, NO_ARG},
|
||||
{"dp", 'd', ONE_DASH, NO_ARG},
|
||||
{"disable-new-dtags", KEY_DISABLE_NEW_DTAGS, ANY_DASH, NO_ARG},
|
||||
{"discard-all", 'x', ANY_DASH, NO_ARG},
|
||||
{"discard-locals", 'X', ANY_DASH, NO_ARG},
|
||||
{"dn", KEY_STATIC, ONE_DASH, NO_ARG},
|
||||
{"dy", KEY_DYNAMIC, ONE_DASH, NO_ARG},
|
||||
{"dynamic-linker", 'I', ANY_DASH, REQ_ARG},
|
||||
{"end-group", ')', ANY_DASH, NO_ARG},
|
||||
{"entry", 'e', ANY_DASH, REQ_ARG},
|
||||
{"error-unresolved-symbols", KEY_ERR_UNRESOLVE_SYM, ANY_DASH, NO_ARG},
|
||||
{"export-dynamic", 'E', ANY_DASH, NO_ARG},
|
||||
{"eh-frame-hdr", KEY_EH_FRAME_HDR, ANY_DASH, NO_ARG},
|
||||
{"emit-relocs", 'q', ANY_DASH, NO_ARG},
|
||||
{"emulation", 'm', ANY_DASH, REQ_ARG},
|
||||
{"enable-new-dtags", KEY_ENABLE_NEW_DTAGS, ANY_DASH, NO_ARG},
|
||||
{"fatal-warnings", KEY_FATAL_WARNINGS, ANY_DASH, NO_ARG},
|
||||
{"filter", 'F', ANY_DASH, NO_ARG},
|
||||
{"fini", KEY_FINI, ANY_DASH, NO_ARG},
|
||||
{"format", 'b', ANY_DASH, REQ_ARG},
|
||||
{"gc-sections", KEY_GC_SECTIONS, ANY_DASH, NO_ARG},
|
||||
{"hash-style", KEY_HASH_STYLE, ANY_DASH, REQ_ARG},
|
||||
{"help", KEY_HELP, ANY_DASH, NO_ARG},
|
||||
{"init", KEY_INIT, ANY_DASH, REQ_ARG},
|
||||
{"just-symbols", 'R', ANY_DASH, REQ_ARG},
|
||||
{"library", 'l', ANY_DASH, REQ_ARG},
|
||||
{"library-path", 'L', ANY_DASH, REQ_ARG},
|
||||
{"mri-script", 'c', ANY_DASH, REQ_ARG},
|
||||
{"nmagic", 'n', ANY_DASH, NO_ARG},
|
||||
{"nostdlib", KEY_NO_STDLIB, ONE_DASH, NO_ARG},
|
||||
{"no-accept-unknown-input-arch", KEY_NO_UNKNOWN, ANY_DASH, NO_ARG},
|
||||
{"no-allow-shlib-undefined", KEY_NO_SHLIB_UNDEF, ANY_DASH, NO_ARG},
|
||||
{"no-as-needed", KEY_NO_AS_NEEDED, ANY_DASH, NO_ARG},
|
||||
{"no-check-sections", KEY_NO_CHECK_SECTIONS, ANY_DASH, NO_ARG},
|
||||
{"no-define-common", KEY_NO_DEFINE_COMMON, ANY_DASH, NO_ARG},
|
||||
{"no-demangle", KEY_NO_DEMANGLE, ANY_DASH, OPT_ARG},
|
||||
{"no-gc-sections", KEY_NO_GC_SECTIONS, ANY_DASH, NO_ARG},
|
||||
{"no-keep-memorg", KEY_NO_KEEP_MEMORY, ANY_DASH, NO_ARG},
|
||||
{"no-omagic", KEY_NO_OMAGIC, ANY_DASH, NO_ARG},
|
||||
{"no-print-gc-sections", KEY_NO_PRINT_GC_SECTIONS, ANY_DASH, NO_ARG},
|
||||
{"no-undefined", KEY_Z_DEFS, ANY_DASH, NO_ARG},
|
||||
{"no-undefined-version", KEY_NO_UNDEF_VERSION, ANY_DASH, NO_ARG},
|
||||
{"no-whole-archive", KEY_NO_WHOLE_ARCHIVE, ANY_DASH, NO_ARG},
|
||||
{"no-warn-mismatch", KEY_NO_WARN_MISMATCH, ANY_DASH, NO_ARG},
|
||||
{"non_shared", KEY_STATIC, ONE_DASH, NO_ARG},
|
||||
{"oformat", KEY_OFORMAT, TWO_DASH, REQ_ARG},
|
||||
{"omagic", 'N', TWO_DASH, NO_ARG},
|
||||
{"output", 'o', TWO_DASH, REQ_ARG},
|
||||
{"pic-executable", KEY_PIE, ANY_DASH, NO_ARG},
|
||||
{"pie", KEY_PIE, ONE_DASH, NO_ARG},
|
||||
{"print-gc-sections", KEY_PRINT_GC_SECTIONS, ANY_DASH, NO_ARG},
|
||||
{"print-map", 'M', ANY_DASH, NO_ARG},
|
||||
{"qmagic", KEY_QMAGIC, ANY_DASH, NO_ARG},
|
||||
{"relax", KEY_RELAX, ANY_DASH, NO_ARG},
|
||||
{"relocatable", 'r', ANY_DASH, NO_ARG},
|
||||
{"retain-symbols-file", KEY_RETAIN_SYM_FILE, ANY_DASH, REQ_ARG},
|
||||
{"rpath", KEY_RPATH, ANY_DASH, REQ_ARG},
|
||||
{"rpath-link", KEY_RPATH_LINK, ANY_DASH, REQ_ARG},
|
||||
{"runpath", KEY_RUNPATH, ANY_DASH, REQ_ARG},
|
||||
{"script", 'T', ANY_DASH, REQ_ARG},
|
||||
{"section-start", KEY_SECTION_START, ANY_DASH, REQ_ARG},
|
||||
{"shared", KEY_SHARED, ANY_DASH, NO_ARG},
|
||||
{"soname", 'h', ONE_DASH, REQ_ARG},
|
||||
{"sort-common", KEY_SORT_COMMON, ANY_DASH, NO_ARG},
|
||||
{"split-by-file", KEY_SPLIT_BY_FILE, ANY_DASH, REQ_ARG},
|
||||
{"split-by-reloc", KEY_SPLIT_BY_RELOC, ANY_DASH, REQ_ARG},
|
||||
{"start-group", '(', ANY_DASH, NO_ARG},
|
||||
{"stats", KEY_STATS, ANY_DASH, NO_ARG},
|
||||
{"static", KEY_STATIC, ONE_DASH, NO_ARG},
|
||||
{"strip-all", 's', ANY_DASH, NO_ARG},
|
||||
{"strip-debug", 'S', ANY_DASH, NO_ARG},
|
||||
{"trace", 't', ANY_DASH, NO_ARG},
|
||||
{"trace_symbol", 'y', ANY_DASH, NO_ARG},
|
||||
{"traditional-format", KEY_TRADITIONAL_FORMAT, ANY_DASH, NO_ARG},
|
||||
{"undefined", 'u', ANY_DASH, REQ_ARG},
|
||||
{"unique", KEY_UNIQUE, ANY_DASH, OPT_ARG},
|
||||
{"unresolved-symbols", KEY_UNRESOLVED_SYMBOLS, ANY_DASH, REQ_ARG},
|
||||
{"verbose" , 'v', ANY_DASH, NO_ARG},
|
||||
{"version", KEY_VERSION, ANY_DASH, NO_ARG},
|
||||
{"version-script", KEY_VERSION_SCRIPT, ANY_DASH, REQ_ARG},
|
||||
{"warn-common", KEY_WARN_COMMON, ANY_DASH, NO_ARG},
|
||||
{"warn-constructors", KEY_WARN_CONSTRUCTORS, ANY_DASH, NO_ARG},
|
||||
{"warn-multiple-gp", KEY_WARN_MULTIPLE_GP, ANY_DASH, NO_ARG},
|
||||
{"warn-once", KEY_WARN_ONCE, ANY_DASH, NO_ARG},
|
||||
{"warn-section-align", KEY_WARN_SECTION_ALIGN, ANY_DASH, NO_ARG},
|
||||
{"warn-shared-textrel", KEY_WARN_SHARED_TEXTREL, ANY_DASH, NO_ARG},
|
||||
{"warn-unresolved-symbols", KEY_WARN_UNRESOLVE_SYM, ANY_DASH, NO_ARG},
|
||||
{"whole_archive", KEY_WHOLE_ARCHIVE, ANY_DASH, NO_ARG},
|
||||
{"wrap", KEY_WRAP, ANY_DASH, REQ_ARG},
|
||||
{"EB", KEY_EB, ONE_DASH, NO_ARG},
|
||||
{"EL", KEY_EL, ONE_DASH, NO_ARG},
|
||||
{"Map", KEY_MAP, ONE_DASH, REQ_ARG},
|
||||
{"Qy", KEY_QY, ONE_DASH, NO_ARG},
|
||||
{"Tbss", KEY_TBSS, ONE_DASH, REQ_ARG},
|
||||
{"Tdata", KEY_TDATA, ONE_DASH, REQ_ARG},
|
||||
{"Ttext", KEY_TTEXT, ONE_DASH, REQ_ARG},
|
||||
{"Ur", KEY_UR, ONE_DASH, NO_ARG},
|
||||
{NULL, 0, 0, 0},
|
||||
};
|
||||
|
||||
static struct ld_option ld_opts_B[] = {
|
||||
{"shareable", KEY_SHARED, ONE_DASH, NO_ARG},
|
||||
{"static", KEY_STATIC, ONE_DASH, NO_ARG},
|
||||
{"dynamic", KEY_DYNAMIC, ONE_DASH, NO_ARG},
|
||||
{"group", KEY_GROUP, ONE_DASH, NO_ARG},
|
||||
{"symbolic", KEY_SYMBOLIC, ONE_DASH, NO_ARG},
|
||||
{"symbolic_functions", KEY_SYMBOLIC_FUNC, ONE_DASH, NO_ARG},
|
||||
};
|
||||
|
||||
static struct ld_option ld_opts_z[] = {
|
||||
{"nodefaultlib", KEY_Z_NO_DEFAULT_LIB, ONE_DASH, NO_ARG},
|
||||
{"allextract", KEY_WHOLE_ARCHIVE, ONE_DASH, NO_ARG},
|
||||
{"defaultextract", KEY_Z_DEFAULT_EXTRACT, ONE_DASH, NO_ARG},
|
||||
{"weakextract", KEY_Z_WEAK_EXTRACT, ONE_DASH, NO_ARG},
|
||||
{"muldefs", KEY_Z_MULDEFS, ONE_DASH, NO_ARG},
|
||||
{"defs", KEY_Z_DEFS, ONE_DASH, NO_ARG},
|
||||
{"execstack", KEY_Z_EXEC_STACK, ONE_DASH, NO_ARG},
|
||||
{"nodefs", KEY_Z_NO_DEFS, ONE_DASH, NO_ARG},
|
||||
{"origin", KEY_Z_ORIGIN, ONE_DASH, NO_ARG},
|
||||
{"now", KEY_Z_NOW, ONE_DASH, NO_ARG},
|
||||
{"nodelete", KEY_Z_NO_DELETE, ONE_DASH, NO_ARG},
|
||||
{"initfirst", KEY_Z_INIT_FIRST, ONE_DASH, NO_ARG},
|
||||
{"lazyload", KEY_Z_LAZYLOAD, ONE_DASH, NO_ARG},
|
||||
{"noexecstack", KEY_Z_NO_EXEC_STACK, ONE_DASH, NO_ARG},
|
||||
{"nodlopen", KEY_Z_NO_DLOPEN, ONE_DASH, NO_ARG},
|
||||
{"nolazyload", KEY_Z_NO_LAZYLOAD, ONE_DASH, NO_ARG},
|
||||
{"ignore", KEY_Z_IGNORE, ONE_DASH, NO_ARG},
|
||||
{"record", KEY_Z_RECORD, ONE_DASH, NO_ARG},
|
||||
{"systemlibrary", KEY_Z_SYSTEM_LIBRARY, ONE_DASH, NO_ARG},
|
||||
};
|
||||
|
||||
static void _copy_optarg(struct ld *ld, char **dst, char *src);
|
||||
static void _process_options(struct ld *ld, int key, char *arg);
|
||||
static int _parse_long_options(struct ld *, struct ld_option *, int,
|
||||
int, char **, char *, enum ld_dash);
|
||||
static void _print_version(struct ld *ld);
|
||||
|
||||
void
|
||||
ld_options_parse(struct ld* ld, int argc, char **argv)
|
||||
{
|
||||
enum ld_dash d;
|
||||
char *p, *p0, *oli;
|
||||
int ac, ac0;
|
||||
|
||||
ac = 1;
|
||||
|
||||
while (ac < argc) {
|
||||
p = argv[ac];
|
||||
if (*p != '-' || p[1] == '\0') {
|
||||
_process_options(ld, KEY_FILE, p);
|
||||
ac++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*++p == '-') {
|
||||
if (p[1] == '\0') {
|
||||
/* Option --. Ignore the rest of options. */
|
||||
return;
|
||||
}
|
||||
p++;
|
||||
d = TWO_DASH;
|
||||
} else {
|
||||
d = ONE_DASH;
|
||||
if (*p == 'B' || *p == 'z') {
|
||||
ac0 = ac;
|
||||
if (*(p0 = p + 1) == '\0')
|
||||
p0 = argv[++ac0];
|
||||
ac = _parse_long_options(ld,
|
||||
*p == 'B' ? ld_opts_B : ld_opts_z,
|
||||
ac0, argc, argv, p0, d);
|
||||
if (ac > 0)
|
||||
continue;
|
||||
ld_fatal(ld, "unrecognized options -%c: %s",
|
||||
*p, p0);
|
||||
}
|
||||
}
|
||||
|
||||
ac0 = _parse_long_options(ld, ld_opts, ac, argc, argv, p, d);
|
||||
if (ac0 > 0) {
|
||||
ac = ac0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (d == TWO_DASH)
|
||||
ld_fatal(ld, "unrecognized option %s", p);
|
||||
|
||||
/*
|
||||
* Search short options.
|
||||
*/
|
||||
while (*p != '\0') {
|
||||
if ((oli = strchr(ld_short_opts, *p)) == NULL)
|
||||
ld_fatal(ld, "unrecognized option -%c", *p);
|
||||
if (*++oli != ':') {
|
||||
_process_options(ld, *p++, NULL);
|
||||
continue;
|
||||
}
|
||||
if (p[1] != '\0')
|
||||
_process_options(ld, *p, &p[1]);
|
||||
else if (oli[1] != ':') {
|
||||
if (++ac >= argc)
|
||||
ld_fatal(ld, "require arg for"
|
||||
" option -%c", *p);
|
||||
_process_options(ld, *p, argv[ac]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ac++;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_parse_long_options(struct ld *ld, struct ld_option *opts, int ac,
|
||||
int argc, char **argv, char *opt, enum ld_dash dash)
|
||||
{
|
||||
char *equal;
|
||||
size_t av_len;
|
||||
int i, match;
|
||||
|
||||
if ((equal = strchr(opt, '=')) != NULL) {
|
||||
av_len = equal - opt;
|
||||
equal++;
|
||||
if (*equal == '\0')
|
||||
ld_fatal(ld, "no argument after =");
|
||||
} else
|
||||
av_len = strlen(opt);
|
||||
|
||||
match = 0;
|
||||
for (i = 0; opts[i].lo_long != NULL; i++) {
|
||||
if (opts[i].lo_dash != ANY_DASH && opts[i].lo_dash != dash)
|
||||
continue;
|
||||
if (strlen(opts[i].lo_long) == av_len &&
|
||||
!strncmp(opt, opts[i].lo_long, av_len)) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
return (-1);
|
||||
|
||||
switch (opts[i].lo_arg) {
|
||||
case NO_ARG:
|
||||
if (equal != NULL) {
|
||||
ld_fatal(ld, "option %s does not accept argument",
|
||||
opts[i].lo_long);
|
||||
}
|
||||
_process_options(ld, opts[i].lo_key, NULL);
|
||||
break;
|
||||
case REQ_ARG:
|
||||
if (equal != NULL)
|
||||
_process_options(ld, opts[i].lo_key, equal);
|
||||
else {
|
||||
if (++ac >= argc)
|
||||
ld_fatal(ld, "require arg for option %s",
|
||||
opts[i].lo_long);
|
||||
_process_options(ld, opts[i].lo_key, argv[ac]);
|
||||
}
|
||||
break;
|
||||
case OPT_ARG:
|
||||
_process_options(ld, opts[i].lo_key, equal);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
return (++ac);
|
||||
}
|
||||
|
||||
static void
|
||||
_process_options(struct ld *ld, int key, char *arg)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
|
||||
assert(ld != NULL);
|
||||
ls = &ld->ld_state;
|
||||
|
||||
switch (key) {
|
||||
case 'b':
|
||||
ls->ls_itgt = elftc_bfd_find_target(arg);
|
||||
if (ls->ls_itgt == NULL)
|
||||
ld_fatal(ld, "invalid BFD target `%s'", arg);
|
||||
break;
|
||||
case 'd':
|
||||
ld->ld_common_alloc = 1;
|
||||
break;
|
||||
case 'e':
|
||||
_copy_optarg(ld, &ld->ld_entry, arg);
|
||||
break;
|
||||
case 'h':
|
||||
_copy_optarg(ld, &ld->ld_soname, arg);
|
||||
break;
|
||||
case 'I':
|
||||
_copy_optarg(ld, &ld->ld_interp, arg);
|
||||
break;
|
||||
case 'l':
|
||||
ld_path_search_library(ld, arg);
|
||||
break;
|
||||
case 'L':
|
||||
ld_path_add(ld, arg, LPT_L);
|
||||
break;
|
||||
case 'M':
|
||||
ld->ld_print_linkmap = 1;
|
||||
break;
|
||||
case 'o':
|
||||
_copy_optarg(ld, &ld->ld_output_file, arg);
|
||||
break;
|
||||
case 'q':
|
||||
ld->ld_emit_reloc = 1;
|
||||
break;
|
||||
case 'r':
|
||||
ld->ld_reloc = 1;
|
||||
break;
|
||||
case 'T':
|
||||
ld_script_parse(arg);
|
||||
break;
|
||||
case 'u':
|
||||
ld_symbols_add_extern(ld, arg);
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
_print_version(ld);
|
||||
break;
|
||||
case '(':
|
||||
ls->ls_group_level++;
|
||||
if (ls->ls_group_level > LD_MAX_NESTED_GROUP)
|
||||
ld_fatal(ld, "too many nested archive groups");
|
||||
break;
|
||||
case ')':
|
||||
ls->ls_group_level--;
|
||||
break;
|
||||
case KEY_AS_NEEDED:
|
||||
ls->ls_as_needed = 1;
|
||||
break;
|
||||
case KEY_DYNAMIC:
|
||||
ls->ls_static = 0;
|
||||
break;
|
||||
case KEY_EH_FRAME_HDR:
|
||||
ld->ld_ehframe_hdr = 1;
|
||||
break;
|
||||
case KEY_GC_SECTIONS:
|
||||
ld->ld_gc = 1;
|
||||
break;
|
||||
case KEY_NO_AS_NEEDED:
|
||||
ls->ls_as_needed = 0;
|
||||
break;
|
||||
case KEY_NO_DEFINE_COMMON:
|
||||
ld->ld_common_no_alloc = 1;
|
||||
break;
|
||||
case KEY_NO_GC_SECTIONS:
|
||||
ld->ld_gc = 0;
|
||||
break;
|
||||
case KEY_NO_PRINT_GC_SECTIONS:
|
||||
ld->ld_gc_print = 0;
|
||||
break;
|
||||
case KEY_NO_WHOLE_ARCHIVE:
|
||||
ls->ls_whole_archive = 0;
|
||||
break;
|
||||
case KEY_OFORMAT:
|
||||
ld_output_format(ld, arg, arg, arg);
|
||||
break;
|
||||
case KEY_PIE:
|
||||
ld->ld_exec = 0;
|
||||
ld->ld_pie = 1;
|
||||
ld->ld_dynamic_link = 1;
|
||||
break;
|
||||
case KEY_PRINT_GC_SECTIONS:
|
||||
ld->ld_gc_print = 1;
|
||||
break;
|
||||
case KEY_RPATH:
|
||||
ld_path_add_multiple(ld, arg, LPT_RPATH);
|
||||
break;
|
||||
case KEY_RPATH_LINK:
|
||||
ld_path_add_multiple(ld, arg, LPT_RPATH_LINK);
|
||||
break;
|
||||
case KEY_SHARED:
|
||||
ld->ld_exec = 0;
|
||||
ld->ld_dso = 1;
|
||||
ld->ld_dynamic_link = 1;
|
||||
break;
|
||||
case KEY_STATIC:
|
||||
ls->ls_static = 1;
|
||||
break;
|
||||
case KEY_WHOLE_ARCHIVE:
|
||||
ls->ls_whole_archive = 1;
|
||||
break;
|
||||
case KEY_FILE:
|
||||
ld_file_add(ld, arg, LFT_UNKNOWN);
|
||||
break;
|
||||
case KEY_VERSION_SCRIPT:
|
||||
ld_script_parse(arg);
|
||||
break;
|
||||
case KEY_Z_EXEC_STACK:
|
||||
ld->ld_gen_gnustack = 1;
|
||||
ld->ld_stack_exec_set = 1;
|
||||
ld->ld_stack_exec = 1;
|
||||
break;
|
||||
case KEY_Z_NO_EXEC_STACK:
|
||||
ld->ld_gen_gnustack = 1;
|
||||
ld->ld_stack_exec_set = 1;
|
||||
ld->ld_stack_exec = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_print_version(struct ld *ld)
|
||||
{
|
||||
|
||||
(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version());
|
||||
ld->ld_print_version = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
_copy_optarg(struct ld *ld, char **dst, char *src)
|
||||
{
|
||||
|
||||
if (*dst != NULL)
|
||||
free(*dst);
|
||||
if ((*dst = strdup(src)) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
}
|
||||
|
||||
struct ld_wildcard *
|
||||
ld_wildcard_alloc(struct ld *ld)
|
||||
{
|
||||
struct ld_wildcard *lw;
|
||||
|
||||
if ((lw = calloc(1, sizeof(*lw))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
return (lw);
|
||||
}
|
||||
|
||||
void
|
||||
ld_wildcard_free(void *ptr)
|
||||
{
|
||||
struct ld_wildcard *lw;
|
||||
|
||||
lw = ptr;
|
||||
if (lw == NULL)
|
||||
return;
|
||||
|
||||
free(lw->lw_name);
|
||||
free(lw);
|
||||
}
|
161
ld/ld_options.h
Normal file
161
ld/ld_options.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_options.h 2894 2013-01-15 23:05:24Z kaiwang27 $
|
||||
*/
|
||||
|
||||
enum ld_dash {
|
||||
ONE_DASH,
|
||||
TWO_DASH,
|
||||
ANY_DASH
|
||||
};
|
||||
|
||||
enum ld_arg {
|
||||
NO_ARG,
|
||||
REQ_ARG,
|
||||
OPT_ARG
|
||||
};
|
||||
|
||||
enum ld_key {
|
||||
KEY_ACCEPT_UNKNOWN = 0x10000,
|
||||
KEY_ALLOW_SHLIB_UNDEF,
|
||||
KEY_ASSERT,
|
||||
KEY_AS_NEEDED,
|
||||
KEY_BUILD_ID,
|
||||
KEY_CHECK_SECTIONS,
|
||||
KEY_CREF,
|
||||
KEY_DEFSYM,
|
||||
KEY_DEMANGLE,
|
||||
KEY_DISABLE_NEW_DTAGS,
|
||||
KEY_DYNAMIC,
|
||||
KEY_EB,
|
||||
KEY_EL,
|
||||
KEY_EH_FRAME_HDR,
|
||||
KEY_ENABLE_NEW_DTAGS,
|
||||
KEY_ERR_UNRESOLVE_SYM,
|
||||
KEY_FATAL_WARNINGS,
|
||||
KEY_FINI,
|
||||
KEY_GC_SECTIONS,
|
||||
KEY_GROUP,
|
||||
KEY_HASH_STYLE,
|
||||
KEY_HELP,
|
||||
KEY_INIT,
|
||||
KEY_MAP,
|
||||
KEY_NO_AS_NEEDED,
|
||||
KEY_NO_CHECK_SECTIONS,
|
||||
KEY_NO_DEFINE_COMMON,
|
||||
KEY_NO_DEMANGLE,
|
||||
KEY_NO_GC_SECTIONS,
|
||||
KEY_NO_KEEP_MEMORY,
|
||||
KEY_NO_OMAGIC,
|
||||
KEY_NO_PRINT_GC_SECTIONS,
|
||||
KEY_NO_SHLIB_UNDEF,
|
||||
KEY_NO_STDLIB,
|
||||
KEY_NO_UNDEF_VERSION,
|
||||
KEY_NO_UNKNOWN,
|
||||
KEY_NO_WHOLE_ARCHIVE,
|
||||
KEY_NO_WARN_MISMATCH,
|
||||
KEY_RPATH,
|
||||
KEY_RPATH_LINK,
|
||||
KEY_RUNPATH,
|
||||
KEY_SECTION_START,
|
||||
KEY_OFORMAT,
|
||||
KEY_PIE,
|
||||
KEY_PRINT_GC_SECTIONS,
|
||||
KEY_QMAGIC,
|
||||
KEY_QY,
|
||||
KEY_RELAX,
|
||||
KEY_RETAIN_SYM_FILE,
|
||||
KEY_SHARED,
|
||||
KEY_SORT_COMMON,
|
||||
KEY_SPLIT_BY_FILE,
|
||||
KEY_SPLIT_BY_RELOC,
|
||||
KEY_STATIC,
|
||||
KEY_STATS,
|
||||
KEY_SYMBOLIC,
|
||||
KEY_SYMBOLIC_FUNC,
|
||||
KEY_TBSS,
|
||||
KEY_TDATA,
|
||||
KEY_TTEXT,
|
||||
KEY_TRADITIONAL_FORMAT,
|
||||
KEY_UNRESOLVED_SYMBOLS,
|
||||
KEY_UNIQUE,
|
||||
KEY_UR,
|
||||
KEY_VERSION,
|
||||
KEY_VERSION_SCRIPT,
|
||||
KEY_WARN_COMMON,
|
||||
KEY_WARN_CONSTRUCTORS,
|
||||
KEY_WARN_MULTIPLE_GP,
|
||||
KEY_WARN_ONCE,
|
||||
KEY_WARN_SECTION_ALIGN,
|
||||
KEY_WARN_SHARED_TEXTREL,
|
||||
KEY_WARN_UNRESOLVE_SYM,
|
||||
KEY_WHOLE_ARCHIVE,
|
||||
KEY_WRAP,
|
||||
KEY_Z_DEFAULT_EXTRACT,
|
||||
KEY_Z_DEFS,
|
||||
KEY_Z_EXEC_STACK,
|
||||
KEY_Z_IGNORE,
|
||||
KEY_Z_INIT_FIRST,
|
||||
KEY_Z_LAZYLOAD,
|
||||
KEY_Z_MULDEFS,
|
||||
KEY_Z_NOW,
|
||||
KEY_Z_NO_DEFAULT_LIB,
|
||||
KEY_Z_NO_DEFS,
|
||||
KEY_Z_NO_DELETE,
|
||||
KEY_Z_NO_DLOPEN,
|
||||
KEY_Z_NO_EXEC_STACK,
|
||||
KEY_Z_NO_LAZYLOAD,
|
||||
KEY_Z_ORIGIN,
|
||||
KEY_Z_RECORD,
|
||||
KEY_Z_SYSTEM_LIBRARY,
|
||||
KEY_Z_WEAK_EXTRACT,
|
||||
|
||||
KEY_FILE = 0x10000000,
|
||||
};
|
||||
|
||||
struct ld_option {
|
||||
const char *lo_long;
|
||||
int lo_key;
|
||||
enum ld_dash lo_dash;
|
||||
enum ld_arg lo_arg;
|
||||
};
|
||||
|
||||
enum ld_wildcard_sort {
|
||||
LWS_NONE,
|
||||
LWS_NAME,
|
||||
LWS_ALIGN,
|
||||
LWS_NAME_ALIGN,
|
||||
LWS_ALIGN_NAME,
|
||||
};
|
||||
|
||||
struct ld_wildcard {
|
||||
char *lw_name; /* wildcard */
|
||||
enum ld_wildcard_sort lw_sort; /* sort mode */
|
||||
};
|
||||
|
||||
void ld_options_parse(struct ld*, int, char **);
|
||||
struct ld_wildcard *ld_wildcard_alloc(struct ld *);
|
||||
void ld_wildcard_free(void *);
|
1154
ld/ld_output.c
Normal file
1154
ld/ld_output.c
Normal file
File diff suppressed because it is too large
Load diff
165
ld/ld_output.h
Normal file
165
ld/ld_output.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/*-
|
||||
* Copyright (c) 2011-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_output.h 2959 2013-08-25 03:12:47Z kaiwang27 $
|
||||
*/
|
||||
|
||||
enum ld_output_element_type {
|
||||
OET_ASSERT,
|
||||
OET_ASSIGN,
|
||||
OET_DATA,
|
||||
OET_ENTRY,
|
||||
OET_INPUT_SECTION_LIST,
|
||||
OET_KEYWORD,
|
||||
OET_OUTPUT_SECTION,
|
||||
OET_OVERLAY,
|
||||
OET_DATA_BUFFER,
|
||||
OET_SYMTAB,
|
||||
OET_STRTAB
|
||||
};
|
||||
|
||||
struct ld_output_element {
|
||||
enum ld_output_element_type oe_type; /* output element type */
|
||||
uint64_t oe_off; /* output element offset */
|
||||
void *oe_entry; /* output element */
|
||||
void *oe_islist; /* input section list */
|
||||
unsigned char oe_insec; /* element inside SECTIONS */
|
||||
STAILQ_ENTRY(ld_output_element) oe_next; /* next element */
|
||||
};
|
||||
|
||||
STAILQ_HEAD(ld_output_element_head, ld_output_element);
|
||||
|
||||
struct ld_output_data_buffer {
|
||||
uint8_t *odb_buf; /* point to data */
|
||||
uint64_t odb_size; /* buffer size */
|
||||
uint64_t odb_off; /* relative offset in output section */
|
||||
uint64_t odb_align; /* buffer alignment */
|
||||
uint64_t odb_type; /* buffer data type */
|
||||
};
|
||||
|
||||
struct ld_reloc_entry_head;
|
||||
struct ld_symbol;
|
||||
|
||||
struct ld_output_section {
|
||||
Elf_Scn *os_scn; /* output section descriptor */
|
||||
char *os_name; /* output section name */
|
||||
uint64_t os_addr; /* output section vma */
|
||||
uint64_t os_lma; /* output section lma */
|
||||
uint64_t os_off; /* output section offset */
|
||||
uint64_t os_size; /* output section size */
|
||||
uint64_t os_align; /* output section alignment */
|
||||
uint64_t os_flags; /* output section flags */
|
||||
uint64_t os_type; /* output section type */
|
||||
uint64_t os_entsize; /* output seciton entry size */
|
||||
uint64_t os_info_val; /* output section info */
|
||||
unsigned char os_empty; /* output section is empty */
|
||||
unsigned char os_dynrel; /* contains dynamic relocations */
|
||||
unsigned char os_pltrel; /* contains PLT relocations */
|
||||
unsigned char os_rel; /* contains normal relocations */
|
||||
unsigned char os_entsize_set; /* entsize is set */
|
||||
char *os_link; /* link to other output section */
|
||||
struct ld_symbol *os_secsym; /* assoicated STT_SECTION symbol */
|
||||
struct ld_output_section *os_info; /* info refer to other section */
|
||||
struct ld_output_section *os_r; /* relocation section */
|
||||
struct ld_script_sections_output *os_ldso;
|
||||
/* output section descriptor */
|
||||
struct ld_output_element *os_pe; /* parent element */
|
||||
struct ld_output_element_head os_e; /* list of child elements */
|
||||
struct ld_reloc_entry_head *os_reloc; /* list of relocations */
|
||||
uint64_t os_num_reloc; /* number of relocations */
|
||||
STAILQ_ENTRY(ld_output_section) os_next; /* next output section */
|
||||
UT_hash_handle hh; /* hash handle */
|
||||
};
|
||||
|
||||
STAILQ_HEAD(ld_output_section_head, ld_output_section);
|
||||
|
||||
struct ld_symver_verneed_head;
|
||||
|
||||
struct ld_output {
|
||||
int lo_fd; /* output file descriptor */
|
||||
Elf *lo_elf; /* output ELF descriptor */
|
||||
int lo_ec; /* output object elf class */
|
||||
int lo_endian; /* outout object endianess */
|
||||
int lo_osabi; /* output object osabi */
|
||||
int lo_soname_nameindex; /* string index for DT_SONAME */
|
||||
int lo_rpath_nameindex; /* string index for DT_RPATH */
|
||||
unsigned lo_phdr_num; /* num of phdrs */
|
||||
unsigned lo_phdr_note; /* create PT_NOTE */
|
||||
unsigned lo_dso_needed; /* num of DSO referenced */
|
||||
unsigned lo_version_index; /* current symver index */
|
||||
unsigned lo_verdef_num; /* num of verdef entries */
|
||||
unsigned lo_verneed_num; /* num of verneed entries */
|
||||
unsigned lo_rel_plt_type; /* type of PLT relocation */
|
||||
unsigned lo_rel_dyn_type; /* type of dynamic relocation */
|
||||
unsigned lo_fde_num; /* num of FDE in .eh_frame */
|
||||
uint64_t lo_shoff; /* section header table offset */
|
||||
uint64_t lo_tls_size; /* TLS segment size */
|
||||
uint64_t lo_tls_align; /* TLS segment align */
|
||||
uint64_t lo_tls_addr; /* TLS segment VMA */
|
||||
size_t lo_symtab_shndx; /* .symtab section index */
|
||||
UT_array *lo_dso_nameindex; /* array of DSO name indices */
|
||||
struct ld_symver_verneed_head *lo_vnlist; /* Verneed list */
|
||||
struct ld_output_element_head lo_oelist; /* output element list */
|
||||
struct ld_output_section_head lo_oslist; /* output section list */
|
||||
struct ld_output_section *lo_ostbl; /* output section hash table */
|
||||
struct ld_output_section *lo_interp; /* .interp section. */
|
||||
struct ld_output_section *lo_init; /* .init section */
|
||||
struct ld_output_section *lo_fini; /* .fini section */
|
||||
struct ld_output_section *lo_dynamic; /* .dynamic section. */
|
||||
struct ld_output_section *lo_dynsym; /* .dynsym section. */
|
||||
struct ld_output_section *lo_dynstr; /* .dynstr section. */
|
||||
struct ld_output_section *lo_hash; /* .hash section. */
|
||||
struct ld_output_section *lo_verdef; /* .gnu.version.d section */
|
||||
struct ld_output_section *lo_verneed; /* .gnu.version.r section */
|
||||
struct ld_output_section *lo_versym; /* .gnu.version section */
|
||||
struct ld_output_section *lo_gotplt; /* GOT(for PLT) section */
|
||||
struct ld_output_section *lo_plt; /* PLT section */
|
||||
struct ld_output_section *lo_rel_plt; /* PLT relocation section */
|
||||
struct ld_output_section *lo_rel_dyn; /* Dynamic relocation section */
|
||||
struct ld_output_section *lo_ehframe_hdr; /* .eh_frame_hdr section */
|
||||
struct ld_output_data_buffer *lo_dynamic_odb; /* .dynamic buffer */
|
||||
struct ld_output_data_buffer *lo_got_odb; /* GOT section data */
|
||||
struct ld_output_data_buffer *lo_plt_odb; /* PLT section data */
|
||||
struct ld_output_data_buffer *lo_rel_plt_odb; /* PLT reloc data */
|
||||
struct ld_output_data_buffer *lo_rel_dyn_odb; /* dynamic reloc data */
|
||||
};
|
||||
|
||||
struct ld_output_section *ld_output_alloc_section(struct ld *, const char *,
|
||||
struct ld_output_section *, struct ld_output_section *);
|
||||
void ld_output_create(struct ld *);
|
||||
struct ld_output_element *ld_output_create_element(struct ld *,
|
||||
struct ld_output_element_head *, enum ld_output_element_type, void *,
|
||||
struct ld_output_element *);
|
||||
struct ld_output_element *ld_output_create_section_element(struct ld *,
|
||||
struct ld_output_section *, enum ld_output_element_type, void *,
|
||||
struct ld_output_element *);
|
||||
void ld_output_create_elf_sections(struct ld *);
|
||||
void ld_output_create_string_table_section(struct ld *, const char *,
|
||||
struct ld_strtab *, Elf_Scn *);
|
||||
void ld_output_emit_gnu_stack_section(struct ld *);
|
||||
void ld_output_format(struct ld *, char *, char *, char *);
|
||||
void ld_output_early_init(struct ld *);
|
||||
void ld_output_init(struct ld *);
|
||||
void ld_output_write(struct ld *);
|
295
ld/ld_path.c
Normal file
295
ld/ld_path.c
Normal file
|
@ -0,0 +1,295 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_path.c 2930 2013-03-17 22:54:26Z kaiwang27 $
|
||||
*/
|
||||
|
||||
#include "ld.h"
|
||||
#include "ld_file.h"
|
||||
#include "ld_path.h"
|
||||
|
||||
static char *_search_file(struct ld *ld, const char *path, const char *file);
|
||||
|
||||
static char *
|
||||
_search_file(struct ld *ld, const char *path, const char *file)
|
||||
{
|
||||
struct dirent *dp;
|
||||
DIR *dirp;
|
||||
char *fp;
|
||||
|
||||
assert(path != NULL && file != NULL);
|
||||
|
||||
if ((dirp = opendir(path)) == NULL) {
|
||||
ld_warn(ld, "opendir failed: %s", strerror(errno));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
fp = NULL;
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (!strcmp(dp->d_name, file)) {
|
||||
if ((fp = malloc(PATH_MAX + 1)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
fp[0] = '\0';
|
||||
snprintf(fp, PATH_MAX + 1, "%s/%s", path, dp->d_name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
|
||||
return (fp);
|
||||
}
|
||||
|
||||
void
|
||||
ld_path_add(struct ld *ld, char *path, enum ld_path_type lpt)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_path *lp;
|
||||
|
||||
assert(ld != NULL && path != NULL);
|
||||
ls = &ld->ld_state;
|
||||
|
||||
if ((lp = calloc(1, sizeof(*lp))) == NULL)
|
||||
ld_fatal_std(ld, "calloc");
|
||||
|
||||
if ((lp->lp_path = strdup(path)) == NULL)
|
||||
ld_fatal_std(ld, "strdup");
|
||||
|
||||
switch (lpt) {
|
||||
case LPT_L:
|
||||
STAILQ_INSERT_TAIL(&ls->ls_lplist, lp, lp_next);
|
||||
break;
|
||||
case LPT_RPATH:
|
||||
STAILQ_INSERT_TAIL(&ls->ls_rplist, lp, lp_next);
|
||||
break;
|
||||
case LPT_RPATH_LINK:
|
||||
STAILQ_INSERT_TAIL(&ls->ls_rllist, lp, lp_next);
|
||||
break;
|
||||
default:
|
||||
ld_fatal(ld, "Internal: invalid path type %d", lpt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_path_add_multiple(struct ld *ld, char *str, enum ld_path_type lpt)
|
||||
{
|
||||
char *p;
|
||||
|
||||
while ((p = strsep(&str, ":")) != NULL) {
|
||||
if (*p != '\0')
|
||||
ld_path_add(ld, p, lpt);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_path_cleanup(struct ld *ld)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_path *lp, *_lp;
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
STAILQ_FOREACH_SAFE(lp, &ls->ls_lplist, lp_next, _lp) {
|
||||
STAILQ_REMOVE(&ls->ls_lplist, lp, ld_path, lp_next);
|
||||
free(lp->lp_path);
|
||||
free(lp);
|
||||
}
|
||||
|
||||
STAILQ_FOREACH_SAFE(lp, &ls->ls_rplist, lp_next, _lp) {
|
||||
STAILQ_REMOVE(&ls->ls_rplist, lp, ld_path, lp_next);
|
||||
free(lp->lp_path);
|
||||
free(lp);
|
||||
}
|
||||
|
||||
STAILQ_FOREACH_SAFE(lp, &ls->ls_rllist, lp_next, _lp) {
|
||||
STAILQ_REMOVE(&ls->ls_rllist, lp, ld_path, lp_next);
|
||||
free(lp->lp_path);
|
||||
free(lp);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
ld_path_join_rpath(struct ld *ld)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_path *lp;
|
||||
char *s;
|
||||
int len;
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
if (STAILQ_EMPTY(&ls->ls_rplist))
|
||||
return (NULL);
|
||||
|
||||
len = 0;
|
||||
STAILQ_FOREACH(lp, &ls->ls_rplist, lp_next)
|
||||
len += strlen(lp->lp_path) + 1;
|
||||
|
||||
if ((s = malloc(len)) == NULL)
|
||||
ld_fatal_std(ld, "malloc");
|
||||
|
||||
STAILQ_FOREACH(lp, &ls->ls_rplist, lp_next) {
|
||||
strcat(s, lp->lp_path);
|
||||
if (lp != STAILQ_LAST(&ls->ls_rplist, ld_path, lp_next))
|
||||
strcat(s, ":");
|
||||
}
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
void
|
||||
ld_path_search_file(struct ld *ld, struct ld_file *lf)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_path *lp;
|
||||
char *fp;
|
||||
int found;
|
||||
|
||||
assert(lf != NULL);
|
||||
ls = &ld->ld_state;
|
||||
|
||||
found = 0;
|
||||
STAILQ_FOREACH(lp, &ls->ls_lplist, lp_next) {
|
||||
if ((fp = _search_file(ld, lp->lp_path, lf->lf_name)) !=
|
||||
NULL) {
|
||||
free(lf->lf_name);
|
||||
lf->lf_name = fp;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
ld_fatal(ld, "cannot find %s", lf->lf_name);
|
||||
}
|
||||
|
||||
void
|
||||
ld_path_search_library(struct ld *ld, const char *name)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_path *lp;
|
||||
struct dirent *dp;
|
||||
DIR *dirp;
|
||||
char fp[PATH_MAX + 1], sfp[PATH_MAX + 1];
|
||||
size_t len;
|
||||
int found;
|
||||
|
||||
assert(ld != NULL && name != NULL);
|
||||
ls = &ld->ld_state;
|
||||
|
||||
len = strlen(name);
|
||||
found = 0;
|
||||
STAILQ_FOREACH(lp, &ls->ls_lplist, lp_next) {
|
||||
assert(lp->lp_path != NULL);
|
||||
if ((dirp = opendir(lp->lp_path)) == NULL) {
|
||||
ld_warn(ld, "opendir failed: %s", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
fp[0] = sfp[0] = '\0';
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (strncmp(dp->d_name, "lib", 3))
|
||||
continue;
|
||||
if (strncmp(name, &dp->d_name[3], len))
|
||||
continue;
|
||||
if (ls->ls_static == 0 &&
|
||||
!strcmp(&dp->d_name[len + 3], ".so")) {
|
||||
snprintf(fp, sizeof(fp), "%s/%s", lp->lp_path,
|
||||
dp->d_name);
|
||||
ld_file_add(ld, fp, LFT_DSO);
|
||||
(void) closedir(dirp);
|
||||
found = 1;
|
||||
goto done;
|
||||
} else if (*sfp == '\0' &&
|
||||
!strcmp(&dp->d_name[len + 3], ".a")) {
|
||||
snprintf(sfp, sizeof(sfp), "%s/%s", lp->lp_path,
|
||||
dp->d_name);
|
||||
if (ls->ls_static == 1) {
|
||||
ld_file_add(ld, sfp, LFT_ARCHIVE);
|
||||
(void) closedir(dirp);
|
||||
found = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
}
|
||||
done:
|
||||
if (!found) {
|
||||
if (ls->ls_static == 0 && *sfp != '\0') {
|
||||
ld_file_add(ld, sfp, LFT_ARCHIVE);
|
||||
} else
|
||||
ld_fatal(ld, "cannot find -l%s", name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ld_path_search_dso_needed(struct ld *ld, struct ld_file *lf, const char *name)
|
||||
{
|
||||
struct ld_state *ls;
|
||||
struct ld_path *lp;
|
||||
struct ld_file *_lf;
|
||||
char *fp;
|
||||
|
||||
ls = &ld->ld_state;
|
||||
|
||||
/*
|
||||
* First check if we've seen this shared library or if it's
|
||||
* already listed in the input file list.
|
||||
*/
|
||||
TAILQ_FOREACH(_lf, &ld->ld_lflist, lf_next) {
|
||||
if (!strcmp(_lf->lf_name, name) ||
|
||||
!strcmp(basename(_lf->lf_name), name))
|
||||
return;
|
||||
}
|
||||
|
||||
/* Search -rpath-link directories. */
|
||||
STAILQ_FOREACH(lp, &ls->ls_rllist, lp_next) {
|
||||
if ((fp = _search_file(ld, lp->lp_path, name)) != NULL)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Search -rpath directories. */
|
||||
STAILQ_FOREACH(lp, &ls->ls_rplist, lp_next) {
|
||||
if ((fp = _search_file(ld, lp->lp_path, name)) != NULL)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* TODO: search additional directories and environment variables. */
|
||||
|
||||
/* Search /lib and /usr/lib. */
|
||||
if ((fp = _search_file(ld, "/lib", name)) != NULL)
|
||||
goto done;
|
||||
if ((fp = _search_file(ld, "/usr/lib", name)) != NULL)
|
||||
goto done;
|
||||
|
||||
/* Not found. */
|
||||
ld_warn(ld, "cannot find needed shared library: %s", name);
|
||||
return;
|
||||
|
||||
done:
|
||||
ld_file_add_after(ld, fp, LFT_DSO, lf);
|
||||
free(fp);
|
||||
}
|
46
ld/ld_path.h
Normal file
46
ld/ld_path.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*-
|
||||
* Copyright (c) 2010-2013 Kai Wang
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: ld_path.h 2930 2013-03-17 22:54:26Z kaiwang27 $
|
||||
*/
|
||||
|
||||
enum ld_path_type {
|
||||
LPT_L,
|
||||
LPT_RPATH,
|
||||
LPT_RPATH_LINK,
|
||||
};
|
||||
|
||||
struct ld_path {
|
||||
char *lp_path;
|
||||
STAILQ_ENTRY(ld_path) lp_next;
|
||||
};
|
||||
|
||||
void ld_path_add(struct ld *, char *, enum ld_path_type);
|
||||
void ld_path_add_multiple(struct ld *, char *, enum ld_path_type);
|
||||
void ld_path_cleanup(struct ld *);
|
||||
char *ld_path_join_rpath(struct ld *);
|
||||
void ld_path_search_file(struct ld *, struct ld_file *);
|
||||
void ld_path_search_library(struct ld *, const char *);
|
||||
void ld_path_search_dso_needed(struct ld *, struct ld_file *, const char *);
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue