5 Commits

Author SHA1 Message Date
745732f9e0 works better, but weird failures 2018-03-25 23:02:18 +02:00
9b46824596 Create README.md 2018-03-25 23:02:18 +02:00
b08f83a54b Remove unncessary variable definitions 2018-03-25 23:02:18 +02:00
648fa467d6 ARM: Compile whole tree with clang.
Note: GCC is still the default compiler, to use clang do the following:

 $ BUILDVARS="" ./releasetools/arm_sdimage.sh
2018-03-25 23:02:17 +02:00
40308cd1ed ARM: Remove linker script for VM.
The linker script has been replaced by small adaptations to make sure
the required structures are aligned at runtime per hardware
requirements.

In some cases, the linker script failed to guarantee proper physical
addresses alignement.

This is important for page entries descriptors which are required to be
aligned as the MMU doesn't support unaligned accesses to those.

Change-Id: I3e22d3da102230be2534b4261e2c6c937e367de6
2018-03-25 23:02:17 +02:00
520 changed files with 182 additions and 47537 deletions

17
README.md Normal file
View File

@@ -0,0 +1,17 @@
# Build MINIX/arm with clang
It is now possible to build a full minix distribution for BeaglBone White/Black and BeagleBoardxM using clang instead of GCC.
This also add support to run the Kuya tests on ARM, which was not possible when GCC was used, because of problems in the C++ exception handling.
## Known Bugs
The following tests still fails:
1. 53: Division by zero does not trigger exceptions
2. 75: ru.tv_secs can't be zero (and is zero)
3. 85: hangs
4. isofs: Fails because of an out of memory condition
5. vnd: crash
6. Running two times the kyua tests in a row, without rebooting in between will lead to a mostly failed second run because of copy-on-write errors.

View File

@@ -81,6 +81,9 @@
./usr/include/arm/vm.h minix-comp
./usr/include/arm/vmparam.h minix-comp
./usr/include/arm/wchar_limits.h minix-comp
./usr/include/clang-3.6/arm_acle.h minix-comp llvm,llvmcmds
./usr/include/clang-3.6/arm_neon.h minix-comp llvm,llvmcmds
./usr/include/clang-3.6/stdatomic.h minix-comp llvm,llvmcmds
./usr/include/evbarm minix-comp
./usr/include/evbarm/disklabel.h minix-comp
./usr/include/evbarm/intr.h minix-comp

View File

@@ -3816,6 +3816,7 @@ class ARMTargetInfo : public TargetInfo {
SizeType = UnsignedInt;
switch (T.getOS()) {
case llvm::Triple::Minix:
case llvm::Triple::NetBSD:
WCharType = SignedInt;
break;

View File

@@ -275,7 +275,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
// FIXME: Thumb should just be another -target-feaure, not in the triple.
#if defined(__minix) || 1
// Minix/ARM-specific force to ARMv7 and EABI.
StringRef Suffix = "v7";
StringRef Suffix = "v7a";
Triple.setEnvironment(llvm::Triple::EABI);
#else
StringRef Suffix = Triple.isOSBinFormatMachO()

View File

@@ -665,6 +665,10 @@ StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
}
break;
case llvm::Triple::Minix:
FloatABI = "softfp";
break;
default:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
@@ -796,6 +800,9 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
ABIName = "aapcs";
break;
default:
if (Triple.getOS() == llvm::Triple::Minix)
ABIName = "apcs-gnu";
if (Triple.getOS() == llvm::Triple::NetBSD)
ABIName = "apcs-gnu";
else
@@ -7733,6 +7740,11 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Many NetBSD architectures support more than one ABI.
// Determine the correct emulation for ld.
switch (getToolChain().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
CmdArgs.push_back("-m");
CmdArgs.push_back("armelf_minix");
break;
case llvm::Triple::x86:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386_minix");

View File

@@ -638,6 +638,8 @@ llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
if (!KernelZeroFlagVal.hasValue()) {
if (OS == llvm::Triple::FreeBSD)
KernelZeroFlagVal = 0x0100;
else if (OS == llvm::Triple::Minix)
KernelZeroFlagVal = 0x0002;
else if (OS == llvm::Triple::NetBSD)
KernelZeroFlagVal = 0x0002;
else if (OS == llvm::Triple::OpenBSD)

View File

@@ -1,4 +0,0 @@
{
"project_id" : "lld",
"conduit_uri" : "http://llvm-reviews.chandlerc.com/"
}

View File

@@ -1,169 +0,0 @@
# If we are not building as a part of LLVM, build lld as a standalone project,
# using LLVM as an external library.
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
project(lld)
cmake_minimum_required(VERSION 2.8)
set(LLD_PATH_TO_LLVM_SOURCE "" CACHE PATH
"Path to LLVM source code. Not necessary if using an installed LLVM.")
set(LLD_PATH_TO_LLVM_BUILD "" CACHE PATH
"Path to the directory where LLVM was built or installed.")
if (LLD_PATH_TO_LLVM_SOURCE)
if (NOT EXISTS "${LLD_PATH_TO_LLVM_SOURCE}/cmake/config-ix.cmake")
message(FATAL_ERROR "Please set LLD_PATH_TO_LLVM_SOURCE to the root "
"directory of LLVM source code.")
else()
get_filename_component(LLVM_MAIN_SRC_DIR ${LLD_PATH_TO_LLVM_SOURCE}
ABSOLUTE)
list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules")
endif()
endif()
list(APPEND CMAKE_MODULE_PATH "${LLD_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
get_filename_component(PATH_TO_LLVM_BUILD ${LLD_PATH_TO_LLVM_BUILD}
ABSOLUTE)
option(LLVM_INSTALL_TOOLCHAIN_ONLY
"Only include toolchain files in the 'install' target." OFF)
include(AddLLVM)
include(TableGen)
include("${LLD_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
include(HandleLLVMOptions)
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
set(LLVM_MAIN_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/include")
set(LLVM_BINARY_DIR ${CMAKE_BINARY_DIR})
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories("${PATH_TO_LLVM_BUILD}/include"
"${LLVM_MAIN_INCLUDE_DIR}")
link_directories("${PATH_TO_LLVM_BUILD}/lib")
if (EXISTS "${LLD_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
set (PATH_TO_LLVM_CONFIG "${LLD_PATH_TO_LLVM_BUILD}/bin/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
elseif (EXISTS "${LLD_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
# FIXME: This is an utter hack.
set (PATH_TO_LLVM_CONFIG "${LLD_PATH_TO_LLVM_BUILD}/bin/Debug/llvm-config${CMAKE_EXECUTABLE_SUFFIX}")
else()
message(FATAL_ERROR "Please set LLD_PATH_TO_LLVM_BUILD to a directory containing a LLVM build.")
endif()
exec_program("${PATH_TO_LLVM_CONFIG} --bindir" OUTPUT_VARIABLE LLVM_BINARY_DIR)
set(LLVM_TABLEGEN_EXE "${LLVM_BINARY_DIR}/llvm-tblgen${CMAKE_EXECUTABLE_SUFFIX}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(LLD_BUILT_STANDALONE 1)
endif()
set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
"the makefiles distributed with LLVM. Please create a directory and run cmake "
"from there, passing the path to this source directory as the last argument. "
"This process created the file `CMakeCache.txt' and the directory "
"`CMakeFiles'. Please delete them.")
endif()
list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules")
option(LLD_USE_VTUNE
"Enable VTune user task tracking."
OFF)
if (LLD_USE_VTUNE)
find_package(VTune)
if (VTUNE_FOUND)
include_directories(${VTune_INCLUDE_DIRS})
list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES})
add_definitions(-DLLD_HAS_VTUNE)
endif()
endif()
# lld requires c++11 to build. Make sure that we have a compiler and standard
# library combination that can do that.
if (NOT MSVC)
# gcc and clang require the -std=c++0x or -std=c++11 flag.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang" AND
NOT ("${CMAKE_CXX_FLAGS}" MATCHES ".*-std=(c|gnu)\\+\\+(0x|11).*"))
message(FATAL_ERROR
"lld requires c++11. Clang and gcc require -std=c++0x or -std=c++11 to "
"enter this mode. Please set CMAKE_CXX_FLAGS accordingly.")
endif()
elseif (MSVC_VERSION LESS 1700)
message(FATAL_ERROR "The selected compiler does not support c++11 which is "
"required to build lld.")
endif()
macro(add_lld_library name)
llvm_process_sources(srcs ${ARGN})
if (MSVC_IDE OR XCODE)
string(REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
list(GET split_path -1 dir)
file(GLOB_RECURSE headers
../../include/lld${dir}/*.h)
set(srcs ${srcs} ${headers})
endif()
if (MODULE)
set(libkind MODULE)
elseif (SHARED_LIBRARY)
set(libkind SHARED)
else()
set(libkind)
endif()
add_library(${name} ${libkind} ${srcs})
if (LLVM_COMMON_DEPENDS)
add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
endif()
target_link_libraries(${name} ${LLVM_USED_LIBS})
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
target_link_libraries(${name} ${LLVM_COMMON_LIBS})
link_system_libs(${name})
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
install(TARGETS ${name}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
endif()
set_target_properties(${name} PROPERTIES FOLDER "lld libraries")
endmacro(add_lld_library)
macro(add_lld_executable name)
add_llvm_executable(${name} ${ARGN})
set_target_properties(${name} PROPERTIES FOLDER "lld executables")
endmacro(add_lld_executable)
include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/include
)
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
install(DIRECTORY include/
DESTINATION include
FILES_MATCHING
PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
endif()
add_subdirectory(lib)
add_subdirectory(tools)
add_subdirectory(utils)
add_subdirectory(test)
if (LLVM_INCLUDE_TESTS AND NOT LLD_BUILT_STANDALONE)
add_subdirectory(unittests)
endif()

View File

@@ -1,62 +0,0 @@
==============================================================================
lld License
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2011-2013 by the contributors listed in CREDITS.TXT
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
The lld software contains code written by third parties. Such software will
have its own individual LICENSE.TXT file in the directory in which it appears.
This file will describe the copyrights, license, and restrictions which apply
to that code.
The disclaimer of warranty in the University of Illinois Open Source License
applies to all code in the lld Distribution, and nothing in any of the
other licenses gives permission to use the names of the LLVM Team or the
University of Illinois to endorse or promote products derived from this
Software.
The following pieces of software have additional or alternate copyrights,
licenses, and/or restrictions:
Program Directory
------- ---------
<none yet>

View File

@@ -1,10 +0,0 @@
LLVM Linker (lld)
==============================
This directory and its subdirectories contain source code for the LLVM Linker, a
modular cross platform linker which is built as part of the LLVM compiler
infrastructure project.
lld is open source software. You may freely distribute it under the terms of
the license agreement found in LICENSE.txt.

View File

@@ -1,31 +0,0 @@
# - Find VTune ittnotify.
# Defines:
# VTune_FOUND
# VTune_INCLUDE_DIRS
# VTune_LIBRARIES
set(dirs
"$ENV{VTUNE_AMPLIFIER_XE_2013_DIR}/"
"C:/Program Files (x86)/Intel/VTune Amplifier XE 2013/"
"$ENV{VTUNE_AMPLIFIER_XE_2011_DIR}/"
"C:/Program Files (x86)/Intel/VTune Amplifier XE 2011/"
)
find_path(VTune_INCLUDE_DIRS ittnotify.h
PATHS ${dirs}
PATH_SUFFIXES include)
if (CMAKE_SIZEOF_VOID_P MATCHES "8")
set(vtune_lib_dir lib64)
else()
set(vtune_lib_dir lib32)
endif()
find_library(VTune_LIBRARIES libittnotify
HINTS "${VTune_INCLUDE_DIRS}/.."
PATHS ${dirs}
PATH_SUFFIXES ${vtune_lib_dir})
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
VTune DEFAULT_MSG VTune_LIBRARIES VTune_INCLUDE_DIRS)

View File

@@ -1,35 +0,0 @@
C++11
=====
lld is developed in a limited subset of C++11. Supported compilers are:
* Clang 3.1+
* g++ 4.6+
* MSVC 2012+
Allowed Features
----------------
Allowed features are based on what these compilers support. Features that are ok
to omit (such as final or = delete) may be conditionally used via macros.
* All of the C++11 standard library, including threading and atomics
* auto
* constexpr via LLVM_CONSTEXPR
* decltype
* deleted functions via LLVM_DELETED_FUNCTION
* Forward enum declarations
* Lambdas
* Local and unnamed types as template args
* Trailing return type
* nullptr
* >> instead of > >
* R-Value references excluding R-Value references for this
* static_assert
* Strongly typed enums
* Range based for loop
* final via LLVM_FINAL
Note that some of these features may not be fully or correctly implemented in
all compilers. Issues using these features should be added here as they are
encountered.

View File

@@ -1,79 +0,0 @@
======
Driver
======
.. contents::
:local:
Introduction
============
This document describes the lld driver. The purpose of this document is to
describe both the motivation and design goals for the driver, as well as details
of the internal implementation.
Overview
========
The lld driver is designed to support a number of different command line
interfaces. The main interfaces we plan to support are binutils' ld, Apple's
ld, and Microsoft's link.exe.
Flavors
-------
Each of these different interfaces is referred to as a flavor. There is also an
extra flavor "core" which is used to exercise the core functionality of the
linker it the test suite.
* gnu
* darwin
* link
* core
Selecting a Flavor
^^^^^^^^^^^^^^^^^^
There are two different ways to tell lld which flavor to be. They are checked in
order, so the second overrides the first. The first is to symlink :program:`lld`
as :program:`lld-{flavor}` or just :program:`{flavor}`. You can also specify
it as the first command line argument using ``-flavor``::
$ lld -flavor gnu
There is a shortcut for ``-flavor core`` as ``-core``.
Adding an Option to an existing Flavor
======================================
#. Add the option to the desired :file:`lib/Driver/{flavor}Options.td`.
#. Add to :cpp:class:`lld::FlavorLinkingContext` a getter and setter method
for the option.
#. Modify :cpp:func:`lld::FlavorDriver::parse` in :file:
`lib/Driver/{Flavor}Driver.cpp` to call the targetInfo setter
for corresponding to the option.
#. Modify {Flavor}Reader and {Flavor}Writer to use the new targtInfo option.
Adding a Flavor
===============
#. Add an entry for the flavor in :file:`include/lld/Driver/Driver.h` to
:cpp:class:`lld::UniversalDriver::Flavor`.
#. Add an entry in :file:`lib/Driver/UniversalDriver.cpp` to
:cpp:func:`lld::Driver::strToFlavor` and
:cpp:func:`lld::UniversalDriver::link`.
This allows the flavor to be selected via symlink and :option:`-flavor`.
#. Add a tablegen file called :file:`lib/Driver/{flavor}Options.td` that
describes the options. If the options are a superset of another driver, that
driver's td file can simply be included. The :file:`{flavor}Options.td` file
must also be added to :file:`lib/Driver/CMakeLists.txt`.
#. Add a ``{flavor}Driver`` as a subclass of :cpp:class:`lld::Driver`
in :file:`lib/Driver/{flavor}Driver.cpp`.

View File

@@ -1,155 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
all: html
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/lld.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/lld.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/lld"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/lld"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@@ -1,12 +0,0 @@
lld Documentation
=================
The lld documentation is written using the Sphinx documentation generator. It is
currently tested with Sphinx 1.1.3.
We currently use the 'nature' theme and a Beaker inspired structure.
To rebuild documents into html:
[/lld/docs]> make html

View File

@@ -1,172 +0,0 @@
.. _Readers:
Developing lld Readers
======================
Introduction
------------
The purpose of a "Reader" is to take an object file in a particular format
and create an `lld::File`:cpp:class: (which is a graph of Atoms)
representing the object file. A Reader inherits from
`lld::Reader`:cpp:class: which lives in
:file:`include/lld/ReaderWriter/Reader.h` and
:file:`lib/ReaderWriter/Reader.cpp`.
The Reader infrastructure for an object format ``Foo`` requires the
following pieces in order to fit into lld:
:file:`include/lld/ReaderWriter/ReaderFoo.h`
.. cpp:class:: ReaderOptionsFoo : public ReaderOptions
This Options class is the only way to configure how the Reader will
parse any file into an `lld::Reader`:cpp:class: object. This class
should be declared in the `lld`:cpp:class: namespace.
.. cpp:function:: Reader *createReaderFoo(ReaderOptionsFoo &reader)
This factory function configures and create the Reader. This function
should be declared in the `lld`:cpp:class: namespace.
:file:`lib/ReaderWriter/Foo/ReaderFoo.cpp`
.. cpp:class:: ReaderFoo : public Reader
This is the concrete Reader class which can be called to parse
object files. It should be declared in an anonymous namespace or
if there is shared code with the `lld::WriterFoo`:cpp:class: you
can make a nested namespace (e.g. `lld::foo`:cpp:class:).
You may have noticed that :cpp:class:`ReaderFoo` is not declared in the
``.h`` file. An important design aspect of lld is that all Readers are
created *only* through an object-format-specific
:cpp:func:`createReaderFoo` factory function. The creation of the Reader is
parametrized through a :cpp:class:`ReaderOptionsFoo` class. This options
class is the one-and-only way to control how the Reader operates when
parsing an input file into an Atom graph. For instance, you may want the
Reader to only accept certain architectures. The options class can be
instantiated from command line options or be programmatically configured.
Where to start
--------------
The lld project already has a skeleton of source code for Readers for
``ELF``, ``PECOFF``, ``MachO``, and lld's native Atom graph format
(both binary ``Native`` and ``YAML`` representations). If your file format
is a variant of one of those, you should modify the existing Reader to
support your variant. This is done by customizing the Options
class for the Reader and making appropriate changes to the ``.cpp`` file to
interpret those options and act accordingly.
If your object file format is not a variant of any existing Reader, you'll need
to create a new Reader subclass with the organization described above.
Readers are factories
---------------------
The linker will usually only instantiate your Reader once. That one Reader will
have its parseFile() method called many times with different input files.
To support multithreaded linking, the Reader may be parsing multiple input
files in parallel. Therefore, there should be no parsing state in you Reader
object. Any parsing state should be in ivars of your File subclass or in
some temporary object.
The key method to implement in a reader is::
virtual error_code parseFile(LinkerInput &input,
std::vector<std::unique_ptr<File>> &result);
It takes a memory buffer (which contains the contents of the object file
being read) and returns an instantiated lld::File object which is
a collection of Atoms. The result is a vector of File pointers (instead of
simple a File pointer) because some file formats allow multiple object
"files" to be encoded in one file system file.
Memory Ownership
----------------
Atoms are always owned by their File object. During core linking when Atoms
are coalesced or stripped away, core linking does not delete them.
Core linking just removes those unused Atoms from its internal list.
The destructor of a File object is responsible for deleting all Atoms it
owns, and if ownership of the MemoryBuffer was passed to it, the File
destructor needs to delete that too.
Making Atoms
------------
The internal model of lld is purely Atom based. But most object files do not
have an explicit concept of Atoms, instead most have "sections". The way
to think of this is that a section is just a list of Atoms with common
attributes.
The first step in parsing section-based object files is to cleave each
section into a list of Atoms. The technique may vary by section type. For
code sections (e.g. .text), there are usually symbols at the start of each
function. Those symbol addresses are the points at which the section is
cleaved into discrete Atoms. Some file formats (like ELF) also include the
length of each symbol in the symbol table. Otherwise, the length of each
Atom is calculated to run to the start of the next symbol or the end of the
section.
Other sections types can be implicitly cleaved. For instance c-string literals
or unwind info (e.g. .eh_frame) can be cleaved by having the Reader look at
the content of the section. It is important to cleave sections into Atoms
to remove false dependencies. For instance the .eh_frame section often
has no symbols, but contains "pointers" to the functions for which it
has unwind info. If the .eh_frame section was not cleaved (but left as one
big Atom), there would always be a reference (from the eh_frame Atom) to
each function. So the linker would be unable to coalesce or dead stripped
away the function atoms.
The lld Atom model also requires that a reference to an undefined symbol be
modeled as a Reference to an UndefinedAtom. So the Reader also needs to
create an UndefinedAtom for each undefined symbol in the object file.
Once all Atoms have been created, the second step is to create References
(recall that Atoms are "nodes" and References are "edges"). Most References
are created by looking at the "relocation records" in the object file. If
a function contains a call to "malloc", there is usually a relocation record
specifying the address in the section and the symbol table index. Your
Reader will need to convert the address to an Atom and offset and the symbol
table index into a target Atom. If "malloc" is not defined in the object file,
the target Atom of the Reference will be an UndefinedAtom.
Performance
-----------
Once you have the above working to parse an object file into Atoms and
References, you'll want to look at performance. Some techniques that can
help performance are:
* Use llvm::BumpPtrAllocator or pre-allocate one big vector<Reference> and then
just have each atom point to its subrange of References in that vector.
This can be faster that allocating each Reference as separate object.
* Pre-scan the symbol table and determine how many atoms are in each section
then allocate space for all the Atom objects at once.
* Don't copy symbol names or section content to each Atom, instead use
StringRef and ArrayRef in each Atom to point to its name and content in the
MemoryBuffer.
Testing
-------
We are still working on infrastructure to test Readers. The issue is that
you don't want to check in binary files to the test suite. And the tools
for creating your object file from assembly source may not be available on
every OS.
We are investigating a way to use YAML to describe the section, symbols,
and content of a file. Then have some code which will write out an object
file from that YAML description.
Once that is in place, you can write test cases that contain section/symbols
YAML and is run through the linker to produce Atom/References based YAML which
is then run through FileCheck to verify the Atoms and References are as
expected.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,4 +0,0 @@
<h3>Bugs</h3>
<p>lld bugs should be reported at the
LLVM <a href="http://llvm.org/bugs">Bugzilla</a>.</p>

View File

@@ -1,12 +0,0 @@
{% extends "!layout.html" %}
{% block extrahead %}
<style type="text/css">
table.right { float: right; margin-left: 20px; }
table.right td { border: 1px solid #ccc; }
</style>
{% endblock %}
{% block rootrellink %}
<li><a href="{{ pathto('index') }}">lld Home</a>&nbsp;|&nbsp;</li>
{% endblock %}

View File

@@ -1,251 +0,0 @@
# -*- coding: utf-8 -*-
#
# lld documentation build configuration file.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'lld'
copyright = u'2011-2013, LLVM Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '3.2'
# The full version, including alpha/beta/rc tags.
release = '3.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%Y-%m-%d'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
show_authors = True
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'friendly'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'llvm-theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = ["."]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
html_last_updated_fmt = '%Y-%m-%d'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
html_sidebars = {'index': 'indexsidebar.html'}
# Additional templates that should be rendered to pages, maps page names to
# template names.
# html_additional_pages = {'index': 'index.html'}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'llddoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('contents', 'lld.tex', u'lld Documentation',
u'LLVM project', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('contents', 'lld', u'lld Documentation',
[u'LLVM project'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('contents', 'lld', u'lld Documentation',
u'LLVM project', 'lld', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# FIXME: Define intersphinx configration.
intersphinx_mapping = {}
# -- Options for extensions ----------------------------------------------------
# Enable this if you want TODOs to show up in the generated documentation.
todo_include_todos = True

View File

@@ -1,470 +0,0 @@
.. _design:
Linker Design
=============
Introduction
------------
lld is a new generation of linker. It is not "section" based like traditional
linkers which mostly just interlace sections from multiple object files into the
output file. Instead, lld is based on "Atoms". Traditional section based
linking work well for simple linking, but their model makes advanced linking
features difficult to implement. Features like dead code stripping, reordering
functions for locality, and C++ coalescing require the linker to work at a finer
grain.
An atom is an indivisible chunk of code or data. An atom has a set of
attributes, such as: name, scope, content-type, alignment, etc. An atom also
has a list of References. A Reference contains: a kind, an optional offset, an
optional addend, and an optional target atom.
The Atom model allows the linker to use standard graph theory models for linking
data structures. Each atom is a node, and each Reference is an edge. The
feature of dead code stripping is implemented by following edges to mark all
live atoms, and then delete the non-live atoms.
Atom Model
----------
An atom is an indivisible chunk of code or data. Typically each user written
function or global variable is an atom. In addition, the compiler may emit
other atoms, such as for literal c-strings or floating point constants, or for
runtime data structures like dwarf unwind info or pointers to initializers.
A simple "hello world" object file would be modeled like this:
.. image:: hello.png
There are three atoms: main, a proxy for printf, and an anonymous atom
containing the c-string literal "hello world". The Atom "main" has two
references. One is the call site for the call to printf, and the other is a
reference for the instruction that loads the address of the c-string literal.
There are only four different types of atoms:
* DefinedAtom
95% of all atoms. This is a chunk of code or data
* UndefinedAtom
This is a place holder in object files for a reference to some atom
outside the translation unit.During core linking it is usually replaced
by (coalesced into) another Atom.
* SharedLibraryAtom
If a required symbol name turns out to be defined in a dynamic shared
library (and not some object file). A SharedLibraryAtom is the
placeholder Atom used to represent that fact.
It is similar to an UndefinedAtom, but it also tracks information
about the associated shared library.
* AbsoluteAtom
This is for embedded support where some stuff is implemented in ROM at
some fixed address. This atom has no content. It is just an address
that the Writer needs to fix up any references to point to.
File Model
----------
The linker views the input files as basically containers of Atoms and
References, and just a few attributes of their own. The linker works with three
kinds of files: object files, static libraries, and dynamic shared libraries.
Each kind of file has reader object which presents the file in the model
expected by the linker.
Object File
~~~~~~~~~~~
An object file is just a container of atoms. When linking an object file, a
reader is instantiated which parses the object file and instantiates a set of
atoms representing all content in the .o file. The linker adds all those atoms
to a master graph.
Static Library (Archive)
~~~~~~~~~~~~~~~~~~~~~~~~
This is the traditional unix static archive which is just a collection of object
files with a "table of contents". When linking with a static library, by default
nothing is added to the master graph of atoms. Instead, if after merging all
atoms from object files into a master graph, if any "undefined" atoms are left
remaining in the master graph, the linker reads the table of contents for each
static library to see if any have the needed definitions. If so, the set of
atoms from the specified object file in the static library is added to the
master graph of atoms.
Dynamic Library (Shared Object)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dynamic libraries are different than object files and static libraries in that
they don't directly add any content. Their purpose is to check at build time
that the remaining undefined references can be resolved at runtime, and provide
a list of dynamic libraries (SO_NEEDED) that will be needed at runtime. The way
this is modeled in the linker is that a dynamic library contributes no atoms to
the initial graph of atoms. Instead, (like static libraries) if there are
"undefined" atoms in the master graph of all atoms, then each dynamic library is
checked to see if exports the required symbol. If so, a "shared library" atom is
instantiated by the by the reader which the linker uses to replace the
"undefined" atom.
Linking Steps
-------------
Through the use of abstract Atoms, the core of linking is architecture
independent and file format independent. All command line parsing is factored
out into a separate "options" abstraction which enables the linker to be driven
with different command line sets.
The overall steps in linking are:
#. Command line processing
#. Parsing input files
#. Resolving
#. Passes/Optimizations
#. Generate output file
The Resolving and Passes steps are done purely on the master graph of atoms, so
they have no notion of file formats such as mach-o or ELF.
Input Files
~~~~~~~~~~~
Existing developer tools using different file formats for object files.
A goal of lld is to be file format independent. This is done
through a plug-in model for reading object files. The lld::Reader is the base
class for all object file readers. A Reader follows the factory method pattern.
A Reader instantiates an lld::File object (which is a graph of Atoms) from a
given object file (on disk or in-memory).
Every Reader subclass defines its own "options" class (for instance the mach-o
Reader defines the class ReaderOptionsMachO). This options class is the
one-and-only way to control how the Reader operates when parsing an input file
into an Atom graph. For instance, you may want the Reader to only accept
certain architectures. The options class can be instantiated from command
line options, or it can be subclassed and the ivars programmatically set.
Resolving
~~~~~~~~~
The resolving step takes all the atoms' graphs from each object file and
combines them into one master object graph. Unfortunately, it is not as simple
as appending the atom list from each file into one big list. There are many
cases where atoms need to be coalesced. That is, two or more atoms need to be
coalesced into one atom. This is necessary to support: C language "tentative
definitions", C++ weak symbols for templates and inlines defined in headers,
replacing undefined atoms with actual definition atoms, and for merging copies
of constants like c-strings and floating point constants.
The linker support coalescing by-name and by-content. By-name is used for
tentative definitions and weak symbols. By-content is used for constant data
that can be merged.
The resolving process maintains some global linking "state", including a "symbol
table" which is a map from llvm::StringRef to lld::Atom*. With these data
structures, the linker iterates all atoms in all input files. For each atom, it
checks if the atom is named and has a global or hidden scope. If so, the atom
is added to the symbol table map. If there already is a matching atom in that
table, that means the current atom needs to be coalesced with the found atom, or
it is a multiple definition error.
When all initial input file atoms have been processed by the resolver, a scan is
made to see if there are any undefined atoms in the graph. If there are, the
linker scans all libraries (both static and dynamic) looking for definitions to
replace the undefined atoms. It is an error if any undefined atoms are left
remaining.
Dead code stripping (if requested) is done at the end of resolving. The linker
does a simple mark-and-sweep. It starts with "root" atoms (like "main" in a main
executable) and follows each references and marks each Atom that it visits as
"live". When done, all atoms not marked "live" are removed.
The result of the Resolving phase is the creation of an lld::File object. The
goal is that the lld::File model is **the** internal representation
throughout the linker. The file readers parse (mach-o, ELF, COFF) into an
lld::File. The file writers (mach-o, ELF, COFF) taken an lld::File and produce
their file kind, and every Pass only operates on an lld::File. This is not only
a simpler, consistent model, but it enables the state of the linker to be dumped
at any point in the link for testing purposes.
Passes
~~~~~~
The Passes step is an open ended set of routines that each get a change to
modify or enhance the current lld::File object. Some example Passes are:
* stub (PLT) generation
* GOT instantiation
* order_file optimization
* branch island generation
* branch shim generation
* Objective-C optimizations (Darwin specific)
* TLV instantiation (Darwin specific)
* DTrace probe processing (Darwin specific)
* compact unwind encoding (Darwin specific)
Some of these passes are specific to Darwin's runtime environments. But many of
the passes are applicable to any OS (such as generating branch island for out of
range branch instructions).
The general structure of a pass is to iterate through the atoms in the current
lld::File object, inspecting each atom and doing something. For instance, the
stub pass, looks for call sites to shared library atoms (e.g. call to printf).
It then instantiates a "stub" atom (PLT entry) and a "lazy pointer" atom for
each proxy atom needed, and these new atoms are added to the current lld::File
object. Next, all the noted call sites to shared library atoms have their
References altered to point to the stub atom instead of the shared library atom.
Generate Output File
~~~~~~~~~~~~~~~~~~~~
Once the passes are done, the output file writer is given current lld::File
object. The writer's job is to create the executable content file wrapper and
place the content of the atoms into it.
lld uses a plug-in model for writing output files. All concrete writers (e.g.
ELF, mach-o, etc) are subclasses of the lld::Writer class.
Unlike the Reader class which has just one method to instantiate an lld::File,
the Writer class has multiple methods. The crucial method is to generate the
output file, but there are also methods which allow the Writer to contribute
Atoms to the resolver and specify passes to run.
An example of contributing
atoms is that if the Writer knows a main executable is being linked and such
an executable requires a specially named entry point (e.g. "_main"), the Writer
can add an UndefinedAtom with that special name to the resolver. This will
cause the resolver to issue an error if that symbol is not defined.
Sometimes a Writer supports lazily created symbols, such as names for the start
of sections. To support this, the Writer can create a File object which vends
no initial atoms, but does lazily supply atoms by name as needed.
Every Writer subclass defines its own "options" class (for instance the mach-o
Writer defines the class WriterOptionsMachO). This options class is the
one-and-only way to control how the Writer operates when producing an output
file from an Atom graph. For instance, you may want the Writer to optimize
the output for certain OS versions, or strip local symbols, etc. The options
class can be instantiated from command line options, or it can be subclassed
and the ivars programmatically set.
lld::File representations
-------------------------
Just as LLVM has three representations of its IR model, lld has three
representations of its File/Atom/Reference model:
* In memory, abstract C++ classes (lld::Atom, lld::Reference, and lld::File).
* textual (in YAML)
* binary format ("native")
Binary File Format
~~~~~~~~~~~~~~~~~~
In theory, lld::File objects could be written to disk in an existing Object File
format standard (e.g. ELF). Instead we choose to define a new binary file
format. There are two main reasons for this: fidelity and performance. In order
for lld to work as a linker on all platforms, its internal model must be rich
enough to model all CPU and OS linking features. But if we choose an existing
Object File format as the lld binary format, that means an on going need to
retrofit each platform specific feature needed from alternate platforms into the
existing Object File format. Having our own "native" binary format side steps
that issue. We still need to be able to binary encode all the features, but
once the in-memory model can represent the feature, it is straight forward to
binary encode it.
The reason to use a binary file format at all, instead of a textual file format,
is speed. You want the binary format to be as fast as possible to read into the
in-memory model. Given that we control the in-memory model and the binary
format, the obvious way to make reading super fast it to make the file format be
basically just an array of atoms. The reader just mmaps in the file and looks
at the header to see how many atoms there are and instantiate that many atom
objects with the atom attribute information coming from that array. The trick
is designing this in a way that can be extended as the Atom mode evolves and new
attributes are added.
The native object file format starts with a header that lists how many "chunks"
are in the file. A chunk is an array of "ivar data". The native file reader
instantiates an array of Atom objects (with one large malloc call). Each atom
contains just a pointer to its vtable and a pointer to its ivar data. All
methods on lld::Atom are virtual, so all the method implementations return
values based on the ivar data to which it has a pointer. If a new linking
features is added which requires a change to the lld::Atom model, a new native
reader class (e.g. version 2) is defined which knows how to read the new feature
information from the new ivar data. The old reader class (e.g. version 1) is
updated to do its best to model (the lack of the new feature) given the old ivar
data in existing native object files.
With this model for the native file format, files can be read and turned
into the in-memory graph of lld::Atoms with just a few memory allocations.
And the format can easily adapt over time to new features.
The binary file format follows the ReaderWriter patterns used in lld. The lld
library comes with the classes: ReaderNative and WriterNative. So, switching
between file formats is as easy as switching which Reader subclass is used.
Textual representations in YAML
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In designing a textual format we want something easy for humans to read and easy
for the linker to parse. Since an atom has lots of attributes most of which are
usually just the default, we should define default values for every attribute so
that those can be omitted from the text representation. Here is the atoms for a
simple hello world program expressed in YAML::
target-triple: x86_64-apple-darwin11
atoms:
- name: _main
scope: global
type: code
content: [ 55, 48, 89, e5, 48, 8d, 3d, 00, 00, 00, 00, 30, c0, e8, 00, 00,
00, 00, 31, c0, 5d, c3 ]
fixups:
- offset: 07
kind: pcrel32
target: 2
- offset: 0E
kind: call32
target: _fprintf
- type: c-string
content: [ 73, 5A, 00 ]
...
The biggest use for the textual format will be writing test cases. Writing test
cases in C is problematic because the compiler may vary its output over time for
its own optimization reasons which my inadvertently disable or break the linker
feature trying to be tested. By writing test cases in the linkers own textual
format, we can exactly specify every attribute of every atom and thus target
specific linker logic.
The textual/YAML format follows the ReaderWriter patterns used in lld. The lld
library comes with the classes: ReaderYAML and WriterYAML.
Testing
-------
The lld project contains a test suite which is being built up as new code is
added to lld. All new lld functionality should have a tests added to the test
suite. The test suite is `lit <http://llvm.org/cmds/lit.html/>`_ driven. Each
test is a text file with comments telling lit how to run the test and check the
result To facilitate testing, the lld project builds a tool called lld-core.
This tool reads a YAML file (default from stdin), parses it into one or more
lld::File objects in memory and then feeds those lld::File objects to the
resolver phase. The output of the resolver is written as a native object file.
It is then read back in using the native object file reader and then pass to the
YAML writer. This round-about path means that all three representations
(in-memory, binary, and text) are exercised, and any new feature has to work in
all the representations to pass the test.
Resolver testing
~~~~~~~~~~~~~~~~
Basic testing is the "core linking" or resolving phase. That is where the
linker merges object files. All test cases are written in YAML. One feature of
YAML is that it allows multiple "documents" to be encoding in one YAML stream.
That means one text file can appear to the linker as multiple .o files - the
normal case for the linker.
Here is a simple example of a core linking test case. It checks that an
undefined atom from one file will be replaced by a definition from another
file::
# RUN: lld-core %s | FileCheck %s
#
# Test that undefined atoms are replaced with defined atoms.
#
---
atoms:
- name: foo
definition: undefined
---
atoms:
- name: foo
scope: global
type: code
...
# CHECK: name: foo
# CHECK: scope: global
# CHECK: type: code
# CHECK-NOT: name: foo
# CHECK: ...
Passes testing
~~~~~~~~~~~~~~
Since Passes just operate on an lld::File object, the lld-core tool has the
option to run a particular pass (after resolving). Thus, you can write a YAML
test case with carefully crafted input to exercise areas of a Pass and the check
the resulting lld::File object as represented in YAML.
Design Issues
-------------
There are a number of open issues in the design of lld. The plan is to wait and
make these design decisions when we need to.
Debug Info
~~~~~~~~~~
Currently, the lld model says nothing about debug info. But the most popular
debug format is DWARF and there is some impedance mismatch with the lld model
and DWARF. In lld there are just Atoms and only Atoms that need to be in a
special section at runtime have an associated section. Also, Atoms do not have
addresses. The way DWARF is spec'ed different parts of DWARF are supposed to go
into specially named sections and the DWARF references function code by address.
CPU and OS specific functionality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Currently, lld has an abstract "Platform" that deals with any CPU or OS specific
differences in linking. We just keep adding virtual methods to the base
Platform class as we find linking areas that might need customization. At some
point we'll need to structure this better.
File Attributes
~~~~~~~~~~~~~~~
Currently, lld::File just has a path and a way to iterate its atoms. We will
need to add more attributes on a File. For example, some equivalent to the
target triple. There is also a number of cached or computed attributes that
could make various Passes more efficient. For instance, on Darwin there are a
number of Objective-C optimizations that can be done by a Pass. But it would
improve the plain C case if the Objective-C optimization Pass did not have to
scan all atoms looking for any Objective-C data structures. This could be done
if the lld::File object had an attribute that said if the file had any
Objective-C data in it. The Resolving phase would then be required to "merge"
that attribute as object files are added.

View File

@@ -1,48 +0,0 @@
.. _development:
Development
===========
lld is developed as part of the `LLVM <http://llvm.org>`_ project.
Using C++11 in lld
------------------
:doc:`C++11`.
Creating a Reader
-----------------
See the :ref:`Creating a Reader <Readers>` guide.
Modifying the Driver
--------------------
See :doc:`Driver`.
Debugging
---------
You can run lld with ``-mllvm -debug`` command line options to enable debugging
printouts. If you want to enable debug information for some specific pass, you
can run it with ``-mllvm '-debug-only=<pass>'``, where pass is a name used in
the ``DEBUG_WITH_TYPE()`` macro.
Documentation
-------------
The project documentation is written in reStructuredText and generated using the
`Sphinx <http://sphinx.pocoo.org/>`_ documentation generator. For more
information on writing documentation for the project, see the
:ref:`sphinx_intro`.
.. toctree::
:hidden:
C++11
Readers
Driver

View File

@@ -1,106 +0,0 @@
.. _getting_started:
Getting Started: Building and Running lld
=========================================
This page gives you the shortest path to checking out and building lld. If you
run into problems, please file bugs in the `LLVM Bugzilla`__
__ http://llvm.org/bugs/
Building lld
------------
On Unix-like Systems
~~~~~~~~~~~~~~~~~~~~
1. Get the required tools.
* `CMake 2.8`_\+.
* make (or any build system CMake supports).
* `Clang 3.1`_\+ or GCC 4.7+ (C++11 support is required).
* If using Clang, you will also need `libc++`_.
* `Python 2.4`_\+ (not 3.x) for running tests.
.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
.. _Clang 3.1: http://clang.llvm.org/
.. _libc++: http://libcxx.llvm.org/
.. _Python 2.4: http://python.org/download/
2. Check out LLVM::
$ cd path/to/llvm-project
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
3. Check out lld::
$ cd llvm/tools
$ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
* lld can also be checked out to ``path/to/llvm-project`` and built as an external
project.
4. Build LLVM and lld::
$ cd path/to/llvm-build/llvm (out of source build required)
$ cmake -G "Unix Makefiles" path/to/llvm-project/llvm
$ make
* If you want to build with clang and it is not the default compiler or
it is installed in an alternate location, you'll need to tell the cmake tool
the location of the C and C++ compiler via CMAKE_C_COMPILER and
CMAKE_CXX_COMPILER. For example::
$ cmake -DCMAKE_CXX_COMPILER=/path/to/clang++ -DCMAKE_C_COMPILER=/path/to/clang ...
5. Test::
$ make lld-test
Using Visual Studio
~~~~~~~~~~~~~~~~~~~
#. Get the required tools.
* `CMake 2.8`_\+.
* `Visual Studio 11`_ (required for C++11 support)
* `Python 2.4`_\+ (not 3.x) for running tests.
.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html
.. _Visual Studio 11: http://www.microsoft.com/visualstudio/11/en-us
.. _Python 2.4: http://python.org/download/
#. Check out LLVM::
$ cd path/to/llvm-project
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
#. Check out lld::
$ cd llvm/tools
$ svn co http://llvm.org/svn/llvm-project/lld/trunk lld
* lld can also be checked out to ``path/to/llvm-project`` and built as an external
project.
#. Generate Visual Studio project files::
$ cd path/to/llvm-build/llvm (out of source build required)
$ cmake -G "Visual Studio 11" path/to/llvm-project/llvm
#. Build
* Open LLVM.sln in Visual Studio.
* Build the ``ALL_BUILD`` target.
#. Test
* Build the ``lld-test`` target.
More Information
~~~~~~~~~~~~~~~~
For more information on using CMake see the `LLVM CMake guide`_.
.. _LLVM CMake guide: http://llvm.org/docs/CMake.html

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

View File

@@ -1,82 +0,0 @@
.. _index:
lld - The LLVM Linker
=====================
lld is a new set of modular code for creating linker tools.
* End-User Features:
* Compatible with existing linker options
* Reads standard Object Files (e.g. ELF, Mach-O, PE/COFF)
* Writes standard Executable Files (e.g. ELF, Mach-O, PE)
* Fast link times
* Minimal memory use
* Remove clang's reliance on "the system linker"
* Uses the LLVM `"UIUC" BSD-Style license`__.
* Applications:
* Modular design
* Support cross linking
* Easy to add new CPU support
* Can be built as static tool or library
* Design and Implementation:
* Extensive unit tests
* Internal linker model can be dumped/read to textual format
* Internal linker model can be dumped/read to a new native format
* Native format designed to be fast to read and write
* Additional linking features can be plugged in as "passes"
* OS specific and CPU specific code factored out
Why a new linker?
-----------------
The fact that clang relies on whatever linker tool you happen to have installed
means that clang has been very conservative adopting features which require a
recent linker.
In the same way that the MC layer of LLVM has removed clang's reliance on the
system assembler tool, the lld project will remove clang's reliance on the
system linker tool.
Current Status
--------------
lld is in its early stages of development.
It can currently self host on Linux x86-64 with -static.
Source
------
lld is available in the LLVM SVN repository::
svn co http://llvm.org/svn/llvm-project/lld/trunk
lld is also available via the read-only git mirror::
git clone http://llvm.org/git/lld.git
Contents
--------
.. toctree::
:maxdepth: 2
design
getting_started
development
open_projects
sphinx_intro
Indices and tables
------------------
* :ref:`genindex`
* :ref:`search`
__ http://llvm.org/docs/DeveloperPolicy.html#license

View File

@@ -1,22 +0,0 @@
{#
sphinxdoc/layout.html
~~~~~~~~~~~~~~~~~~~~~
Sphinx layout template for the sphinxdoc theme.
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{% extends "basic/layout.html" %}
{% block relbar1 %}
<div class="logo">
<a href="{{ pathto('index') }}"><img src="{{
pathto("_static/logo.png", 1) }}" alt="LLVM Documentation"/></a>
</div>
{{ super() }}
{% endblock %}
{# put the sidebar before the body #}
{% block sidebar1 %}{{ sidebar() }}{% endblock %}
{% block sidebar2 %}{% endblock %}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

View File

@@ -1,345 +0,0 @@
/*
* sphinxdoc.css_t
* ~~~~~~~~~~~~~~~
*
* Sphinx stylesheet -- sphinxdoc theme. Originally created by
* Armin Ronacher for Werkzeug.
*
* :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@import url("basic.css");
/* -- page layout ----------------------------------------------------------- */
body {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif;
font-size: 14px;
letter-spacing: -0.01em;
line-height: 150%;
text-align: center;
background-color: #BFD1D4;
color: black;
padding: 0;
border: 1px solid #aaa;
margin: 0px 80px 0px 80px;
min-width: 740px;
}
div.logo {
background-color: white;
text-align: left;
padding: 10px 10px 15px 15px;
}
div.document {
background-color: white;
text-align: left;
background-image: url(contents.png);
background-repeat: repeat-x;
}
div.bodywrapper {
margin: 0 240px 0 0;
border-right: 1px solid #ccc;
}
div.body {
margin: 0;
padding: 0.5em 20px 20px 20px;
}
div.related {
font-size: 1em;
}
div.related ul {
background-image: url(navigation.png);
height: 2em;
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
}
div.related ul li {
margin: 0;
padding: 0;
height: 2em;
float: left;
}
div.related ul li.right {
float: right;
margin-right: 5px;
}
div.related ul li a {
margin: 0;
padding: 0 5px 0 5px;
line-height: 1.75em;
color: #EE9816;
}
div.related ul li a:hover {
color: #3CA8E7;
}
div.sphinxsidebarwrapper {
padding: 0;
}
div.sphinxsidebar {
margin: 0;
padding: 0.5em 15px 15px 0;
width: 210px;
float: right;
font-size: 1em;
text-align: left;
}
div.sphinxsidebar h3, div.sphinxsidebar h4 {
margin: 1em 0 0.5em 0;
font-size: 1em;
padding: 0.1em 0 0.1em 0.5em;
color: white;
border: 1px solid #86989B;
background-color: #AFC1C4;
}
div.sphinxsidebar h3 a {
color: white;
}
div.sphinxsidebar ul {
padding-left: 1.5em;
margin-top: 7px;
padding: 0;
line-height: 130%;
}
div.sphinxsidebar ul ul {
margin-left: 20px;
}
div.footer {
background-color: #E3EFF1;
color: #86989B;
padding: 3px 8px 3px 0;
clear: both;
font-size: 0.8em;
text-align: right;
}
div.footer a {
color: #86989B;
text-decoration: underline;
}
/* -- body styles ----------------------------------------------------------- */
p {
margin: 0.8em 0 0.5em 0;
}
a {
color: #CA7900;
text-decoration: none;
}
a:hover {
color: #2491CF;
}
div.body a {
text-decoration: underline;
}
h1 {
margin: 0;
padding: 0.7em 0 0.3em 0;
font-size: 1.5em;
color: #11557C;
}
h2 {
margin: 1.3em 0 0.2em 0;
font-size: 1.35em;
padding: 0;
}
h3 {
margin: 1em 0 -0.3em 0;
font-size: 1.2em;
}
div.body h1 a, div.body h2 a, div.body h3 a, div.body h4 a, div.body h5 a, div.body h6 a {
color: black!important;
}
h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor {
display: none;
margin: 0 0 0 0.3em;
padding: 0 0.2em 0 0.2em;
color: #aaa!important;
}
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor,
h5:hover a.anchor, h6:hover a.anchor {
display: inline;
}
h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover,
h5 a.anchor:hover, h6 a.anchor:hover {
color: #777;
background-color: #eee;
}
a.headerlink {
color: #c60f0f!important;
font-size: 1em;
margin-left: 6px;
padding: 0 4px 0 4px;
text-decoration: none!important;
}
a.headerlink:hover {
background-color: #ccc;
color: white!important;
}
cite, code, tt {
font-family: 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.01em;
}
tt {
background-color: #f2f2f2;
border-bottom: 1px solid #ddd;
color: #333;
}
tt.descname, tt.descclassname, tt.xref {
border: 0;
}
hr {
border: 1px solid #abc;
margin: 2em;
}
a tt {
border: 0;
color: #CA7900;
}
a tt:hover {
color: #2491CF;
}
pre {
font-family: 'Consolas', 'Deja Vu Sans Mono',
'Bitstream Vera Sans Mono', monospace;
font-size: 0.95em;
letter-spacing: 0.015em;
line-height: 120%;
padding: 0.5em;
border: 1px solid #ccc;
background-color: #f8f8f8;
}
pre a {
color: inherit;
text-decoration: underline;
}
td.linenos pre {
padding: 0.5em 0;
}
div.quotebar {
background-color: #f8f8f8;
max-width: 250px;
float: right;
padding: 2px 7px;
border: 1px solid #ccc;
}
div.topic {
background-color: #f8f8f8;
}
table {
border-collapse: collapse;
margin: 0 -0.5em 0 -0.5em;
}
table td, table th {
padding: 0.2em 0.5em 0.2em 0.5em;
}
div.admonition, div.warning {
font-size: 0.9em;
margin: 1em 0 1em 0;
border: 1px solid #86989B;
background-color: #f7f7f7;
padding: 0;
}
div.admonition p, div.warning p {
margin: 0.5em 1em 0.5em 1em;
padding: 0;
}
div.admonition pre, div.warning pre {
margin: 0.4em 1em 0.4em 1em;
}
div.admonition p.admonition-title,
div.warning p.admonition-title {
margin: 0;
padding: 0.1em 0 0.1em 0.5em;
color: white;
border-bottom: 1px solid #86989B;
font-weight: bold;
background-color: #AFC1C4;
}
div.warning {
border: 1px solid #940000;
}
div.warning p.admonition-title {
background-color: #CF0000;
border-bottom-color: #940000;
}
div.admonition ul, div.admonition ol,
div.warning ul, div.warning ol {
margin: 0.1em 0.5em 0.5em 3em;
padding: 0;
}
div.versioninfo {
margin: 1em 0 0 0;
border: 1px solid #ccc;
background-color: #DDEAF0;
padding: 8px;
line-height: 1.3em;
font-size: 0.9em;
}
.viewcode-back {
font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
'Verdana', sans-serif;
}
div.viewcode-block:target {
background-color: #f4debf;
border-top: 1px solid #ac9;
border-bottom: 1px solid #ac9;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

View File

@@ -1,4 +0,0 @@
[theme]
inherit = basic
stylesheet = llvm.css
pygments_style = friendly

View File

@@ -1,190 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\lld.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\lld.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@@ -1,13 +0,0 @@
.. _open_projects:
Open Projects
=============
.. include:: ../include/lld/Core/TODO.txt
.. include:: ../lib/Core/TODO.txt
.. include:: ../tools/lld/TODO.txt
Documentation TODOs
~~~~~~~~~~~~~~~~~~~
.. todolist::

View File

@@ -1,147 +0,0 @@
.. _sphinx_intro:
Sphinx Introduction for LLVM Developers
=======================================
This document is intended as a short and simple introduction to the Sphinx
documentation generation system for LLVM developers.
Quickstart
----------
To get started writing documentation, you will need to:
1. Have the Sphinx tools :ref:`installed <installing_sphinx>`.
2. Understand how to :ref:`build the documentation
<building_the_documentation>`.
3. Start :ref:`writing documentation <writing_documentation>`!
.. _installing_sphinx:
Installing Sphinx
~~~~~~~~~~~~~~~~~
You should be able to install Sphinx using the standard Python package
installation tool ``easy_install``, as follows::
$ sudo easy_install sphinx
Searching for sphinx
Reading http://pypi.python.org/simple/sphinx/
Reading http://sphinx.pocoo.org/
Best match: Sphinx 1.1.3
... more lines here ..
If you do not have root access (or otherwise want to avoid installing Sphinx in
system directories) see the section on :ref:`installing_sphinx_in_a_venv` .
If you do not have the ``easy_install`` tool on your system, you should be able
to install it using:
Linux
Use your distribution's standard package management tool to install it,
i.e., ``apt-get install easy_install`` or ``yum install easy_install``.
Mac OS X
All modern Mac OS X systems come with ``easy_install`` as part of the base
system.
Windows
See the `setuptools <http://pypi.python.org/pypi/setuptools>`_ package web
page for instructions.
.. _building_the_documentation:
Building the documentation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In order to build the documentation, all you should need to do is change to the
``docs`` directory and invoke make as follows::
$ cd path/to/project/docs
$ make html
Note that on Windows there is a ``make.bat`` command in the docs directory which
supplies the same interface as the ``Makefile``.
That command will invoke ``sphinx-build`` with the appropriate options for the
project, and generate the HTML documentation in a ``_build`` subdirectory. You
can browse it starting from the index page by visiting
``_build/html/index.html``.
Sphinx supports a wide variety of generation formats (including LaTeX, man
pages, and plain text). The ``Makefile`` includes a number of convenience
targets for invoking ``sphinx-build`` appropriately, the common ones are:
make html
Generate the HTML output.
make latexpdf
Generate LaTeX documentation and convert to a PDF.
make man
Generate man pages.
.. _writing_documentation:
Writing documentation
~~~~~~~~~~~~~~~~~~~~~
The documentation itself is written in the reStructuredText (ReST) format, and Sphinx
defines additional tags to support features like cross-referencing.
The ReST format itself is organized around documents mostly being readable
plaintext documents. You should generally be able to write new documentation
easily just by following the style of the existing documentation.
If you want to understand the formatting of the documents more, the best place
to start is Sphinx's own `ReST Primer <http://sphinx.pocoo.org/rest.html>`_.
Learning More
-------------
If you want to learn more about the Sphinx system, the best place to start is
the Sphinx documentation itself, available `here
<http://sphinx.pocoo.org/contents.html>`_.
.. _installing_sphinx_in_a_venv:
Installing Sphinx in a Virtual Environment
------------------------------------------
Most Python developers prefer to work with tools inside a *virtualenv* (virtual
environment) instance, which functions as an application sandbox. This avoids
polluting your system installation with different packages used by various
projects (and ensures that dependencies for different packages don't conflict
with one another). Of course, you need to first have the virtualenv software
itself which generally would be installed at the system level::
$ sudo easy_install virtualenv
but after that you no longer need to install additional packages in the system
directories.
Once you have the *virtualenv* tool itself installed, you can create a
virtualenv for Sphinx using::
$ virtualenv ~/my-sphinx-install
New python executable in /Users/dummy/my-sphinx-install/bin/python
Installing setuptools............done.
Installing pip...............done.
$ ~/my-sphinx-install/bin/easy_install sphinx
... install messages here ...
and from now on you can "activate" the *virtualenv* using::
$ source ~/my-sphinx-install/bin/activate
which will change your PATH to ensure the sphinx-build tool from inside the
virtual environment will be used. See the `virtualenv website
<http://www.virtualenv.org/en/latest/index.html>`_ for more information on using
virtual environments.

View File

@@ -1,43 +0,0 @@
//===- Core/AbsoluteAtom.h - An absolute Atom -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_ABSOLUTE_ATOM_H
#define LLD_CORE_ABSOLUTE_ATOM_H
#include "lld/Core/Atom.h"
namespace lld {
/// An AbsoluteAtom has no content.
/// It exists to represent content at fixed addresses in memory.
class AbsoluteAtom : public Atom {
public:
virtual uint64_t value() const = 0;
/// scope - The visibility of this atom to other atoms. C static functions
/// have scope scopeTranslationUnit. Regular C functions have scope
/// scopeGlobal. Functions compiled with visibility=hidden have scope
/// scopeLinkageUnit so they can be see by other atoms being linked but not
/// by the OS loader.
virtual Scope scope() const = 0;
static inline bool classof(const Atom *a) {
return a->definition() == definitionAbsolute;
}
static inline bool classof(const AbsoluteAtom *) { return true; }
protected:
AbsoluteAtom() : Atom(definitionAbsolute) {}
virtual ~AbsoluteAtom() {}
};
} // namespace lld
#endif // LLD_CORE_ABSOLUTE_ATOM_H

View File

@@ -1,48 +0,0 @@
//===- Core/ArchiveLibraryFile.h - Models static library ------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_ARCHIVE_LIBRARY_FILE_H
#define LLD_CORE_ARCHIVE_LIBRARY_FILE_H
#include "lld/Core/File.h"
namespace lld {
///
/// The ArchiveLibraryFile subclass of File is used to represent unix
/// static library archives. These libraries provide no atoms to the
/// initial set of atoms linked. Instead, when the Resolver will query
/// ArchiveLibraryFile instances for specific symbols names using the
/// find() method. If the archive contains an object file which has a
/// DefinedAtom whose scope is not translationUnit, then that entire
/// object file File is returned.
///
class ArchiveLibraryFile : public File {
public:
static inline bool classof(const File *f) {
return f->kind() == kindArchiveLibrary;
}
/// Check if any member of the archive contains an Atom with the
/// specified name and return the File object for that member, or nullptr.
virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0;
virtual const LinkingContext &getLinkingContext() const { return _context; }
protected:
/// only subclasses of ArchiveLibraryFile can be instantiated
ArchiveLibraryFile(const LinkingContext &context, StringRef path)
: File(path, kindArchiveLibrary), _context(context) {}
const LinkingContext &_context;
};
} // namespace lld
#endif // LLD_CORE_ARCHIVE_LIBRARY_FILE_H

View File

@@ -1,84 +0,0 @@
//===- Core/Atom.h - A node in linking graph ------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_ATOM_H
#define LLD_CORE_ATOM_H
#include "lld/Core/LLVM.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
namespace llvm {
class StringRef;
}
namespace lld {
class File;
///
/// The linker has a Graph Theory model of linking. An object file is seen
/// as a set of Atoms with References to other Atoms. Each Atom is a node
/// and each Reference is an edge. An Atom can be a DefinedAtom which has
/// content or a UndefinedAtom which is a placeholder and represents an
/// undefined symbol (extern declaration).
///
class Atom {
public:
/// Whether this atom is defined or a proxy for an undefined symbol
enum Definition {
definitionRegular, ///< Normal C/C++ function or global variable.
definitionAbsolute, ///< Asm-only (foo = 10). Not tied to any content.
definitionUndefined, ///< Only in .o files to model reference to undef.
definitionSharedLibrary ///< Only in shared libraries to model export.
};
/// The scope in which this atom is acessible to other atoms.
enum Scope {
scopeTranslationUnit, ///< Accessible only to atoms in the same translation
/// unit (e.g. a C static).
scopeLinkageUnit, ///< Accessible to atoms being linked but not visible
/// to runtime loader (e.g. visibility=hidden).
scopeGlobal ///< Accessible to all atoms and visible to runtime
/// loader (e.g. visibility=default).
};
/// file - returns the File that produced/owns this Atom
virtual const File& file() const = 0;
/// name - The name of the atom. For a function atom, it is the (mangled)
/// name of the function.
virtual StringRef name() const = 0;
/// definition - Whether this atom is a definition or represents an undefined
/// symbol.
Definition definition() const { return _definition; }
static inline bool classof(const Atom *a) { return true; }
protected:
/// Atom is an abstract base class. Only subclasses can access constructor.
explicit Atom(Definition def) : _definition(def) {}
/// The memory for Atom objects is always managed by the owning File
/// object. Therefore, no one but the owning File object should call
/// delete on an Atom. In fact, some File objects may bulk allocate
/// an array of Atoms, so they cannot be individually deleted by anyone.
virtual ~Atom() {}
private:
Definition _definition;
};
} // namespace lld
#endif // LLD_CORE_ATOM_H

View File

@@ -1,357 +0,0 @@
//===- Core/DefinedAtom.h - An Atom with content --------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_DEFINED_ATOM_H
#define LLD_CORE_DEFINED_ATOM_H
#include "lld/Core/Atom.h"
#include "lld/Core/Reference.h"
namespace llvm {
template <typename T>
class ArrayRef;
class StringRef;
}
namespace lld {
class File;
/// \brief The fundamental unit of linking.
///
/// A C function or global variable is an atom. An atom has content and
/// attributes. The content of a function atom is the instructions that
/// implement the function. The content of a global variable atom is its
/// initial bytes.
///
/// Here are some example attribute sets for common atoms. If a particular
/// attribute is not listed, the default values are: definition=regular,
/// sectionChoice=basedOnContent, scope=translationUnit, merge=no,
/// deadStrip=normal, interposable=no
///
/// C function: void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global
///
/// C static function: staic void func() {} <br>
/// name=func, type=code, perm=r_x
///
/// C global variable: int count = 1; <br>
/// name=count, type=data, perm=rw_, scope=global
///
/// C tentative definition: int bar; <br>
/// name=bar, type=zerofill, perm=rw_, scope=global,
/// merge=asTentative, interposable=yesAndRuntimeWeak
///
/// Uninitialized C static variable: static int stuff; <br>
/// name=stuff, type=zerofill, perm=rw_
///
/// Weak C function: __attribute__((weak)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, merge=asWeak
///
/// Hidden C function: __attribute__((visibility("hidden"))) void foo() {}<br>
/// name=foo, type=code, perm=r_x, scope=linkageUnit
///
/// No-dead-strip function: __attribute__((used)) void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global, deadStrip=never
///
/// Non-inlined C++ inline method: inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=asWeak
///
/// Non-inlined C++ inline method whose address is taken:
/// inline void Foo::doit() {} <br>
/// name=_ZN3Foo4doitEv, type=code, perm=r_x, scope=global,
/// mergeDupes=asAddressedWeak
///
/// literal c-string: "hello" <br>
/// name="" type=cstring, perm=r__, scope=linkageUnit
///
/// literal double: 1.234 <br>
/// name="" type=literal8, perm=r__, scope=linkageUnit
///
/// constant: { 1,2,3 } <br>
/// name="" type=constant, perm=r__, scope=linkageUnit
///
/// Pointer to initializer function: <br>
/// name="" type=initializer, perm=rw_l,
/// sectionChoice=customRequired
///
/// C function place in custom section: __attribute__((section("__foo")))
/// void foo() {} <br>
/// name=foo, type=code, perm=r_x, scope=global,
/// sectionChoice=customRequired, customSectionName=__foo
///
class DefinedAtom : public Atom {
public:
enum Interposable {
interposeNo, // linker can directly bind uses of this atom
interposeYes, // linker must indirect (through GOT) uses
interposeYesAndRuntimeWeak // must indirect and mark symbol weak in final
// linked image
};
enum Merge {
mergeNo, // Another atom with same name is error
mergeAsTentative, // Is ANSI C tentative defintion, can be coalesced
mergeAsWeak, // is C++ inline definition that was not inlined,
// but address was not taken, so atom can be hidden
// by linker
mergeAsWeakAndAddressUsed,// is C++ definition inline definition whose
// address was taken.
mergeByContent // merge with other constants with same content
};
enum ContentType {
typeUnknown, // for use with definitionUndefined
typeCode, // executable code
typeResolver, // function which returns address of target
typeBranchIsland, // linker created for large binaries
typeBranchShim, // linker created to switch thumb mode
typeStub, // linker created for calling external function
typeStubHelper, // linker created for initial stub binding
typeConstant, // a read-only constant
typeCString, // a zero terminated UTF8 C string
typeUTF16String, // a zero terminated UTF16 string
typeCFI, // a FDE or CIE from dwarf unwind info
typeLSDA, // extra unwinding info
typeLiteral4, // a four-btye read-only constant
typeLiteral8, // an eight-btye read-only constant
typeLiteral16, // a sixteen-btye read-only constant
typeData, // read-write data
typeDataFast, // allow data to be quickly accessed
typeZeroFill, // zero-fill data
typeZeroFillFast, // allow zero-fill data to be quicky accessed
typeConstData, // read-only data after dynamic linker is done
typeObjC1Class, // ObjC1 class [Darwin]
typeLazyPointer, // pointer through which a stub jumps
typeLazyDylibPointer, // pointer through which a stub jumps [Darwin]
typeCFString, // NS/CFString object [Darwin]
typeGOT, // pointer to external symbol
typeInitializerPtr, // pointer to initializer function
typeTerminatorPtr, // pointer to terminator function
typeCStringPtr, // pointer to UTF8 C string [Darwin]
typeObjCClassPtr, // pointer to ObjC class [Darwin]
typeObjC2CategoryList, // pointers to ObjC category [Darwin]
typeDTraceDOF, // runtime data for Dtrace [Darwin]
typeTempLTO, // temporary atom for bitcode reader
typeCompactUnwindInfo, // runtime data for unwinder [Darwin]
typeThunkTLV, // thunk used to access a TLV [Darwin]
typeTLVInitialData, // initial data for a TLV [Darwin]
typeTLVInitialZeroFill, // TLV initial zero fill data [Darwin]
typeTLVInitializerPtr, // pointer to thread local initializer [Darwin]
typeDataDirectoryEntry, // linker created for data directory header [PECOFF]
typeThreadZeroFill, // Uninitialized thread local data(TBSS) [ELF]
typeThreadData, // Initialized thread local data(TDATA) [ELF]
typeRONote, // Identifies readonly note sections [ELF]
typeRWNote, // Identifies readwrite note sections [ELF]
typeNoAlloc, // Identifies non allocatable sections [ELF]
};
// Permission bits for atoms and segments. The order of these values are
// important, because the layout pass may sort atoms by permission if other
// attributes are the same.
enum ContentPermissions {
perm___ = 0, // mapped as unaccessible
permR__ = 8, // mapped read-only
permRW_ = 8 + 2, // mapped readable and writable
permRW_L = 8 + 2 + 1, // initially mapped r/w, then made read-only
// loader writable
permR_X = 8 + 4, // mapped readable and executable
permRWX = 8 + 2 + 4, // mapped readable and writable and executable
permUnknown = 16 // unknown or invalid permissions
};
enum SectionChoice {
sectionBasedOnContent, // linker infers final section based on content
sectionCustomPreferred, // linker may place in specific section
sectionCustomRequired // linker must place in specific section
};
enum SectionPosition {
sectionPositionStart, // atom must be at start of section (and zero size)
sectionPositionEarly, // atom should be near start of section
sectionPositionAny, // atom can be anywhere in section
sectionPositionEnd // atom must be at end of section (and zero size)
};
enum DeadStripKind {
deadStripNormal, // linker may dead strip this atom
deadStripNever, // linker must never dead strip this atom
deadStripAlways // linker must remove this atom if unused
};
enum DynamicExport {
/// \brief The linker may or may not export this atom dynamically depending
/// on the output type and other context of the link.
dynamicExportNormal,
/// \brief The linker will always export this atom dynamically.
dynamicExportAlways,
};
struct Alignment {
Alignment(int p2, int m = 0)
: powerOf2(p2)
, modulus(m) {}
uint16_t powerOf2;
uint16_t modulus;
bool operator==(const Alignment &rhs) const {
return (powerOf2 == rhs.powerOf2) && (modulus == rhs.modulus);
}
};
/// \brief returns a value for the order of this Atom within its file.
///
/// This is used by the linker to order the layout of Atoms so that the
/// resulting image is stable and reproducible.
///
/// Note that this should not be confused with ordinals of exported symbols in
/// Windows DLLs. In Windows terminology, ordinals are symbols' export table
/// indices (small integers) which can be used instead of symbol names to
/// refer items in a DLL.
virtual uint64_t ordinal() const = 0;
/// \brief the number of bytes of space this atom's content will occupy in the
/// final linked image.
///
/// For a function atom, it is the number of bytes of code in the function.
virtual uint64_t size() const = 0;
/// \brief The visibility of this atom to other atoms.
///
/// C static functions have scope scopeTranslationUnit. Regular C functions
/// have scope scopeGlobal. Functions compiled with visibility=hidden have
/// scope scopeLinkageUnit so they can be see by other atoms being linked but
/// not by the OS loader.
virtual Scope scope() const = 0;
/// \brief Whether the linker should use direct or indirect access to this
/// atom.
virtual Interposable interposable() const = 0;
/// \brief how the linker should handle if multiple atoms have the same name.
virtual Merge merge() const = 0;
/// \brief The type of this atom, such as code or data.
virtual ContentType contentType() const = 0;
/// \brief The alignment constraints on how this atom must be laid out in the
/// final linked image (e.g. 16-byte aligned).
virtual Alignment alignment() const = 0;
/// \brief Whether this atom must be in a specially named section in the final
/// linked image, or if the linker can infer the section based on the
/// contentType().
virtual SectionChoice sectionChoice() const = 0;
/// \brief If sectionChoice() != sectionBasedOnContent, then this return the
/// name of the section the atom should be placed into.
virtual StringRef customSectionName() const = 0;
/// \brief constraints on whether the linker may dead strip away this atom.
virtual SectionPosition sectionPosition() const = 0;
/// \brief constraints on whether the linker may dead strip away this atom.
virtual DeadStripKind deadStrip() const = 0;
/// \brief Under which conditions should this atom be dynamically exported.
virtual DynamicExport dynamicExport() const {
return dynamicExportNormal;
}
/// \brief Returns the OS memory protections required for this atom's content
/// at runtime.
///
/// A function atom is R_X, a global variable is RW_, and a read-only constant
/// is R__.
virtual ContentPermissions permissions() const;
/// \brief means this is a zero size atom that exists to provide an alternate
/// name for another atom. Alias atoms must have a special Reference to the
/// atom they alias which the layout engine recognizes and forces the alias
/// atom to layout right before the target atom.
virtual bool isAlias() const = 0;
/// \brief returns a reference to the raw (unrelocated) bytes of this Atom's
/// content.
virtual ArrayRef<uint8_t> rawContent() const = 0;
/// This class abstracts iterating over the sequence of References
/// in an Atom. Concrete instances of DefinedAtom must implement
/// the derefIterator() and incrementIterator() methods.
class reference_iterator {
public:
reference_iterator(const DefinedAtom &a, const void *it)
: _atom(a), _it(it) { }
const Reference *operator*() const {
return _atom.derefIterator(_it);
}
const Reference *operator->() const {
return _atom.derefIterator(_it);
}
bool operator!=(const reference_iterator &other) const {
return _it != other._it;
}
reference_iterator &operator++() {
_atom.incrementIterator(_it);
return *this;
}
private:
const DefinedAtom &_atom;
const void *_it;
};
/// \brief Returns an iterator to the beginning of this Atom's References.
virtual reference_iterator begin() const = 0;
/// \brief Returns an iterator to the end of this Atom's References.
virtual reference_iterator end() const = 0;
static inline bool classof(const Atom *a) {
return a->definition() == definitionRegular;
}
/// Utility for deriving permissions from content type
static ContentPermissions permissions(ContentType type);
/// Utility function to check if the atom occupies file space
virtual bool occupiesDiskSpace() const {
ContentType atomContentType = contentType();
return !(atomContentType == DefinedAtom::typeZeroFill ||
atomContentType == DefinedAtom::typeZeroFillFast ||
atomContentType == DefinedAtom::typeTLVInitialZeroFill ||
atomContentType == DefinedAtom::typeThreadZeroFill);
}
protected:
// DefinedAtom is an abstract base class. Only subclasses can access
// constructor.
DefinedAtom() : Atom(definitionRegular) { }
// The memory for DefinedAtom objects is always managed by the owning File
// object. Therefore, no one but the owning File object should call delete on
// an Atom. In fact, some File objects may bulk allocate an array of Atoms,
// so they cannot be individually deleted by anyone.
virtual ~DefinedAtom() {}
/// \brief Returns a pointer to the Reference object that the abstract
/// iterator "points" to.
virtual const Reference *derefIterator(const void *iter) const = 0;
/// \brief Adjusts the abstract iterator to "point" to the next Reference
/// object for this Atom.
virtual void incrementIterator(const void *&iter) const = 0;
};
} // end namespace lld
#endif

View File

@@ -1,84 +0,0 @@
//===- Error.h - system_error extensions for lld ----------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This declares a new error_category for the lld library.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_ERROR_H
#define LLD_CORE_ERROR_H
#include "llvm/Support/system_error.h"
namespace lld {
const llvm::error_category &native_reader_category();
enum class NativeReaderError {
success = 0,
unknown_file_format,
file_too_short,
file_malformed,
unknown_chunk_type,
memory_error,
};
inline llvm::error_code make_error_code(NativeReaderError e) {
return llvm::error_code(static_cast<int>(e), native_reader_category());
}
const llvm::error_category &YamlReaderCategory();
enum class YamlReaderError {
success = 0,
unknown_keyword,
illegal_value
};
inline llvm::error_code make_error_code(YamlReaderError e) {
return llvm::error_code(static_cast<int>(e), YamlReaderCategory());
}
const llvm::error_category &LinkerScriptReaderCategory();
enum class LinkerScriptReaderError {
success = 0,
parse_error
};
inline llvm::error_code make_error_code(LinkerScriptReaderError e) {
return llvm::error_code(static_cast<int>(e), LinkerScriptReaderCategory());
}
/// \brief Errors returned by InputGraph functionality
const llvm::error_category &InputGraphErrorCategory();
enum class InputGraphError {
success = 0,
failure = 1,
no_more_elements,
no_more_files
};
inline llvm::error_code make_error_code(InputGraphError e) {
return llvm::error_code(static_cast<int>(e), InputGraphErrorCategory());
}
} // end namespace lld
namespace llvm {
template <> struct is_error_code_enum<lld::NativeReaderError> : true_type {};
template <> struct is_error_code_enum<lld::YamlReaderError> : true_type {};
template <>
struct is_error_code_enum<lld::LinkerScriptReaderError> : true_type {};
template <> struct is_error_code_enum<lld::InputGraphError> : true_type {};
} // end namespace llvm
#endif

View File

@@ -1,251 +0,0 @@
//===- Core/File.h - A Container of Atoms ---------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_FILE_H
#define LLD_CORE_FILE_H
#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/range.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/UndefinedAtom.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include <vector>
namespace lld {
class LinkingContext;
/// Every Atom is owned by some File. A common scenario is for a single
/// object file (.o) to be parsed by some reader and produce a single
/// File object that represents the content of that object file.
///
/// To iterate through the Atoms in a File there are four methods that
/// return collections. For instance to iterate through all the DefinedAtoms
/// in a File object use:
/// for (const DefinedAtoms *atom : file->defined()) {
/// }
///
/// The Atom objects in a File are owned by the File object. The Atom objects
/// are destroyed when the File object is destroyed.
class File {
public:
virtual ~File();
/// \brief Kinds of files that are supported.
enum Kind {
kindObject, ///< object file (.o)
kindSharedLibrary, ///< shared library (.so)
kindArchiveLibrary, ///< archive (.a)
kindLinkerScript, ///< linker script
};
/// \brief Returns file kind. Need for dyn_cast<> on File objects.
Kind kind() const {
return _kind;
}
/// \brief For error messages and debugging, this returns the path to the file
/// which was used to create this object (e.g. "/tmp/foo.o").
StringRef path() const {
return _path;
}
/// \brief Returns the path of the source file used to create the object
/// file which this (File) object represents. This information is usually
/// parsed out of the DWARF debug information. If the source file cannot
/// be ascertained, this method returns the empty string.
virtual StringRef translationUnitSource() const;
/// Returns the command line order of the file.
uint64_t ordinal() const {
assert(_ordinal != UINT64_MAX);
return _ordinal;
}
/// Returns true/false depending on whether an ordinal has been set.
bool hasOrdinal() const { return (_ordinal != UINT64_MAX); }
/// Sets the command line order of the file.
void setOrdinal(uint64_t ordinal) const { _ordinal = ordinal; }
public:
template <typename T> class atom_iterator; // forward reference
/// \brief For use interating over DefinedAtoms in this File.
typedef atom_iterator<DefinedAtom> defined_iterator;
/// \brief For use interating over UndefinedAtoms in this File.
typedef atom_iterator<UndefinedAtom> undefined_iterator;
/// \brief For use interating over SharedLibraryAtoms in this File.
typedef atom_iterator<SharedLibraryAtom> shared_library_iterator;
/// \brief For use interating over AbsoluteAtoms in this File.
typedef atom_iterator<AbsoluteAtom> absolute_iterator;
/// \brief Different object file readers may instantiate and manage atoms with
/// different data structures. This class is a collection abstraction.
/// Each concrete File instance must implement these atom_collection
/// methods to enable clients to interate the File's atoms.
template <typename T>
class atom_collection {
public:
virtual ~atom_collection() { }
virtual atom_iterator<T> begin() const = 0;
virtual atom_iterator<T> end() const = 0;
virtual const T *deref(const void *it) const = 0;
virtual void next(const void *&it) const = 0;
virtual uint64_t size() const = 0;
};
/// \brief The class is the iterator type used to iterate through a File's
/// Atoms. This iterator delegates the work to the associated atom_collection
/// object. There are four kinds of Atoms, so this iterator is templated on
/// the four base Atom kinds.
template <typename T>
class atom_iterator {
public:
atom_iterator(const atom_collection<T> &c, const void *it)
: _collection(c), _it(it) { }
const T *operator*() const {
return _collection.deref(_it);
}
const T *operator->() const {
return _collection.deref(_it);
}
bool operator!=(const atom_iterator<T> &other) const {
return (this->_it != other._it);
}
atom_iterator<T> &operator++() {
_collection.next(_it);
return *this;
}
private:
const atom_collection<T> &_collection;
const void *_it;
};
/// \brief Must be implemented to return the atom_collection object for
/// all DefinedAtoms in this File.
virtual const atom_collection<DefinedAtom> &defined() const = 0;
/// \brief Must be implemented to return the atom_collection object for
/// all UndefinedAtomw in this File.
virtual const atom_collection<UndefinedAtom> &undefined() const = 0;
/// \brief Must be implemented to return the atom_collection object for
/// all SharedLibraryAtoms in this File.
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const = 0;
/// \brief Must be implemented to return the atom_collection object for
/// all AbsoluteAtoms in this File.
virtual const atom_collection<AbsoluteAtom> &absolute() const = 0;
virtual const LinkingContext &getLinkingContext() const = 0;
protected:
/// \brief only subclasses of File can be instantiated
File(StringRef p, Kind kind) : _path(p), _kind(kind), _ordinal(UINT64_MAX) {}
/// \brief This is a convenience class for File subclasses which manage their
/// atoms as a simple std::vector<>.
template <typename T>
class atom_collection_vector : public atom_collection<T> {
public:
virtual atom_iterator<T> begin() const {
return atom_iterator<T>(*this,
_atoms.empty() ? 0 : reinterpret_cast<const void *>(_atoms.data()));
}
virtual atom_iterator<T> end() const{
return atom_iterator<T>(*this, _atoms.empty() ? 0 :
reinterpret_cast<const void *>(_atoms.data() + _atoms.size()));
}
virtual const T *deref(const void *it) const {
return *reinterpret_cast<const T* const*>(it);
}
virtual void next(const void *&it) const {
const T *const *p = reinterpret_cast<const T *const*>(it);
++p;
it = reinterpret_cast<const void*>(p);
}
virtual uint64_t size() const { return _atoms.size(); }
std::vector<const T *> _atoms;
};
/// \brief This is a convenience class for File subclasses which need to
/// return an empty collection.
template <typename T>
class atom_collection_empty : public atom_collection<T> {
public:
virtual atom_iterator<T> begin() const {
return atom_iterator<T>(*this, nullptr);
}
virtual atom_iterator<T> end() const{
return atom_iterator<T>(*this, nullptr);
}
virtual const T *deref(const void *it) const {
llvm_unreachable("empty collection should never be accessed");
}
virtual void next(const void *&it) const {
}
virtual void push_back(const T *element) {
llvm_unreachable("empty collection should never be grown");
}
virtual uint64_t size() const { return 0; }
};
static atom_collection_empty<DefinedAtom> _noDefinedAtoms;
static atom_collection_empty<UndefinedAtom> _noUndefinedAtoms;
static atom_collection_empty<SharedLibraryAtom> _noSharedLibraryAtoms;
static atom_collection_empty<AbsoluteAtom> _noAbsoluteAtoms;
private:
StringRef _path;
Kind _kind;
mutable uint64_t _ordinal;
};
/// \brief A mutable File.
class MutableFile : public File {
public:
/// \brief Add an atom to the file. Invalidates iterators for all returned
/// containters.
virtual void addAtom(const Atom&) = 0;
typedef range<std::vector<const DefinedAtom *>::iterator> DefinedAtomRange;
virtual DefinedAtomRange definedAtoms() = 0;
virtual const LinkingContext &getLinkingContext() const { return _context; }
protected:
/// \brief only subclasses of MutableFile can be instantiated
MutableFile(const LinkingContext &ctx, StringRef p)
: File(p, kindObject), _context(ctx) {}
private:
const LinkingContext &_context;
};
} // end namespace lld
#endif

View File

@@ -1,411 +0,0 @@
//===- lld/Core/InputGraph.h - Input Graph --------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Inputs to the linker in the form of a Graph.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_INPUT_GRAPH_H
#define LLD_CORE_INPUT_GRAPH_H
#include "lld/Core/File.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <stack>
#include <vector>
namespace lld {
class InputElement;
class LinkingContext;
/// \brief The inputs to the linker are represented by an InputGraph. The
/// nodes in the input graph contains Input elements. The InputElements are
/// either Input Files or Control Options. The Input Files represent each Input
/// File to the linker and the control option specify what the linker needs
/// to do when it processes the option.
/// Each InputElement that is part of the Graph has an Ordinal value
/// associated with it. The ordinal value is needed for the Writer to figure out
/// the relative position of the arguments that appeared in the Command Line.
/// InputElements have a weight function that can be used to determine the
/// weight of the file, for statistical purposes.
class InputGraph {
public:
typedef std::vector<std::unique_ptr<InputElement> > InputElementVectorT;
typedef InputElementVectorT::iterator InputElementIterT;
typedef std::vector<std::unique_ptr<File> > FileVectorT;
typedef FileVectorT::iterator FileIterT;
/// Where do we want to insert the input element when calling the
/// insertElementAt, insertOneElementAt API's.
enum Position : uint8_t {
ANY,
BEGIN,
END
};
/// \brief Initialize the inputgraph
InputGraph() : _ordinal(0), _nextElementIndex(0) {}
/// \brief Adds a node into the InputGraph
virtual bool addInputElement(std::unique_ptr<InputElement>);
/// \brief Set Ordinals for all the InputElements that form the InputGraph
virtual bool assignOrdinals();
/// Destructor
virtual ~InputGraph() {}
/// \brief Do postprocessing of the InputGraph if there is a need for the
/// to provide additional information to the user, also rearranges
/// InputElements by their ordinals. If an user wants to place an input file
/// at the desired position, the user can do that
virtual void doPostProcess();
range<InputElementIterT> inputElements() {
return make_range(_inputArgs.begin(), _inputArgs.end());
}
/// \brief Validate the input graph
virtual bool validate();
// \brief Does the inputGraph contain any elements
size_t size() const { return _inputArgs.size(); }
/// \brief Dump the input Graph
virtual bool dump(raw_ostream &diagnostics = llvm::errs());
InputElement &operator[](size_t index) const {
return (*_inputArgs[index]);
}
/// \brief Insert a vector of elements into the input graph at position.
virtual void insertElementsAt(std::vector<std::unique_ptr<InputElement> >,
Position position, size_t pos = 0);
/// \brief Insert an element into the input graph at position.
virtual void insertOneElementAt(std::unique_ptr<InputElement>,
Position position, size_t pos = 0);
/// \brief Helper functions for the resolver
virtual ErrorOr<InputElement *> getNextInputElement();
/// \brief Set the index on what inputElement has to be returned
virtual error_code setNextElementIndex(uint32_t index = 0);
/// \brief Reset the inputGraph for the inputGraph to start processing
/// files from the beginning
virtual error_code reset() { return setNextElementIndex(0); }
protected:
// Input arguments
InputElementVectorT _inputArgs;
// Ordinals
int64_t _ordinal;
// Index of the next element to be processed
uint32_t _nextElementIndex;
};
/// \brief This describes each element in the InputGraph. The Kind
/// determines what the current node contains.
class InputElement {
public:
/// Each input element in the graph can be a File or a control
enum class Kind : uint8_t {
Control, // Represents a type associated with ControlNodes
SimpleFile, // Represents a type reserved for internal files
File // Represents a type associated with File Nodes
};
/// \brief Initialize the Input Element, The ordinal value of an input Element
/// is initially set to -1, if the user wants to override its ordinal,
/// let the user do it
InputElement(Kind type, int64_t ordinal = -1);
virtual ~InputElement() {}
/// Return the Element Type for an Input Element
virtual Kind kind() const { return _kind; }
virtual void setOrdinal(int64_t ordinal) {
if (_ordinal != -1)
_ordinal = ordinal;
}
virtual int64_t getOrdinal() const { return _ordinal; }
virtual int64_t weight() const { return _weight; }
virtual void setWeight(int64_t weight) { _weight = weight; }
/// \brief validates the Input Element
virtual bool validate() = 0;
/// \brief Dump the Input Element
virtual bool dump(raw_ostream &diagnostics) = 0;
/// \brief parse the input element
virtual error_code parse(const LinkingContext &, raw_ostream &) = 0;
/// \brief functions for the resolver to use
/// Get the next file to be processed by the resolver
virtual ErrorOr<File &> getNextFile() = 0;
/// \brief Set the resolve state for the element
virtual void setResolveState(uint32_t state) = 0;
/// \brief Get the resolve state for the element
virtual uint32_t getResolveState() const = 0;
/// \brief Reset the next index
virtual void resetNextIndex() = 0;
protected:
Kind _kind; // The type of the Element
int64_t _ordinal; // The ordinal value
int64_t _weight; // Weight of the file
};
/// \brief The Control class represents a control node in the InputGraph
class ControlNode : public InputElement {
public:
/// A control node could be of several types supported by InputGraph
/// Future kinds of Control node could be added
enum class ControlKind : uint8_t{
Simple, // Represents a simple control node
Group // Represents a type associated with ControlNodes
};
ControlNode(ControlNode::ControlKind controlKind =
ControlNode::ControlKind::Simple,
int64_t _ordinal = -1)
: InputElement(InputElement::Kind::Control, _ordinal),
_controlKind(controlKind), _currentElementIndex(0),
_nextElementIndex(0) {}
virtual ~ControlNode() {}
/// \brief Return the kind of control node
virtual ControlNode::ControlKind controlKind() { return _controlKind; }
/// \brief Process control start/exit
virtual bool processControlEnter() { return true; }
/// \brief Process control start/exit
virtual bool processControlExit() { return true; }
/// Process the input Elemenet
virtual bool processInputElement(std::unique_ptr<InputElement> element) = 0;
/// \brief Casting support
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::Control;
}
range<InputGraph::InputElementIterT> elements() {
return make_range(_elements.begin(), _elements.end());
}
virtual void resetNextIndex() {
_currentElementIndex = _nextElementIndex = 0;
for (auto &elem : _elements)
elem->resetNextIndex();
}
virtual uint32_t getResolveState() const;
virtual void setResolveState(uint32_t);
protected:
ControlKind _controlKind;
InputGraph::InputElementVectorT _elements;
uint32_t _currentElementIndex;
uint32_t _nextElementIndex;
};
/// \brief Represents an Input file in the graph
///
/// This class represents an input to the linker. It create the MemoryBuffer
/// lazily when needed based on the file path. It can also take a MemoryBuffer
/// directly.
class FileNode : public InputElement {
public:
FileNode(StringRef path, int64_t ordinal = -1);
virtual ErrorOr<StringRef> getPath(const LinkingContext &) const {
return _path;
}
// The saved input path thats used when a file is not found while
// trying to parse a file
StringRef getUserPath() const { return _path; }
virtual ~FileNode() {}
/// \brief Casting support
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::File;
}
/// \brief create an error string for printing purposes
virtual std::string errStr(error_code errc) {
std::string msg = errc.message();
Twine twine = Twine("Cannot open ") + _path + ": " + msg;
return twine.str();
}
/// \brief Get the list of files
range<InputGraph::FileIterT> files() {
return make_range(_files.begin(), _files.end());
}
/// \brief number of files.
size_t numFiles() const { return _files.size(); }
/// \brief add a file to the list of files
virtual void addFiles(InputGraph::FileVectorT files) {
for (auto &ai : files)
_files.push_back(std::move(ai));
}
/// \brief Reset the file index if the resolver needs to process
/// the node again.
virtual void resetNextIndex();
/// \brief Set the resolve state for the FileNode.
virtual void setResolveState(uint32_t resolveState) {
_resolveState = resolveState;
}
/// \brief Retrieve the resolve state of the FileNode.
virtual uint32_t getResolveState() const { return _resolveState; }
protected:
/// \brief Read the file into _buffer.
error_code getBuffer(StringRef filePath);
StringRef _path; // The path of the Input file
InputGraph::FileVectorT _files; // A vector of lld File objects
std::unique_ptr<MemoryBuffer> _buffer; // Memory buffer to actual
// contents
uint32_t _resolveState; // The resolve state of the file
uint32_t _nextFileIndex; // The next file that would be processed by the
// resolver
};
/// \brief A Control node which contains a group of InputElements
/// This affects the resolver so that it resolves undefined symbols
/// in the group completely before looking at other input files that
/// follow the group
class Group : public ControlNode {
public:
Group(int64_t ordinal)
: ControlNode(ControlNode::ControlKind::Group, ordinal) {}
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::Control;
}
/// \brief Process input element and add it to the group
virtual bool processInputElement(std::unique_ptr<InputElement> element) {
_elements.push_back(std::move(element));
return true;
}
virtual ErrorOr<File &> getNextFile();
};
/// \brief Represents Internal Input files
class SimpleFileNode : public InputElement {
public:
SimpleFileNode(StringRef path, int64_t ordinal = -1);
virtual ErrorOr<StringRef> path(const LinkingContext &) const {
return _path;
}
// The saved input path thats used when a file is not found while
// trying to parse a file
StringRef getUserPath() const { return _path; }
virtual ~SimpleFileNode() {}
/// \brief Casting support
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::SimpleFile;
}
/// \brief Get the list of files
range<InputGraph::FileIterT> files() {
return make_range(_files.begin(), _files.end());
}
/// \brief number of files.
size_t numFiles() const { return _files.size(); }
/// \brief add a file to the list of files
virtual void appendInputFile(std::unique_ptr<File> f) {
_files.push_back(std::move(f));
}
/// \brief add a file to the list of files
virtual void appendInputFiles(InputGraph::FileVectorT files) {
for (auto &ai : files)
_files.push_back(std::move(ai));
}
/// \brief validates the Input Element
virtual bool validate() { return true; }
/// \brief Dump the Input Element
virtual bool dump(raw_ostream &) { return true; }
/// \brief parse the input element
virtual error_code parse(const LinkingContext &, raw_ostream &) {
return error_code::success();
}
/// \brief Return the next File thats part of this node to the
/// resolver.
virtual ErrorOr<File &> getNextFile() {
if (_nextFileIndex == _files.size())
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
/// \brief Set the resolver state.
virtual void setResolveState(uint32_t resolveState) {
_resolveState = resolveState;
}
/// \brief Retrieve the resolve state.
virtual uint32_t getResolveState() const { return _resolveState; }
// Do nothing here.
virtual void resetNextIndex() {}
protected:
StringRef _path; // A string associated with this file.
InputGraph::FileVectorT _files; // Vector of lld::File objects
uint32_t _nextFileIndex; // The next file that would be processed by the
// resolver
uint32_t _resolveState; // The resolve state associated with this Node
};
} // namespace lld
#endif // LLD_DRIVER_INPUT_GRAPH_H

View File

@@ -1,133 +0,0 @@
//===- include/Core/Instrumentation.h - Instrumentation API ---------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Provide an Instrumentation API that optionally uses VTune interfaces.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_INSTRUMENTATION_H
#define LLD_CORE_INSTRUMENTATION_H
#include "llvm/Support/Compiler.h"
#include <utility>
#ifdef LLD_HAS_VTUNE
# include <ittnotify.h>
#endif
namespace lld {
#ifdef LLD_HAS_VTUNE
/// \brief A unique global scope for instrumentation data.
///
/// Domains last for the lifetime of the application and cannot be destroyed.
/// Multiple Domains created with the same name represent the same domain.
class Domain {
__itt_domain *_domain;
public:
explicit Domain(const char *name) : _domain(__itt_domain_createA(name)) {}
operator __itt_domain *() const { return _domain; }
__itt_domain *operator->() const { return _domain; }
};
/// \brief A global reference to a string constant.
///
/// These are uniqued by the ITT runtime and cannot be deleted. They are not
/// specific to a domain.
///
/// Prefer reusing a single StringHandle over passing a ntbs when the same
/// string will be used often.
class StringHandle {
__itt_string_handle *_handle;
public:
StringHandle(const char *name) : _handle(__itt_string_handle_createA(name)) {}
operator __itt_string_handle *() const { return _handle; }
};
/// \brief A task on a single thread. Nests within other tasks.
///
/// Each thread has its own task stack and tasks nest recursively on that stack.
/// A task cannot transfer threads.
///
/// SBRM is used to ensure task starts and ends are ballanced. The lifetime of
/// a task is either the liftime of this object, or until end is called.
class ScopedTask {
__itt_domain *_domain;
ScopedTask(const ScopedTask &) LLVM_DELETED_FUNCTION;
ScopedTask &operator=(const ScopedTask &) LLVM_DELETED_FUNCTION;
public:
/// \brief Create a task in Domain \p d named \p s.
ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) {
__itt_task_begin(d, __itt_null, __itt_null, s);
}
ScopedTask(ScopedTask &&other) {
*this = std::move(other);
}
ScopedTask &operator=(ScopedTask &&other) {
_domain = other._domain;
other._domain = nullptr;
return *this;
}
/// \brief Prematurely end this task.
void end() {
if (_domain)
__itt_task_end(_domain);
_domain = nullptr;
}
~ScopedTask() { end(); }
};
/// \brief A specific point in time. Allows metadata to be associated.
class Marker {
public:
Marker(const Domain &d, const StringHandle &s) {
__itt_marker(d, __itt_null, s, __itt_scope_global);
}
};
#else
class Domain {
public:
Domain(const char *name) {}
};
class StringHandle {
public:
StringHandle(const char *name) {}
};
class ScopedTask {
public:
ScopedTask(const Domain &d, const StringHandle &s) {}
void end() {}
};
class Marker {
public:
Marker(const Domain &d, const StringHandle &s) {}
};
#endif
inline const Domain &getDefaultDomain() {
static Domain domain("org.llvm.lld");
return domain;
}
} // end namespace lld.
#endif

View File

@@ -1,92 +0,0 @@
//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file forward declares and imports various common LLVM datatypes that
// lld wants to use unqualified.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_LLVM_H
#define LLD_CORE_LLVM_H
// This should be the only #include, force #includes of all the others on
// clients.
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/Casting.h"
#include <utility>
namespace llvm {
// ADT's.
class StringRef;
class Twine;
class MemoryBuffer;
template<typename T> class ArrayRef;
template<class T> class OwningPtr;
template<unsigned InternalLen> class SmallString;
template<typename T, unsigned N> class SmallVector;
template<typename T> class SmallVectorImpl;
template<typename T>
struct SaveAndRestore;
template<typename T>
class ErrorOr;
// Reference counting.
template <typename T> class IntrusiveRefCntPtr;
template <typename T> struct IntrusiveRefCntPtrInfo;
template <class Derived> class RefCountedBase;
class RefCountedBaseVPTR;
class error_code;
class raw_ostream;
// TODO: DenseMap, ...
}
namespace lld {
// Casting operators.
using llvm::isa;
using llvm::cast;
using llvm::dyn_cast;
using llvm::dyn_cast_or_null;
using llvm::cast_or_null;
// ADT's.
using llvm::StringRef;
using llvm::Twine;
using llvm::MemoryBuffer;
using llvm::ArrayRef;
using llvm::OwningPtr;
using llvm::SmallString;
using llvm::SmallVector;
using llvm::SmallVectorImpl;
using llvm::SaveAndRestore;
using llvm::ErrorOr;
// Reference counting.
using llvm::IntrusiveRefCntPtr;
using llvm::IntrusiveRefCntPtrInfo;
using llvm::RefCountedBase;
using llvm::RefCountedBaseVPTR;
using llvm::error_code;
using llvm::raw_ostream;
} // end namespace clang.
namespace std {
template <> struct hash<llvm::StringRef> {
public:
size_t operator()(const llvm::StringRef &s) const {
return llvm::hash_value(s);
}
};
}
#endif

View File

@@ -1,378 +0,0 @@
//===- lld/Core/LinkingContext.h - Linker Target Info Interface -----------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_LINKING_CONTEXT_H
#define LLD_CORE_LINKING_CONTEXT_H
#include "lld/Core/Error.h"
#include "lld/Core/InputGraph.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/range.h"
#include "lld/Core/Reference.h"
#include "lld/ReaderWriter/Reader.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
#include <vector>
namespace llvm {
class Triple;
}
namespace lld {
class PassManager;
class File;
class Writer;
class InputGraph;
class InputElement;
/// \brief The LinkingContext class encapsulates "what and how" to link.
///
/// The base class LinkingContext contains the options needed by core linking.
/// Subclasses of LinkingContext have additional options needed by specific
/// Readers
/// and Writers. For example, ELFLinkingContext has methods that supplies
/// options
/// to the ELF Reader and Writer.
class LinkingContext {
public:
/// \brief The types of output file that the linker
/// creates.
enum class OutputFileType : uint8_t {
Default, // The default output type for this target
YAML, // The output type is set to YAML
Native // The output file format is Native (Atoms)
};
virtual ~LinkingContext();
/// \name Methods needed by core linking
/// @{
/// Name of symbol linker should use as "entry point" to program,
/// usually "main" or "start".
virtual StringRef entrySymbolName() const { return _entrySymbolName; }
/// Whether core linking should remove Atoms not reachable by following
/// References from the entry point Atom or from all global scope Atoms
/// if globalsAreDeadStripRoots() is true.
bool deadStrip() const { return _deadStrip; }
/// Only used if deadStrip() returns true. Means all global scope Atoms
/// should be marked live (along with all Atoms they reference). Usually
/// this method returns false for main executables, but true for dynamic
/// shared libraries.
bool globalsAreDeadStripRoots() const {
assert(_deadStrip && "only applicable when deadstripping enabled");
return _globalsAreDeadStripRoots;
}
/// Only used if deadStrip() returns true. This method returns the names
/// of DefinedAtoms that should be marked live (along with all Atoms they
/// reference). Only Atoms with scope scopeLinkageUnit or scopeGlobal can
/// be kept live using this method.
const std::vector<StringRef> &deadStripRoots() const {
return _deadStripRoots;
}
/// Add the given symbol name to the dead strip root set. Only used if
/// deadStrip() returns true.
void addDeadStripRoot(StringRef symbolName) {
assert(_deadStrip && "only applicable when deadstripping enabled");
assert(!symbolName.empty() && "Empty symbol cannot be a dead strip root");
_deadStripRoots.push_back(symbolName);
}
/// Archive files (aka static libraries) are normally lazily loaded. That is,
/// object files within an archive are only loaded and linked in, if the
/// object file contains a DefinedAtom which will replace an existing
/// UndefinedAtom. If this method returns true, core linking will also look
/// for archive members to replace existing tentative definitions in addition
/// to replacing undefines. Note: a "tentative definition" (also called a
/// "common" symbols) is a C (but not C++) concept. They are modeled in lld
/// as a DefinedAtom with merge() of mergeAsTentative.
bool searchArchivesToOverrideTentativeDefinitions() const {
return _searchArchivesToOverrideTentativeDefinitions;
}
/// Normally core linking will turn a tentative definition into a real
/// definition if not replaced by a real DefinedAtom from some object file.
/// If this method returns true, core linking will search all supplied
/// dynamic shared libraries for symbol names that match remaining tentative
/// definitions. If any are found, the corresponding tentative definition
/// atom is replaced with SharedLibraryAtom.
bool searchSharedLibrariesToOverrideTentativeDefinitions() const {
return _searchSharedLibrariesToOverrideTentativeDefinitions;
}
/// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
/// SharedLibraryAtom for the link to be successful. This method controls
/// whether core linking prints out a list of remaining UndefinedAtoms.
///
/// \todo This should be a method core linking calls with a list of the
/// UndefinedAtoms so that different drivers can format the error message
/// as needed.
bool printRemainingUndefines() const { return _printRemainingUndefines; }
/// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
/// SharedLibraryAtom for the link to be successful. This method controls
/// whether core linking considers remaining undefines to be an error.
bool allowRemainingUndefines() const { return _allowRemainingUndefines; }
/// In the lld model, a SharedLibraryAtom is a proxy atom for something
/// that will be found in a dynamic shared library when the program runs.
/// A SharedLibraryAtom optionally contains the name of the shared library
/// in which to find the symbol name at runtime. Core linking may merge
/// two SharedLibraryAtom with the same name. If this method returns true,
/// when merging core linking will also verify that they both have the same
/// loadName() and if not print a warning.
///
/// \todo This should be a method core linking calls so that drivers can
/// format the warning as needed.
bool warnIfCoalesableAtomsHaveDifferentLoadName() const {
return _warnIfCoalesableAtomsHaveDifferentLoadName;
}
/// In C/C++ you can mark a function's prototype with
/// __attribute__((weak_import)) or __attribute__((weak)) to say the function
/// may not be available at runtime and/or build time and in which case its
/// address will evaluate to NULL. In lld this is modeled using the
/// UndefinedAtom::canBeNull() method. During core linking, UndefinedAtom
/// with the same name are automatically merged. If this method returns
/// true, core link also verfies that the canBeNull() value for merged
/// UndefinedAtoms are the same and warns if not.
///
/// \todo This should be a method core linking calls so that drivers can
/// format the warning as needed.
bool warnIfCoalesableAtomsHaveDifferentCanBeNull() const {
return _warnIfCoalesableAtomsHaveDifferentCanBeNull;
}
/// Normally, every UndefinedAtom must be replaced by a DefinedAtom or a
/// SharedLibraryAtom for the link to be successful. This method controls
/// whether core linking considers remaining undefines from the shared library
/// to be an error.
bool allowShlibUndefines() const { return _allowShlibUndefines; }
/// If true, core linking will write the path to each input file to stdout
/// (i.e. llvm::outs()) as it is used. This is used to implement the -t
/// linker option.
///
/// \todo This should be a method core linking calls so that drivers can
/// format the line as needed.
bool logInputFiles() const { return _logInputFiles; }
/// Parts of LLVM use global variables which are bound to command line
/// options (see llvm::cl::Options). This method returns "command line"
/// options which are used to configure LLVM's command line settings.
/// For instance the -debug-only XXX option can be used to dynamically
/// trace different parts of LLVM and lld.
const std::vector<const char *> &llvmOptions() const { return _llvmOptions; }
/// \name Methods used by Drivers to configure TargetInfo
/// @{
void setOutputPath(StringRef str) { _outputPath = str; }
// Set the entry symbol name. You may also need to call addDeadStripRoot() for
// the symbol if your platform supports dead-stripping, so that the symbol
// will not be removed from the output.
void setEntrySymbolName(StringRef name) {
_entrySymbolName = name;
}
void setDeadStripping(bool enable) { _deadStrip = enable; }
void setGlobalsAreDeadStripRoots(bool v) { _globalsAreDeadStripRoots = v; }
void setSearchArchivesToOverrideTentativeDefinitions(bool search) {
_searchArchivesToOverrideTentativeDefinitions = search;
}
void setSearchSharedLibrariesToOverrideTentativeDefinitions(bool search) {
_searchSharedLibrariesToOverrideTentativeDefinitions = search;
}
void setWarnIfCoalesableAtomsHaveDifferentCanBeNull(bool warn) {
_warnIfCoalesableAtomsHaveDifferentCanBeNull = warn;
}
void setWarnIfCoalesableAtomsHaveDifferentLoadName(bool warn) {
_warnIfCoalesableAtomsHaveDifferentLoadName = warn;
}
void setPrintRemainingUndefines(bool print) {
_printRemainingUndefines = print;
}
void setAllowRemainingUndefines(bool allow) {
_allowRemainingUndefines = allow;
}
void setAllowShlibUndefines(bool allow) { _allowShlibUndefines = allow; }
void setLogInputFiles(bool log) { _logInputFiles = log; }
void appendLLVMOption(const char *opt) { _llvmOptions.push_back(opt); }
virtual void setInputGraph(std::unique_ptr<InputGraph> inputGraph) {
_inputGraph = std::move(inputGraph);
}
virtual InputGraph &inputGraph() const { return *_inputGraph; }
/// This method adds undefined symbols specified by the -u option to the to
/// the list of undefined symbols known to the linker. This option essentially
/// forces an undefined symbol to be create. You may also need to call
/// addDeadStripRoot() for the symbol if your platform supports dead
/// stripping, so that the symbol will not be removed from the output.
void addInitialUndefinedSymbol(StringRef symbolName) {
_initialUndefinedSymbols.push_back(symbolName);
}
/// Iterators for symbols that appear on the command line
typedef std::vector<StringRef> StringRefVector;
typedef StringRefVector::iterator StringRefVectorIter;
typedef StringRefVector::const_iterator StringRefVectorConstIter;
/// Create linker internal files containing atoms for the linker to include
/// during link. Flavors can override this function in their LinkingContext
/// to add more internal files. These internal files are positioned before
/// the actual input files.
virtual bool createInternalFiles(std::vector<std::unique_ptr<File> > &) const;
/// Return the list of undefined symbols that are specified in the
/// linker command line, using the -u option.
range<const StringRef *> initialUndefinedSymbols() const {
return _initialUndefinedSymbols;
}
/// After all set* methods are called, the Driver calls this method
/// to validate that there are no missing options or invalid combinations
/// of options. If there is a problem, a description of the problem
/// is written to the supplied stream.
///
/// \returns true if there is an error with the current settings.
bool validate(raw_ostream &diagnostics);
/// @}
/// \name Methods used by Driver::link()
/// @{
/// Returns the file system path to which the linked output should be written.
///
/// \todo To support in-memory linking, we need an abstraction that allows
/// the linker to write to an in-memory buffer.
StringRef outputPath() const { return _outputPath; }
/// Set the various output file types that the linker would
/// create
bool setOutputFileType(StringRef outputFileType) {
if (outputFileType.equals_lower("yaml"))
_outputFileType = OutputFileType::YAML;
else if (outputFileType.equals_lower("native"))
_outputFileType = OutputFileType::YAML;
else
return false;
return true;
}
/// Returns the output file that that the linker needs to create
OutputFileType outputFileType() const { return _outputFileType; }
/// Returns the YAML reader.
virtual Reader &getYAMLReader() const { return *_yamlReader; }
/// Returns the LLD Native file format reader.
virtual Reader &getNativeReader() const { return *_nativeReader; }
/// Return the default reader for the target
virtual Reader &getDefaultReader() const = 0;
/// This method is called by core linking to give the Writer a chance
/// to add file format specific "files" to set of files to be linked. This is
/// how file format specific atoms can be added to the link.
virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &) const;
/// This method is called by core linking to build the list of Passes to be
/// run on the merged/linked graph of all input files.
virtual void addPasses(PassManager &pm);
/// Calls through to the writeFile() method on the specified Writer.
///
/// \param linkedFile This is the merged/linked graph of all input file Atoms.
virtual error_code writeFile(const File &linkedFile) const;
/// nextFile returns the next file that needs to be processed by the resolver.
/// The LinkingContext's can override the default behavior to change the way
/// the resolver operates. This uses the currentInputElement. When there are
/// no more files to be processed an appropriate InputGraphError is
/// returned. Ordinals are assigned to files returned by nextFile, which means
/// ordinals would be assigned in the way files are resolved.
virtual ErrorOr<File &> nextFile();
/// Set the resolver state for the current Input element This is used by the
/// InputGraph to decide the next file that needs to be processed for various
/// types of nodes in the InputGraph. The resolver state is nothing but a
/// bitmask of various types of states that the resolver handles when adding
/// atoms.
virtual void setResolverState(uint32_t resolverState);
/// Return the next ordinal and Increment it.
virtual uint64_t getNextOrdinalAndIncrement() const { return _nextOrdinal++; }
/// @}
/// \name Methods needed by YAML I/O and error messages to convert Kind values
/// to and from strings.
/// @{
/// Abstract method to parse a kind name string into an integral
/// Reference::Kind
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const = 0;
/// Abstract method to return the name for a given integral
/// Reference::Kind.
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind k) const = 0;
/// @}
protected:
LinkingContext(); // Must be subclassed
/// Abstract method to lazily instantiate the Writer.
virtual Writer &writer() const = 0;
/// Method to create a internal file for the entry symbol
virtual std::unique_ptr<File> createEntrySymbolFile() const;
/// Method to create a internal file for an undefined symbol
virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
StringRef _outputPath;
StringRef _entrySymbolName;
bool _deadStrip;
bool _globalsAreDeadStripRoots;
bool _searchArchivesToOverrideTentativeDefinitions;
bool _searchSharedLibrariesToOverrideTentativeDefinitions;
bool _warnIfCoalesableAtomsHaveDifferentCanBeNull;
bool _warnIfCoalesableAtomsHaveDifferentLoadName;
bool _printRemainingUndefines;
bool _allowRemainingUndefines;
bool _logInputFiles;
bool _allowShlibUndefines;
OutputFileType _outputFileType;
std::vector<StringRef> _deadStripRoots;
std::vector<const char *> _llvmOptions;
std::unique_ptr<Reader> _yamlReader;
std::unique_ptr<Reader> _nativeReader;
StringRefVector _initialUndefinedSymbols;
std::unique_ptr<InputGraph> _inputGraph;
mutable llvm::BumpPtrAllocator _allocator;
InputElement *_currentInputElement;
mutable uint64_t _nextOrdinal;
private:
/// Validate the subclass bits. Only called by validate.
virtual bool validateImpl(raw_ostream &diagnostics) = 0;
};
} // end namespace lld
#endif

View File

@@ -1,271 +0,0 @@
//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_PARALLEL_H
#define LLD_CORE_PARALLEL_H
#include "lld/Core/Instrumentation.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/range.h"
#include "llvm/Support/MathExtras.h"
#ifdef _MSC_VER
// Exceptions are disabled so this isn't defined, but concrt assumes it is.
namespace {
void *__uncaught_exception() { return nullptr; }
}
#endif
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <stack>
#ifdef _MSC_VER
#include <concrt.h>
#include <ppl.h>
#endif
namespace lld {
/// \brief Allows one or more threads to wait on a potentially unknown number of
/// events.
///
/// A latch starts at \p count. inc() increments this, and dec() decrements it.
/// All calls to sync() will block while the count is not 0.
///
/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
class Latch {
uint32_t _count;
mutable std::mutex _condMut;
mutable std::condition_variable _cond;
public:
explicit Latch(uint32_t count = 0) : _count(count) {}
~Latch() { sync(); }
void inc() {
std::unique_lock<std::mutex> lock(_condMut);
++_count;
}
void dec() {
std::unique_lock<std::mutex> lock(_condMut);
if (--_count == 0)
_cond.notify_all();
}
void sync() const {
std::unique_lock<std::mutex> lock(_condMut);
_cond.wait(lock, [&] {
return _count == 0;
});
}
};
/// \brief An abstract class that takes closures and runs them asynchronously.
class Executor {
public:
virtual ~Executor() {}
virtual void add(std::function<void()> func) = 0;
};
/// \brief An implementation of an Executor that runs closures on a thread pool
/// in filo order.
class ThreadPoolExecutor : public Executor {
public:
explicit ThreadPoolExecutor(unsigned threadCount =
std::thread::hardware_concurrency())
: _stop(false), _done(threadCount) {
// Spawn all but one of the threads in another thread as spawning threads
// can take a while.
std::thread([&, threadCount] {
for (std::size_t i = 1; i < threadCount; ++i) {
std::thread([=] {
work();
}).detach();
}
work();
}).detach();
}
~ThreadPoolExecutor() {
std::unique_lock<std::mutex> lock(_mutex);
_stop = true;
lock.unlock();
_cond.notify_all();
// Wait for ~Latch.
}
virtual void add(std::function<void()> f) {
std::unique_lock<std::mutex> lock(_mutex);
_workStack.push(f);
lock.unlock();
_cond.notify_one();
}
private:
void work() {
while (true) {
std::unique_lock<std::mutex> lock(_mutex);
_cond.wait(lock, [&] {
return _stop || !_workStack.empty();
});
if (_stop)
break;
auto task = _workStack.top();
_workStack.pop();
lock.unlock();
task();
}
_done.dec();
}
std::atomic<bool> _stop;
std::stack<std::function<void()>> _workStack;
std::mutex _mutex;
std::condition_variable _cond;
Latch _done;
};
#ifdef _MSC_VER
/// \brief An Executor that runs tasks via ConcRT.
class ConcRTExecutor : public Executor {
struct Taskish {
Taskish(std::function<void()> task) : _task(task) {}
std::function<void()> _task;
static void run(void *p) {
Taskish *self = static_cast<Taskish *>(p);
self->_task();
concurrency::Free(self);
}
};
public:
virtual void add(std::function<void()> func) {
Concurrency::CurrentScheduler::ScheduleTask(Taskish::run,
new (concurrency::Alloc(sizeof(Taskish))) Taskish(func));
}
};
inline Executor *getDefaultExecutor() {
static ConcRTExecutor exec;
return &exec;
}
#else
inline Executor *getDefaultExecutor() {
static ThreadPoolExecutor exec;
return &exec;
}
#endif
/// \brief Allows launching a number of tasks and waiting for them to finish
/// either explicitly via sync() or implicitly on destruction.
class TaskGroup {
Latch _latch;
public:
void spawn(std::function<void()> f) {
_latch.inc();
getDefaultExecutor()->add([&, f] {
f();
_latch.dec();
});
}
void sync() const { _latch.sync(); }
};
#ifdef _MSC_VER
// Use ppl parallel_sort on Windows.
template <class RandomAccessIterator, class Comp>
void parallel_sort(
RandomAccessIterator start, RandomAccessIterator end,
const Comp &comp = std::less<
typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
concurrency::parallel_sort(start, end, comp);
}
#else
namespace detail {
const ptrdiff_t minParallelSize = 1024;
/// \brief Inclusive median.
template <class RandomAccessIterator, class Comp>
RandomAccessIterator medianOf3(RandomAccessIterator start,
RandomAccessIterator end, const Comp &comp) {
RandomAccessIterator mid = start + (std::distance(start, end) / 2);
return comp(*start, *(end - 1))
? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start)
: end - 1)
: (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1)
: start);
}
template <class RandomAccessIterator, class Comp>
void parallel_quick_sort(RandomAccessIterator start, RandomAccessIterator end,
const Comp &comp, TaskGroup &tg, size_t depth) {
// Do a sequential sort for small inputs.
if (std::distance(start, end) < detail::minParallelSize || depth == 0) {
std::sort(start, end, comp);
return;
}
// Partition.
auto pivot = medianOf3(start, end, comp);
// Move pivot to end.
std::swap(*(end - 1), *pivot);
pivot = std::partition(start, end - 1, [end](decltype(*start) v) {
return v < *(end - 1);
});
// Move pivot to middle of partition.
std::swap(*pivot, *(end - 1));
// Recurse.
tg.spawn([=, &tg] {
parallel_quick_sort(start, pivot, comp, tg, depth - 1);
});
parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1);
}
}
template <class RandomAccessIterator, class Comp>
void parallel_sort(
RandomAccessIterator start, RandomAccessIterator end,
const Comp &comp = std::less<
typename std::iterator_traits<RandomAccessIterator>::value_type>()) {
TaskGroup tg;
detail::parallel_quick_sort(start, end, comp, tg,
llvm::Log2_64(std::distance(start, end)) + 1);
}
#endif
template <class T> void parallel_sort(T *start, T *end) {
parallel_sort(start, end, std::less<T>());
}
#ifdef _MSC_VER
// Use ppl parallel_for_each on Windows.
template <class Iterator, class Func>
void parallel_for_each(Iterator begin, Iterator end, Func func) {
concurrency::parallel_for_each(begin, end, func);
}
#else
template <class Iterator, class Func>
void parallel_for_each(Iterator begin, Iterator end, Func func) {
// TODO: Make this parallel.
std::for_each(begin, end, func);
}
#endif
} // end namespace lld
#endif

View File

@@ -1,118 +0,0 @@
//===------ Core/Pass.h - Base class for linker passes --------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_PASS_H
#define LLD_CORE_PASS_H
#include "lld/Core/Atom.h"
#include "lld/Core/File.h"
#include "lld/Core/range.h"
#include "lld/Core/Reference.h"
#include <vector>
namespace lld {
class DefinedAtom;
class MutableFile;
/// Once the core linking is done (which resolves references, coalesces atoms
/// and produces a complete Atom graph), the linker runs a series of passes
/// on the Atom graph. The graph is modeled as a File, which means the pass
/// has access to all the atoms and to File level attributes. Each pass does
/// a particular transformation to the Atom graph or to the File attributes.
///
/// This is the abstract base class for all passes. A Pass does its
/// actual work in it perform() method. It can iterator over Atoms in the
/// graph using the *begin()/*end() atom iterator of the File. It can add
/// new Atoms to the graph using the File's addAtom() method.
class Pass {
public:
virtual ~Pass() { }
/// Do the actual work of the Pass.
virtual void perform(std::unique_ptr<MutableFile> &mergedFile) = 0;
protected:
// Only subclassess can be instantiated.
Pass() { }
};
/// Pass for adding stubs (PLT entries) for calls to functions
/// outside the linkage unit. This class is subclassed by each
/// file format Writer which implements the pure virtual methods.
class StubsPass : public Pass {
public:
StubsPass() : Pass() {}
/// Scans all Atoms looking for call-site uses of SharedLibraryAtoms
/// and transfroms the call-site to call a stub instead using the
/// helper methods below.
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
/// If true, the pass should use stubs for references
/// to shared library symbols. If false, the pass
/// will generate relocations on the text segment which the
/// runtime loader will use to patch the program at runtime.
virtual bool noTextRelocs() = 0;
/// Returns whether the Reference kind is for a call site. The pass
/// uses this to find calls that need to be indirected through a stub.
virtual bool isCallSite(int32_t) = 0;
/// Returns a file format specific atom for a stub/PLT entry which contains
/// instructions which jump to the specified atom. May be called multiple
/// times for the same target atom, in which case this method should return
/// the same stub atom.
virtual const DefinedAtom *getStub(const Atom &target) = 0;
/// After the default implementation of perform() is done calling getStub(),
/// it will call this method to add all the stub (and support) atoms to the
/// master file object.
virtual void addStubAtoms(MutableFile &masterFile) = 0;
};
/// Pass for adding GOT entries for pointers to functions/data
/// outside the linkage unit. This class is subclassed by each
/// file format Writer which implements the pure virtual methods.
class GOTPass : public Pass {
public:
GOTPass() : Pass() {}
/// Scans all Atoms looking for pointer to SharedLibraryAtoms
/// and transfroms them to a pointer to a GOT entry using the
/// helper methods below.
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
/// If true, the pass will use GOT entries for references
/// to shared library symbols. If false, the pass
/// will generate relocations on the text segment which the
/// runtime loader will use to patch the program at runtime.
virtual bool noTextRelocs() = 0;
/// Returns whether the Reference kind is a pre-instantiated GOT access.
/// The default implementation of perform() uses this to figure out
/// what GOT entries to instantiate.
virtual bool isGOTAccess(int32_t, bool &canBypassGOT) = 0;
/// The file format Writer needs to alter the reference kind from a
/// pre-instantiated GOT access to an actual access. If targetIsNowGOT is
/// true, the pass has instantiated a GOT atom and altered the reference's
/// target to point to that atom. If targetIsNowGOT is false, the pass
/// determined a GOT entry is not needed because the reference site can
/// directly access the target.
virtual void updateReferenceToGOT(const Reference*, bool targetIsNowGOT) = 0;
/// Returns a file format specific atom for a GOT entry targeting
/// the specified atom.
virtual const DefinedAtom *makeGOTEntry(const Atom &target) = 0;
};
} // namespace lld
#endif // LLD_CORE_PASS_H

View File

@@ -1,43 +0,0 @@
//===- lld/Core/PassManager.h - Manage linker passes ----------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_PASS_MANAGER_H
#define LLD_CORE_PASS_MANAGER_H
#include "lld/Core/LLVM.h"
#include "lld/Core/Pass.h"
#include <memory>
#include <vector>
namespace lld {
class MutableFile;
class Pass;
/// \brief Owns and runs a collection of passes.
///
/// This class is currently just a container for passes and a way to run them.
///
/// In the future this should handle timing pass runs, running parallel passes,
/// and validate/satisfy pass dependencies.
class PassManager {
public:
void add(std::unique_ptr<Pass> pass) {
_passes.push_back(std::move(pass));
}
error_code runOnFile(std::unique_ptr<MutableFile> &);
private:
/// \brief Passes in the order they should run.
std::vector<std::unique_ptr<Pass>> _passes;
};
} // end namespace lld
#endif

View File

@@ -1,112 +0,0 @@
//===- Core/References.h - A Reference to Another Atom --------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_REFERENCES_H
#define LLD_CORE_REFERENCES_H
#include "llvm/Support/DataTypes.h"
#include "llvm/ADT/StringSwitch.h"
namespace lld {
class Atom;
///
/// The linker has a Graph Theory model of linking. An object file is seen
/// as a set of Atoms with References to other Atoms. Each Atom is a node
/// and each Reference is an edge.
///
/// For example if a function contains a call site to "malloc" 40 bytes into
/// the Atom, then the function Atom will have a Reference of: offsetInAtom=40,
/// kind=callsite, target=malloc, addend=0.
///
/// Besides supporting traditional "relocations", References are also used
/// grouping atoms (group comdat), forcing layout (one atom must follow
/// another), marking data-in-code (jump tables or ARM constants), etc.
///
class Reference {
public:
/// The meaning of positive kind values is architecture specific.
/// Negative kind values are architecture independent.
typedef int32_t Kind;
enum {
kindInGroup = -3,
kindLayoutAfter = -2,
kindLayoutBefore = -1,
kindTargetLow = 0
};
// A value to be added to the value of a target
typedef int64_t Addend;
/// What sort of reference this is.
Kind kind() const { return _kind; }
/// During linking, some optimizations may change the code gen and
/// hence the reference kind.
void setKind(Kind kind) { _kind = kind; };
virtual StringRef kindToString() const {
switch (kind()) {
case kindLayoutBefore:
return "layout-before";
case kindLayoutAfter:
return "layout-after";
case kindInGroup:
return "in-group";
default:
return "unknown";
}
}
virtual int32_t stringToKind(StringRef kindString) const {
if (kindString == "in-group")
return kindInGroup;
else if (kindString == "layout-before")
return kindLayoutBefore;
else if (kindString == "layout-after")
return kindLayoutAfter;
assert(0 && "unknown relocation kind");
return -1;
}
/// If the reference is a fixup in the Atom, then this returns the
/// byte offset into the Atom's content to do the fix up.
virtual uint64_t offsetInAtom() const = 0;
/// If the reference is an edge to another Atom, then this returns the
/// other Atom. Otherwise, it returns nullptr.
virtual const Atom *target() const = 0;
/// During linking, the linker may merge graphs which coalesces some nodes
/// (i.e. Atoms). To switch the target of a reference, this method is called.
virtual void setTarget(const Atom *) = 0;
/// Some relocations require a symbol and a value (e.g. foo + 4).
virtual Addend addend() const = 0;
/// During linking, some optimzations may change addend value.
virtual void setAddend(Addend) = 0;
protected:
/// Atom is an abstract base class. Only subclasses can access constructor.
Reference() {}
/// The memory for Reference objects is always managed by the owning File
/// object. Therefore, no one but the owning File object should call
/// delete on an Reference. In fact, some File objects may bulk allocate
/// an array of References, so they cannot be individually deleted by anyone.
virtual ~Reference() {}
Kind _kind;
};
} // namespace lld
#endif // LLD_CORE_REFERENCES_H

View File

@@ -1,128 +0,0 @@
//===- Core/Resolver.h - Resolves Atom References -------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_RESOLVER_H
#define LLD_CORE_RESOLVER_H
#include "lld/Core/File.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/SymbolTable.h"
#include "llvm/ADT/DenseSet.h"
#include <set>
#include <vector>
namespace lld {
class Atom;
class LinkingContext;
/// \brief The Resolver is responsible for merging all input object files
/// and producing a merged graph.
class Resolver {
public:
enum ResolverState {
StateNoChange = 0, // The default resolver state
StateNewDefinedAtoms = 1, // New defined atoms were added
StateNewUndefinedAtoms = 2, // New undefined atoms were added
StateNewSharedLibraryAtoms = 4, // New shared library atoms were added
StateNewAbsoluteAtoms = 8 // New absolute atoms were added
};
Resolver(LinkingContext &context)
: _context(context), _symbolTable(context),
_result(new MergedFile(context)), _haveLLVMObjs(false),
_addToFinalSection(false) {}
virtual ~Resolver() {}
// InputFiles::Handler methods
virtual void doDefinedAtom(const DefinedAtom&);
virtual void doUndefinedAtom(const UndefinedAtom&);
virtual void doSharedLibraryAtom(const SharedLibraryAtom &);
virtual void doAbsoluteAtom(const AbsoluteAtom &);
virtual void doFile(const File&);
// Handle files, this adds atoms from the current file thats
// being processed by the resolver
virtual void handleFile(const File &);
// Handle an archive library file.
virtual void handleArchiveFile(const File &);
// Handle a shared library file.
virtual void handleSharedLibrary(const File &);
/// @brief do work of merging and resolving and return list
bool resolve();
std::unique_ptr<MutableFile> resultFile() { return std::move(_result); }
private:
typedef std::function<void(StringRef, bool)> UndefCallback;
/// \brief The main function that iterates over the files to resolve
bool resolveUndefines();
void updateReferences();
void deadStripOptimize();
bool checkUndefines(bool final);
void removeCoalescedAwayAtoms();
void checkDylibSymbolCollisions();
void linkTimeOptimize();
void tweakAtoms();
void forEachUndefines(UndefCallback callback, bool searchForOverrides);
void markLive(const Atom &atom);
void addAtoms(const std::vector<const DefinedAtom *>&);
class MergedFile : public MutableFile {
public:
MergedFile(const LinkingContext &context)
: MutableFile(context, "<linker-internal>") {}
virtual const atom_collection<DefinedAtom> &defined() const {
return _definedAtoms;
}
virtual const atom_collection<UndefinedAtom>& undefined() const {
return _undefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom>& sharedLibrary() const {
return _sharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom>& absolute() const {
return _absoluteAtoms;
}
void addAtoms(std::vector<const Atom*>& atoms);
virtual void addAtom(const Atom& atom);
virtual DefinedAtomRange definedAtoms();
private:
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
};
LinkingContext &_context;
SymbolTable _symbolTable;
std::vector<const Atom *> _atoms;
std::set<const Atom *> _deadStripRoots;
std::vector<const Atom *> _atomsWithUnresolvedReferences;
llvm::DenseSet<const Atom *> _liveAtoms;
std::unique_ptr<MergedFile> _result;
bool _haveLLVMObjs;
bool _addToFinalSection;
};
} // namespace lld
#endif // LLD_CORE_RESOLVER_H

View File

@@ -1,33 +0,0 @@
//===- lld/Core/STDExtra.h - Helpers for the stdlib -----------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_STD_EXTRA_H
#define LLD_CORE_STD_EXTRA_H
namespace lld {
/// \brief Deleter for smart pointers that only calls the destructor. Memory is
/// managed elsewhere. A common use of this is for things allocated with a
/// BumpPtrAllocator.
template <class T>
struct destruct_delete {
void operator ()(T *ptr) {
ptr->~T();
}
};
// Sadly VS 2012 doesn't support template aliases.
// template <class T>
// using unique_bump_ptr = std::unique_ptr<T, destruct_delete<T>>;
#define LLD_UNIQUE_BUMP_PTR(...) \
std::unique_ptr<__VA_ARGS__, destruct_delete<__VA_ARGS__>>
} // end namespace lld
#endif

View File

@@ -1,57 +0,0 @@
//===- Core/SharedLibraryAtom.h - A Shared Library Atom -------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_SHARED_LIBRARY_ATOM_H
#define LLD_CORE_SHARED_LIBRARY_ATOM_H
#include "lld/Core/Atom.h"
namespace llvm {
class StringRef;
}
namespace lld {
/// A SharedLibraryAtom has no content.
/// It exists to represent a symbol which will be bound at runtime.
class SharedLibraryAtom : public Atom {
public:
enum class Type : uint32_t {
Unknown,
Code,
Data,
};
/// Returns shared library name used to load it at runtime.
/// On linux that is the DT_NEEDED name.
/// On Darwin it is the LC_DYLIB_LOAD dylib name.
/// On Windows it is the DLL name that to be referred from .idata section.
virtual StringRef loadName() const = 0;
/// Returns if shared library symbol can be missing at runtime and if
/// so the loader should silently resolve address of symbol to be nullptr.
virtual bool canBeNullAtRuntime() const = 0;
virtual Type type() const = 0;
virtual uint64_t size() const = 0;
static inline bool classof(const Atom *a) {
return a->definition() == definitionSharedLibrary;
}
static inline bool classof(const SharedLibraryAtom *) { return true; }
protected:
SharedLibraryAtom() : Atom(definitionSharedLibrary) {}
virtual ~SharedLibraryAtom() {}
};
} // namespace lld
#endif // LLD_CORE_SHARED_LIBRARY_ATOM_H

View File

@@ -1,42 +0,0 @@
//===- Core/SharedLibraryFile.h - Models shared libraries as Atoms --------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_SHARED_LIBRARY_FILE_H
#define LLD_CORE_SHARED_LIBRARY_FILE_H
#include "lld/Core/File.h"
#include "lld/Core/SharedLibraryAtom.h"
namespace lld {
///
/// The SharedLibraryFile subclass of File is used to represent dynamic
/// shared libraries being linked against.
///
class SharedLibraryFile : public File {
public:
virtual ~SharedLibraryFile() {}
static inline bool classof(const File *f) {
return f->kind() == kindSharedLibrary;
}
/// Check if the shared library exports a symbol with the specified name.
/// If so, return a SharedLibraryAtom which represents that exported
/// symbol. Otherwise return nullptr.
virtual const SharedLibraryAtom *exports(StringRef name,
bool dataSymbolOnly) const = 0;
protected:
/// only subclasses of SharedLibraryFile can be instantiated
explicit SharedLibraryFile(StringRef path) : File(path, kindSharedLibrary) {}
};
} // namespace lld
#endif // LLD_CORE_SHARED_LIBRARY_FILE_H

View File

@@ -1,110 +0,0 @@
//===- Core/SymbolTable.h - Main Symbol Table -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_SYMBOL_TABLE_H
#define LLD_CORE_SYMBOL_TABLE_H
#include "lld/Core/LLVM.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include <cstring>
#include <map>
#include <vector>
namespace lld {
class AbsoluteAtom;
class Atom;
class DefinedAtom;
class LinkingContext;
class ResolverOptions;
class SharedLibraryAtom;
class UndefinedAtom;
/// \brief The SymbolTable class is responsible for coalescing atoms.
///
/// All atoms coalescable by-name or by-content should be added.
/// The method replacement() can be used to find the replacement atom
/// if an atom has been coalesced away.
class SymbolTable {
public:
explicit SymbolTable(const LinkingContext &);
/// @brief add atom to symbol table
void add(const DefinedAtom &);
/// @brief add atom to symbol table
void add(const UndefinedAtom &);
/// @brief add atom to symbol table
void add(const SharedLibraryAtom &);
/// @brief add atom to symbol table
void add(const AbsoluteAtom &);
/// @brief checks if name is in symbol table and if so atom is not
/// UndefinedAtom
bool isDefined(StringRef sym);
/// @brief returns atom in symbol table for specified name (or nullptr)
const Atom *findByName(StringRef sym);
/// @brief returns vector of remaining UndefinedAtoms
void undefines(std::vector<const UndefinedAtom *>&);
/// returns vector of tentative definitions
void tentativeDefinitions(std::vector<StringRef> &);
/// @brief count of by-name entries in symbol table
unsigned int size();
/// @brief add atom to replacement table
void addReplacement(const Atom *replaced, const Atom *replacement);
/// @brief if atom has been coalesced away, return replacement, else return atom
const Atom *replacement(const Atom *);
private:
typedef llvm::DenseMap<const Atom *, const Atom *> AtomToAtom;
struct StringRefMappingInfo {
static StringRef getEmptyKey() { return StringRef(); }
static StringRef getTombstoneKey() { return StringRef(" ", 0); }
static unsigned getHashValue(StringRef const val) {
return llvm::HashString(val); }
static bool isEqual(StringRef const lhs,
StringRef const rhs) { return lhs.equals(rhs); }
};
typedef llvm::DenseMap<StringRef, const Atom *,
StringRefMappingInfo> NameToAtom;
struct AtomMappingInfo {
static const DefinedAtom * getEmptyKey() { return nullptr; }
static const DefinedAtom * getTombstoneKey() { return (DefinedAtom*)(-1); }
static unsigned getHashValue(const DefinedAtom * const Val);
static bool isEqual(const DefinedAtom * const LHS,
const DefinedAtom * const RHS);
};
typedef llvm::DenseSet<const DefinedAtom*, AtomMappingInfo> AtomContentSet;
void addByName(const Atom &);
void addByContent(const DefinedAtom &);
const LinkingContext &_context;
AtomToAtom _replacedAtoms;
NameToAtom _nameTable;
AtomContentSet _contentTable;
};
} // namespace lld
#endif // LLD_CORE_SYMBOL_TABLE_H

View File

@@ -1,17 +0,0 @@
include/lld/Core
~~~~~~~~~~~~~~~~
* The native/yaml reader/writer interfaces should be changed to return
an explanatory string if there is an error. The existing error_code
abstraction only works for returning low level OS errors. It does not
work for describing formatting issues.
* We need to design a diagnostics interface. It would be nice to share code
with Clang_ where possible.
* We need to add more attributes to File. In particular, we need cpu
and OS information (like target triples). We should also provide explicit
support for `LLVM IR module flags metadata`__.
.. __: http://llvm.org/docs/LangRef.html#module_flags
.. _Clang: http://clang.llvm.org/docs/InternalsManual.html#Diagnostics

View File

@@ -1,74 +0,0 @@
//===- Core/UndefinedAtom.h - An Undefined Atom ---------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_UNDEFINED_ATOM_H
#define LLD_CORE_UNDEFINED_ATOM_H
#include "lld/Core/Atom.h"
namespace lld {
/// An UndefinedAtom has no content.
/// It exists as a place holder for a future atom.
class UndefinedAtom : public Atom {
public:
/// Whether this undefined symbol needs to be resolved,
/// or whether it can just evaluate to nullptr.
/// This concept is often called "weak", but that term
/// is overloaded to mean other things too.
enum CanBeNull {
/// Normal symbols must be resolved at build time
canBeNullNever,
/// This symbol can be missing at runtime and will evalute to nullptr.
/// That is, the static linker still must find a definition (usually
/// is some shared library), but at runtime, the dynamic loader
/// will allow the symbol to be missing and resolved to nullptr.
///
/// On Darwin this is generated using a function prototype with
/// __attribute__((weak_import)).
/// On linux this is generated using a function prototype with
/// __attribute__((weak)).
/// On Windows this feature is not supported.
canBeNullAtRuntime,
/// This symbol can be missing at build time.
/// That is, the static linker will not error if a definition for
/// this symbol is not found at build time. Instead, the linker
/// will build an executable that lets the dynamic loader find the
/// symbol at runtime.
/// This feature is not supported on Darwin nor Windows.
/// On linux this is generated using a function prototype with
/// __attribute__((weak)).
canBeNullAtBuildtime
};
virtual CanBeNull canBeNull() const = 0;
static inline bool classof(const Atom *a) {
return a->definition() == definitionUndefined;
}
static inline bool classof(const UndefinedAtom *) { return true; }
/// Returns an undefined atom if this undefined symbol has a synonym. This is
/// mainly used in COFF. In COFF, an unresolved external symbol can have up to
/// one optional name (sym2) in addition to its regular name (sym1). If a
/// definition of sym1 exists, sym1 is resolved normally. Otherwise, all
/// references to sym1 refer to sym2 instead. In that case sym2 must be
/// resolved, or link will fail.
virtual const UndefinedAtom *fallback() const { return nullptr; }
protected:
UndefinedAtom() : Atom(definitionUndefined) {}
virtual ~UndefinedAtom() {}
};
} // namespace lld
#endif // LLD_CORE_UNDEFINED_ATOM_H

View File

@@ -1,739 +0,0 @@
//===-- lld/Core/range.h - Iterator ranges ----------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Iterator range type based on c++1y range proposal.
///
/// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html
///
//===----------------------------------------------------------------------===//
#ifndef LLD_CORE_RANGE_H
#define LLD_CORE_RANGE_H
#include "llvm/Support/Compiler.h"
#include <cassert>
#include <array>
#include <iterator>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
namespace lld {
// Nothing in this namespace is part of the exported interface.
namespace detail {
using std::begin;
using std::end;
/// Used as the result type of undefined functions.
struct undefined {};
template <typename R> class begin_result {
template <typename T> static auto check(T &&t) -> decltype(begin(t));
static undefined check(...);
public:
typedef decltype(check(std::declval<R>())) type;
};
template <typename R> class end_result {
template <typename T> static auto check(T &&t) -> decltype(end(t));
static undefined check(...);
public:
typedef decltype(check(std::declval<R>())) type;
};
// Things that begin and end work on, in compatible ways, are
// ranges. [stmt.ranged]
template <typename R>
struct is_range : std::is_same<typename detail::begin_result<R>::type,
typename detail::end_result<R>::type> {};
// This currently requires specialization and doesn't work for
// detecting \c range<>s or iterators. We should add
// \c contiguous_iterator_tag to fix that.
template <typename R> struct is_contiguous_range : std::false_type {};
template <typename R>
struct is_contiguous_range<R &> : is_contiguous_range<R> {};
template <typename R>
struct is_contiguous_range <R &&> : is_contiguous_range<R> {};
template <typename R>
struct is_contiguous_range<const R> : is_contiguous_range<R> {};
template <typename T, size_t N>
struct is_contiguous_range<T[N]> : std::true_type {};
template <typename T, size_t N>
struct is_contiguous_range<const T[N]> : std::true_type {};
template <typename T, size_t N>
struct is_contiguous_range<std::array<T, N> > : std::true_type {};
template <typename charT, typename traits, typename Allocator>
struct is_contiguous_range<
std::basic_string<charT, traits, Allocator> > : std::true_type {};
template <typename T, typename Allocator>
struct is_contiguous_range<std::vector<T, Allocator> > : std::true_type {};
// Removes cv qualifiers from all levels of a multi-level pointer
// type, not just the type level.
template <typename T> struct remove_all_cv_ptr {
typedef T type;
};
template <typename T> struct remove_all_cv_ptr<T *> {
typedef typename remove_all_cv_ptr<T>::type *type;
};
template <typename T> struct remove_all_cv_ptr<const T> {
typedef typename remove_all_cv_ptr<T>::type type;
};
template <typename T> struct remove_all_cv_ptr<volatile T> {
typedef typename remove_all_cv_ptr<T>::type type;
};
template <typename T> struct remove_all_cv_ptr<const volatile T> {
typedef typename remove_all_cv_ptr<T>::type type;
};
template <typename From, typename To>
struct conversion_preserves_array_indexing : std::false_type {};
template <typename FromVal, typename ToVal>
struct conversion_preserves_array_indexing<FromVal *,
ToVal *> : std::integral_constant<
bool, std::is_convertible<FromVal *, ToVal *>::value &&
std::is_same<typename remove_all_cv_ptr<FromVal>::type,
typename remove_all_cv_ptr<ToVal>::type>::value> {};
template <typename T>
LLVM_CONSTEXPR auto adl_begin(T &&t) -> decltype(begin(t)) {
return begin(std::forward<T>(t));
}
template <typename T> LLVM_CONSTEXPR auto adl_end(T &&t) -> decltype(end(t)) {
return end(std::forward<T>(t));
}
} // end namespace detail
/// A \c std::range<Iterator> represents a half-open iterator range
/// built from two iterators, \c 'begin', and \c 'end'. If \c end is
/// not reachable from \c begin, the behavior is undefined.
///
/// The mutability of elements of the range is controlled by the
/// Iterator argument. Instantiate
/// <code>range<<var>Foo</var>::iterator></code> or
/// <code>range<<var>T</var>*></code>, or call
/// <code>make_range(<var>non_const_container</var>)</code>, and you
/// get a mutable range. Instantiate
/// <code>range<<var>Foo</var>::const_iterator></code> or
/// <code>range<const <var>T</var>*></code>, or call
/// <code>make_range(<var>const_container</var>)</code>, and you get a
/// constant range.
///
/// \todo Inherit from std::pair<Iterator, Iterator>?
///
/// \todo This interface contains some functions that could be
/// provided as free algorithms rather than member functions, and all
/// of the <code>pop_*()</code> functions could be replaced by \c
/// slice() at the cost of some extra iterator copies. This makes
/// them more awkward to use, but makes it easier for users to write
/// their own types that follow the same interface. On the other hand,
/// a \c range_facade could be provided to help users write new
/// ranges, and it could provide the members. Such functions are
/// marked with a note in their documentation. (Of course, all of
/// these member functions could be provided as free functions using
/// the iterator access methods, but one goal here is to allow people
/// to program without touching iterators at all.)
template <typename Iterator> class range {
Iterator begin_, end_;
public:
/// \name types
/// @{
/// The iterator category of \c Iterator.
/// \todo Consider defining range categories. If they don't add
/// anything over the corresponding iterator categories, then
/// they're probably not worth defining.
typedef typename std::iterator_traits<
Iterator>::iterator_category iterator_category;
/// The type of elements of the range. Not cv-qualified.
typedef typename std::iterator_traits<Iterator>::value_type value_type;
/// The type of the size of the range and offsets within the range.
typedef typename std::iterator_traits<
Iterator>::difference_type difference_type;
/// The return type of element access methods: \c front(), \c back(), etc.
typedef typename std::iterator_traits<Iterator>::reference reference;
typedef typename std::iterator_traits<Iterator>::pointer pointer;
/// @}
/// \name constructors
/// @{
/// Creates a range of default-constructed (<em>not</em>
/// value-initialized) iterators. For most \c Iterator types, this
/// will be an invalid range.
range() : begin_(), end_() {}
/// \pre \c end is reachable from \c begin.
/// \post <code>this->begin() == begin && this->end() == end</code>
LLVM_CONSTEXPR range(Iterator begin, Iterator end)
: begin_(begin), end_(end) {}
/// \par Participates in overload resolution if:
/// - \c Iterator is not a pointer type,
/// - \c begin(r) and \c end(r) return the same type, and
/// - that type is convertible to \c Iterator.
///
/// \todo std::begin and std::end are overloaded between T& and
/// const T&, which means that if a container has only a non-const
/// begin or end method, then it's ill-formed to pass an rvalue to
/// the free function. To avoid that problem, we don't use
/// std::forward<> here, so begin() and end() are always called with
/// an lvalue. Another option would be to insist that rvalue
/// arguments to range() must have const begin() and end() methods.
template <typename R> LLVM_CONSTEXPR range(
R &&r,
typename std::enable_if<
!std::is_pointer<Iterator>::value &&
detail::is_range<R>::value &&
std::is_convertible<typename detail::begin_result<R>::type,
Iterator>::value>::type* = 0)
: begin_(detail::adl_begin(r)), end_(detail::adl_end(r)) {}
/// This constructor creates a \c range<T*> from any range with
/// contiguous iterators. Because dereferencing a past-the-end
/// iterator can be undefined behavior, empty ranges get initialized
/// with \c nullptr rather than \c &*begin().
///
/// \par Participates in overload resolution if:
/// - \c Iterator is a pointer type \c T*,
/// - \c begin(r) and \c end(r) return the same type,
/// - elements \c i of that type satisfy the invariant
/// <code>&*(i + N) == (&*i) + N</code>, and
/// - The result of <code>&*begin()</code> is convertible to \c T*
/// using only qualification conversions [conv.qual] (since
/// pointer conversions stop the pointer from pointing to an
/// array element).
///
/// \todo The <code>&*(i + N) == (&*i) + N</code> invariant is
/// currently impossible to check for user-defined types. We need a
/// \c contiguous_iterator_tag to let users assert it.
template <typename R> LLVM_CONSTEXPR range(
R &&r,
typename std::enable_if<
std::is_pointer<Iterator>::value &&
detail::is_contiguous_range<R>::value
// MSVC returns false for this in this context, but not if we lift it out of the
// constructor.
#ifndef _MSC_VER
&& detail::conversion_preserves_array_indexing<
decltype(&*detail::adl_begin(r)), Iterator>::value
#endif
>::type* = 0)
: begin_((detail::adl_begin(r) == detail::adl_end(r) &&
!std::is_pointer<decltype(detail::adl_begin(r))>::value)
// For non-pointers, &*begin(r) is only defined behavior
// if there's an element there. Otherwise, use nullptr
// since the user can't dereference it anyway. This _is_
// detectable.
? nullptr : &*detail::adl_begin(r)),
end_(begin_ + (detail::adl_end(r) - detail::adl_begin(r))) {}
/// @}
/// \name iterator access
/// @{
LLVM_CONSTEXPR Iterator begin() const { return begin_; }
LLVM_CONSTEXPR Iterator end() const { return end_; }
/// @}
/// \name element access
/// @{
/// \par Complexity:
/// O(1)
/// \pre \c !empty()
/// \returns a reference to the element at the front of the range.
LLVM_CONSTEXPR reference front() const { return *begin(); }
/// \par Ill-formed unless:
/// \c iterator_category is convertible to \c
/// std::bidirectional_iterator_tag.
///
/// \par Complexity:
/// O(2) (Involves copying and decrementing an iterator, so not
/// quite as cheap as \c front())
///
/// \pre \c !empty()
/// \returns a reference to the element at the front of the range.
LLVM_CONSTEXPR reference back() const {
static_assert(
std::is_convertible<iterator_category,
std::bidirectional_iterator_tag>::value,
"Can only retrieve the last element of a bidirectional range.");
using std::prev;
return *prev(end());
}
/// This method is drawn from scripting language indexing. It
/// indexes std::forward from the beginning of the range if the argument
/// is positive, or backwards from the end of the array if the
/// argument is negative.
///
/// \par Ill-formed unless:
/// \c iterator_category is convertible to \c
/// std::random_access_iterator_tag.
///
/// \par Complexity:
/// O(1)
///
/// \pre <code>abs(index) < size() || index == -size()</code>
///
/// \returns if <code>index >= 0</code>, a reference to the
/// <code>index</code>'th element in the range. Otherwise, a
/// reference to the <code>size()+index</code>'th element.
LLVM_CONSTEXPR reference operator[](difference_type index) const {
static_assert(std::is_convertible<iterator_category,
std::random_access_iterator_tag>::value,
"Can only index into a random-access range.");
// Less readable construction for constexpr support.
return index < 0 ? end()[index]
: begin()[index];
}
/// @}
/// \name size
/// @{
/// \par Complexity:
/// O(1)
/// \returns \c true if the range contains no elements.
LLVM_CONSTEXPR bool empty() const { return begin() == end(); }
/// \par Ill-formed unless:
/// \c iterator_category is convertible to
/// \c std::forward_iterator_tag.
///
/// \par Complexity:
/// O(1) if \c iterator_category is convertible to \c
/// std::random_access_iterator_tag. O(<code>size()</code>)
/// otherwise.
///
/// \returns the number of times \c pop_front() can be called before
/// \c empty() becomes true.
LLVM_CONSTEXPR difference_type size() const {
static_assert(std::is_convertible<iterator_category,
std::forward_iterator_tag>::value,
"Calling size on an input range would destroy the range.");
return dispatch_size(iterator_category());
}
/// @}
/// \name traversal from the beginning of the range
/// @{
/// Advances the beginning of the range by one element.
/// \pre \c !empty()
void pop_front() { ++begin_; }
/// Advances the beginning of the range by \c n elements.
///
/// \par Complexity:
/// O(1) if \c iterator_category is convertible to \c
/// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
///
/// \pre <code>n >= 0</code>, and there must be at least \c n
/// elements in the range.
void pop_front(difference_type n) { advance(begin_, n); }
/// Advances the beginning of the range by at most \c n elements,
/// stopping if the range becomes empty. A negative argument causes
/// no change.
///
/// \par Complexity:
/// O(1) if \c iterator_category is convertible to \c
/// std::random_access_iterator_tag, O(<code>min(n,
/// <var>#-elements-in-range</var>)</code>) otherwise.
///
/// \note Could be provided as a free function with little-to-no
/// loss in efficiency.
void pop_front_upto(difference_type n) {
advance_upto(begin_, std::max<difference_type>(0, n), end_,
iterator_category());
}
/// @}
/// \name traversal from the end of the range
/// @{
/// Moves the end of the range earlier by one element.
///
/// \par Ill-formed unless:
/// \c iterator_category is convertible to
/// \c std::bidirectional_iterator_tag.
///
/// \par Complexity:
/// O(1)
///
/// \pre \c !empty()
void pop_back() {
static_assert(std::is_convertible<iterator_category,
std::bidirectional_iterator_tag>::value,
"Can only access the end of a bidirectional range.");
--end_;
}
/// Moves the end of the range earlier by \c n elements.
///
/// \par Ill-formed unless:
/// \c iterator_category is convertible to
/// \c std::bidirectional_iterator_tag.
///
/// \par Complexity:
/// O(1) if \c iterator_category is convertible to \c
/// std::random_access_iterator_tag, O(<code>n</code>) otherwise.
///
/// \pre <code>n >= 0</code>, and there must be at least \c n
/// elements in the range.
void pop_back(difference_type n) {
static_assert(std::is_convertible<iterator_category,
std::bidirectional_iterator_tag>::value,
"Can only access the end of a bidirectional range.");
advance(end_, -n);
}
/// Moves the end of the range earlier by <code>min(n,
/// size())</code> elements. A negative argument causes no change.
///
/// \par Ill-formed unless:
/// \c iterator_category is convertible to
/// \c std::bidirectional_iterator_tag.
///
/// \par Complexity:
/// O(1) if \c iterator_category is convertible to \c
/// std::random_access_iterator_tag, O(<code>min(n,
/// <var>#-elements-in-range</var>)</code>) otherwise.
///
/// \note Could be provided as a free function with little-to-no
/// loss in efficiency.
void pop_back_upto(difference_type n) {
static_assert(std::is_convertible<iterator_category,
std::bidirectional_iterator_tag>::value,
"Can only access the end of a bidirectional range.");
advance_upto(end_, -std::max<difference_type>(0, n), begin_,
iterator_category());
}
/// @}
/// \name creating derived ranges
/// @{
/// Divides the range into two pieces at \c index, where a positive
/// \c index represents an offset from the beginning of the range
/// and a negative \c index represents an offset from the end.
/// <code>range[index]</code> is the first element in the second
/// piece. If <code>index >= size()</code>, the second piece
/// will be empty. If <code>index < -size()</code>, the first
/// piece will be empty.
///
/// \par Ill-formed unless:
/// \c iterator_category is convertible to
/// \c std::forward_iterator_tag.
///
/// \par Complexity:
/// - If \c iterator_category is convertible to \c
/// std::random_access_iterator_tag: O(1)
/// - Otherwise, if \c iterator_category is convertible to \c
/// std::bidirectional_iterator_tag, \c abs(index) iterator increments
/// or decrements
/// - Otherwise, if <code>index >= 0</code>, \c index iterator
/// increments
/// - Otherwise, <code>size() + (size() + index)</code>
/// iterator increments.
///
/// \returns a pair of adjacent ranges.
///
/// \post
/// - <code>result.first.size() == min(index, this->size())</code>
/// - <code>result.first.end() == result.second.begin()</code>
/// - <code>result.first.size() + result.second.size()</code> <code>==
/// this->size()</code>
///
/// \todo split() could take an arbitrary number of indices and
/// return an <code>N+1</code>-element \c tuple<>. This is tricky to
/// implement with negative indices in the optimal number of
/// increments or decrements for a bidirectional iterator, but it
/// should be possible. Do we want it?
std::pair<range, range> split(difference_type index) const {
static_assert(
std::is_convertible<iterator_category,
std::forward_iterator_tag>::value,
"Calling split on a non-std::forward range would return a useless "
"first result.");
if (index >= 0) {
range second = *this;
second.pop_front_upto(index);
return make_pair(range(begin(), second.begin()), second);
} else {
return dispatch_split_neg(index, iterator_category());
}
}
/// \returns A sub-range from \c start to \c stop (not including \c
/// stop, as usual). \c start and \c stop are interpreted as for
/// <code>operator[]</code>, with negative values offsetting from
/// the end of the range. Omitting the \c stop argument makes the
/// sub-range continue to the end of the original range. Positive
/// arguments saturate to the end of the range, and negative
/// arguments saturate to the beginning. If \c stop is before \c
/// start, returns an empty range beginning and ending at \c start.
///
/// \par Ill-formed unless:
/// \c iterator_category is convertible to
/// \c std::forward_iterator_tag.
///
/// \par Complexity:
/// - If \c iterator_category is convertible to \c
/// std::random_access_iterator_tag: O(1)
/// - Otherwise, if \c iterator_category is convertible to \c
/// std::bidirectional_iterator_tag, at most <code>min(abs(start),
/// size()) + min(abs(stop), size())</code> iterator
/// increments or decrements
/// - Otherwise, if <code>start >= 0 && stop >= 0</code>,
/// <code>max(start, stop)</code> iterator increments
/// - Otherwise, <code>size() + max(start', stop')</code>
/// iterator increments, where \c start' and \c stop' are the
/// offsets of the elements \c start and \c stop refer to.
///
/// \note \c slice(start) should be implemented with a different
/// overload, rather than defaulting \c stop to
/// <code>numeric_limits<difference_type>::max()</code>, because
/// using a default would force non-random-access ranges to use an
/// O(<code>size()</code>) algorithm to compute the end rather
/// than the O(1) they're capable of.
range slice(difference_type start, difference_type stop) const {
static_assert(
std::is_convertible<iterator_category,
std::forward_iterator_tag>::value,
"Calling slice on a non-std::forward range would destroy the original "
"range.");
return dispatch_slice(start, stop, iterator_category());
}
range slice(difference_type start) const {
static_assert(
std::is_convertible<iterator_category,
std::forward_iterator_tag>::value,
"Calling slice on a non-std::forward range would destroy the original "
"range.");
return split(start).second;
}
/// @}
private:
// advance_upto: should be added to <algorithm>, but I'll use it as
// a helper function here.
//
// These return the number of increments that weren't applied
// because we ran into 'limit' (or 0 if we didn't run into limit).
static difference_type advance_upto(Iterator &it, difference_type n,
Iterator limit, std::input_iterator_tag) {
if (n < 0)
return 0;
while (it != limit && n > 0) {
++it;
--n;
}
return n;
}
static difference_type advance_upto(Iterator &it, difference_type n,
Iterator limit,
std::bidirectional_iterator_tag) {
if (n < 0) {
while (it != limit && n < 0) {
--it;
++n;
}
} else {
while (it != limit && n > 0) {
++it;
--n;
}
}
return n;
}
static difference_type advance_upto(Iterator &it, difference_type n,
Iterator limit,
std::random_access_iterator_tag) {
difference_type distance = limit - it;
if (distance < 0)
assert(n <= 0);
else if (distance > 0)
assert(n >= 0);
if (abs(distance) > abs(n)) {
it += n;
return 0;
} else {
it = limit;
return n - distance;
}
}
// Dispatch functions.
difference_type dispatch_size(std::forward_iterator_tag) const {
return std::distance(begin(), end());
}
LLVM_CONSTEXPR difference_type dispatch_size(
std::random_access_iterator_tag) const {
return end() - begin();
}
std::pair<range, range> dispatch_split_neg(difference_type index,
std::forward_iterator_tag) const {
assert(index < 0);
difference_type size = this->size();
return split(std::max<difference_type>(0, size + index));
}
std::pair<range, range> dispatch_split_neg(
difference_type index, std::bidirectional_iterator_tag) const {
assert(index < 0);
range first = *this;
first.pop_back_upto(-index);
return make_pair(first, range(first.end(), end()));
}
range dispatch_slice(difference_type start, difference_type stop,
std::forward_iterator_tag) const {
if (start < 0 || stop < 0) {
difference_type size = this->size();
if (start < 0)
start = std::max<difference_type>(0, size + start);
if (stop < 0)
stop = size + stop; // Possibly negative; will be fixed in 2 lines.
}
stop = std::max<difference_type>(start, stop);
Iterator first = begin();
advance_upto(first, start, end(), iterator_category());
Iterator last = first;
advance_upto(last, stop - start, end(), iterator_category());
return range(first, last);
}
range dispatch_slice(const difference_type start, const difference_type stop,
std::bidirectional_iterator_tag) const {
Iterator first;
if (start < 0) {
first = end();
advance_upto(first, start, begin(), iterator_category());
} else {
first = begin();
advance_upto(first, start, end(), iterator_category());
}
Iterator last;
if (stop < 0) {
last = end();
advance_upto(last, stop, first, iterator_category());
} else {
if (start >= 0) {
last = first;
if (stop > start)
advance_upto(last, stop - start, end(), iterator_category());
} else {
// Complicated: 'start' walked from the end of the sequence,
// but 'stop' needs to walk from the beginning.
Iterator dummy = begin();
// Walk up to 'stop' increments from begin(), stopping when we
// get to 'first', and capturing the remaining number of
// increments.
difference_type increments_past_start =
advance_upto(dummy, stop, first, iterator_category());
if (increments_past_start == 0) {
// If this is 0, then stop was before start.
last = first;
} else {
// Otherwise, count that many spaces beyond first.
last = first;
advance_upto(last, increments_past_start, end(), iterator_category());
}
}
}
return range(first, last);
}
range dispatch_slice(difference_type start, difference_type stop,
std::random_access_iterator_tag) const {
const difference_type size = this->size();
if (start < 0)
start = size + start;
if (start < 0)
start = 0;
if (start > size)
start = size;
if (stop < 0)
stop = size + stop;
if (stop < start)
stop = start;
if (stop > size)
stop = size;
return range(begin() + start, begin() + stop);
}
};
/// \name deducing constructor wrappers
/// \relates std::range
/// \xmlonly <nonmember/> \endxmlonly
///
/// These functions do the same thing as the constructor with the same
/// signature. They just allow users to avoid writing the iterator
/// type.
/// @{
/// \todo I'd like to define a \c make_range taking a single iterator
/// argument representing the beginning of a range that ends with a
/// default-constructed \c Iterator. This would help with using
/// iterators like \c istream_iterator. However, using just \c
/// make_range() could be confusing and lead to people writing
/// incorrect ranges of more common iterators. Is there a better name?
template <typename Iterator>
LLVM_CONSTEXPR range<Iterator> make_range(Iterator begin, Iterator end) {
return range<Iterator>(begin, end);
}
/// \par Participates in overload resolution if:
/// \c begin(r) and \c end(r) return the same type.
template <typename Range> LLVM_CONSTEXPR auto make_range(
Range &&r,
typename std::enable_if<detail::is_range<Range>::value>::type* = 0)
-> range<decltype(detail::adl_begin(r))> {
return range<decltype(detail::adl_begin(r))>(r);
}
/// \par Participates in overload resolution if:
/// - \c begin(r) and \c end(r) return the same type,
/// - that type satisfies the invariant that <code>&*(i + N) ==
/// (&*i) + N</code>, and
/// - \c &*begin(r) has a pointer type.
template <typename Range> LLVM_CONSTEXPR auto make_ptr_range(
Range &&r,
typename std::enable_if<
detail::is_contiguous_range<Range>::value &&
std::is_pointer<decltype(&*detail::adl_begin(r))>::value>::type* = 0)
-> range<decltype(&*detail::adl_begin(r))> {
return range<decltype(&*detail::adl_begin(r))>(r);
}
/// @}
} // end namespace lld
#endif

View File

@@ -1,79 +0,0 @@
//===- lld/Driver/CoreInputGraph.h - Input Graph Node for Core linker -----===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Handles Options for CORE linking and provides InputElements
/// for the CORE linker
///
//===----------------------------------------------------------------------===//
#ifndef LLD_DRIVER_CORE_INPUT_GRAPH_H
#define LLD_DRIVER_CORE_INPUT_GRAPH_H
#include "lld/Core/InputGraph.h"
#include "lld/ReaderWriter/CoreLinkingContext.h"
#include <map>
namespace lld {
/// \brief Represents a CORE File
class COREFileNode : public FileNode {
public:
COREFileNode(CoreLinkingContext &ctx, StringRef path)
: FileNode(path), _ctx(ctx) {}
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::File;
}
/// \brief validates the Input Element
virtual bool validate() {
(void)_ctx;
return true;
}
/// \brief Parse the input file to lld::File.
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
ErrorOr<StringRef> filePath = getPath(ctx);
if (!filePath &&
error_code(filePath) == llvm::errc::no_such_file_or_directory)
return make_error_code(llvm::errc::no_such_file_or_directory);
// Create a memory buffer
OwningPtr<MemoryBuffer> opmb;
if (error_code ec = MemoryBuffer::getFileOrSTDIN(*filePath, opmb))
return ec;
std::unique_ptr<MemoryBuffer> mb(opmb.take());
_buffer = std::move(mb);
return _ctx.getDefaultReader().parseFile(_buffer, _files);
}
/// \brief Return the file that has to be processed by the resolver
/// to resolve atoms. This iterates over all the files thats part
/// of this node. Returns no_more_files when there are no files to be
/// processed
virtual ErrorOr<File &> getNextFile() {
if (_files.size() == _nextFileIndex)
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
/// \brief Dump the Input Element
virtual bool dump(raw_ostream &) { return true; }
private:
CoreLinkingContext &_ctx;
};
} // namespace lld
#endif

View File

@@ -1,82 +0,0 @@
//===- lld/Driver/DarwinInputGraph.h - Input Graph Node for Mach-O linker -===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Handles Options for MachO linking and provides InputElements
/// for MachO linker
///
//===----------------------------------------------------------------------===//
#ifndef LLD_DRIVER_DARWIN_INPUT_GRAPH_H
#define LLD_DRIVER_DARWIN_INPUT_GRAPH_H
#include "lld/Core/InputGraph.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include <map>
namespace lld {
/// \brief Represents a MachO File
class MachOFileNode : public FileNode {
public:
MachOFileNode(MachOLinkingContext &ctx, StringRef path, bool isWholeArchive)
: FileNode(path), _ctx(ctx), _isWholeArchive(isWholeArchive) {}
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::File;
}
/// \brief validates the Input Element
virtual bool validate() {
(void)_ctx;
return true;
}
/// \brief Parse the input file to lld::File.
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
ErrorOr<StringRef> filePath = getPath(ctx);
if (!filePath)
return error_code(filePath);
if (error_code ec = getBuffer(*filePath))
return ec;
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
if (filePath->endswith(".objtxt"))
return ctx.getYAMLReader().parseFile(_buffer, _files);
(void) (_isWholeArchive);
return error_code::success();
}
/// \brief Return the file that has to be processed by the resolver
/// to resolve atoms. This iterates over all the files thats part
/// of this node. Returns no_more_files when there are no files to be
/// processed
virtual ErrorOr<File &> getNextFile() {
if (_files.size() == _nextFileIndex)
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
/// \brief Dump the Input Element
virtual bool dump(raw_ostream &) { return true; }
private:
const MachOLinkingContext &_ctx;
bool _isWholeArchive;
};
} // namespace lld
#endif

View File

@@ -1,135 +0,0 @@
//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Interface for Drivers which convert command line arguments into
/// LinkingContext objects, then perform the link.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_DRIVER_DRIVER_H
#define LLD_DRIVER_DRIVER_H
#include "lld/Core/InputGraph.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
#include <vector>
namespace lld {
class LinkingContext;
class CoreLinkingContext;
class MachOLinkingContext;
class PECOFFLinkingContext;
class ELFLinkingContext;
/// Base class for all Drivers.
class Driver {
protected:
/// Performs link using specified options
static bool link(LinkingContext &context,
raw_ostream &diagnostics = llvm::errs());
private:
Driver() LLVM_DELETED_FUNCTION;
};
/// Driver for "universal" lld tool which can mimic any linker command line
/// parsing once it figures out which command line flavor to use.
class UniversalDriver : public Driver {
public:
/// Determine flavor and pass control to Driver for that flavor.
static bool link(int argc, const char *argv[],
raw_ostream &diagnostics = llvm::errs());
private:
UniversalDriver() LLVM_DELETED_FUNCTION;
};
/// Driver for gnu/binutil 'ld' command line options.
class GnuLdDriver : public Driver {
public:
/// Parses command line arguments same as gnu/binutils ld and performs link.
/// Returns true iff an error occurred.
static bool linkELF(int argc, const char *argv[],
raw_ostream &diagnostics = llvm::errs());
/// Uses gnu/binutils style ld command line options to fill in options struct.
/// Returns true iff there was an error.
static bool parse(int argc, const char *argv[],
std::unique_ptr<ELFLinkingContext> &context,
raw_ostream &diagnostics = llvm::errs());
private:
static llvm::Triple getDefaultTarget(const char *progName);
GnuLdDriver() LLVM_DELETED_FUNCTION;
};
/// Driver for darwin/ld64 'ld' command line options.
class DarwinLdDriver : public Driver {
public:
/// Parses command line arguments same as darwin's ld and performs link.
/// Returns true iff there was an error.
static bool linkMachO(int argc, const char *argv[],
raw_ostream &diagnostics = llvm::errs());
/// Uses darwin style ld command line options to update LinkingContext object.
/// Returns true iff there was an error.
static bool parse(int argc, const char *argv[], MachOLinkingContext &info,
raw_ostream &diagnostics = llvm::errs());
private:
DarwinLdDriver() LLVM_DELETED_FUNCTION;
};
/// Driver for Windows 'link.exe' command line options
class WinLinkDriver : public Driver {
public:
/// Parses command line arguments same as Windows link.exe and performs link.
/// Returns true iff there was an error.
static bool linkPECOFF(int argc, const char *argv[],
raw_ostream &diagnostics = llvm::errs());
/// Uses Windows style link command line options to fill in options struct.
/// Returns true iff there was an error.
static bool parse(int argc, const char *argv[], PECOFFLinkingContext &info,
raw_ostream &diagnostics = llvm::errs(),
bool isDirective = false);
private:
WinLinkDriver() LLVM_DELETED_FUNCTION;
};
/// Driver for lld unit tests
class CoreDriver : public Driver {
public:
/// Parses command line arguments same as lld-core and performs link.
/// Returns true iff there was an error.
static bool link(int argc, const char *argv[],
raw_ostream &diagnostics = llvm::errs());
/// Uses lld-core command line options to fill in options struct.
/// Returns true iff there was an error.
static bool parse(int argc, const char *argv[], CoreLinkingContext &info,
raw_ostream &diagnostics = llvm::errs());
private:
CoreDriver() LLVM_DELETED_FUNCTION;
};
} // end namespace lld
#endif

View File

@@ -1,187 +0,0 @@
//===- lld/Driver/GnuLdInputGraph.h - Input Graph Node for ELF linker------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Handles Options for the GNU style linker for ELF and provides InputElements
/// for the GNU style linker for ELF
///
//===----------------------------------------------------------------------===//
#ifndef LLD_DRIVER_GNU_LD_INPUT_GRAPH_H
#define LLD_DRIVER_GNU_LD_INPUT_GRAPH_H
#include "lld/Core/InputGraph.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "lld/ReaderWriter/FileArchive.h"
namespace lld {
/// \brief Represents a ELF File
class ELFFileNode : public FileNode {
public:
ELFFileNode(ELFLinkingContext &ctx, StringRef path,
std::vector<StringRef> searchPath, int64_t ordinal = -1,
bool isWholeArchive = false, bool asNeeded = false,
bool dashlPrefix = false)
: FileNode(path, ordinal), _elfLinkingContext(ctx),
_isWholeArchive(isWholeArchive), _asNeeded(asNeeded),
_isDashlPrefix(dashlPrefix) {
std::copy(searchPath.begin(), searchPath.end(),
std::back_inserter(_libraryPaths));
}
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::File;
}
virtual ErrorOr<StringRef> getPath(const LinkingContext &ctx) const;
/// \brief validates the Input Element
virtual bool validate() { return true; }
/// \brief create an error string for printing purposes
virtual std::string errStr(error_code);
/// \brief Dump the Input Element
virtual bool dump(raw_ostream &diagnostics) {
diagnostics << "Name : " << *getPath(_elfLinkingContext) << "\n";
diagnostics << "Type : "
<< "ELF File"
<< "\n";
diagnostics << "Ordinal : " << getOrdinal() << "\n";
diagnostics << "Attributes : "
<< "\n";
diagnostics << " - wholeArchive : "
<< ((_isWholeArchive) ? "true" : "false") << "\n";
diagnostics << " - asNeeded : " << ((_asNeeded) ? "true" : "false")
<< "\n";
diagnostics << " contextPath : " << ((_libraryPaths.size()) ? "" : "None")
<< "\n";
for (auto path : _libraryPaths)
diagnostics << " - " << path << "\n";
return true;
}
/// \brief Parse the input file to lld::File.
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
ErrorOr<StringRef> filePath = getPath(ctx);
if (!filePath)
return error_code(filePath);
if (error_code ec = getBuffer(*filePath))
return ec;
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
if (filePath->endswith(".objtxt"))
return ctx.getYAMLReader().parseFile(_buffer, _files);
// Identify File type
llvm::sys::fs::file_magic FileType =
llvm::sys::fs::identify_magic(_buffer->getBuffer());
switch (FileType) {
case llvm::sys::fs::file_magic::elf_relocatable:
case llvm::sys::fs::file_magic::elf_shared_object:
// Call the default reader to read object files and shared objects
return _elfLinkingContext.getDefaultReader().parseFile(_buffer, _files);
case llvm::sys::fs::file_magic::archive: {
// Process archive files. If Whole Archive option is set,
// parse all members of the archive.
error_code ec;
std::unique_ptr<FileArchive> fileArchive(
new FileArchive(ctx, std::move(_buffer), ec, _isWholeArchive));
if (_isWholeArchive) {
fileArchive->parseAllMembers(_files);
_archiveFile = std::move(fileArchive);
} else {
_files.push_back(std::move(fileArchive));
}
return ec;
}
default:
// Process Linker script
return _elfLinkingContext.getLinkerScriptReader().parseFile(_buffer,
_files);
}
}
/// \brief This is used by Group Nodes, when there is a need to reset the
/// the file to be processed next. When handling a group node that contains
/// Input elements, if the group node has to be reprocessed, the linker needs
/// to start processing files as part of the inputelement from beginning.
/// reset the next file index to 0 only if the node is an archive library or
/// a shared library
virtual void resetNextIndex() {
if ((!_isWholeArchive && (_files[0]->kind() == File::kindArchiveLibrary)) ||
(_files[0]->kind() == File::kindSharedLibrary))
_nextFileIndex = 0;
setResolveState(Resolver::StateNoChange);
return;
}
/// \brief Return the file that has to be processed by the resolver
/// to resolve atoms. This iterates over all the files thats part
/// of this node. Returns no_more_files when there are no files to be
/// processed
virtual ErrorOr<File &> getNextFile() {
if (_nextFileIndex == _files.size())
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
private:
llvm::BumpPtrAllocator _alloc;
const ELFLinkingContext &_elfLinkingContext;
bool _isWholeArchive;
bool _asNeeded;
bool _isDashlPrefix;
std::vector<StringRef> _libraryPaths;
std::unique_ptr<FileArchive> _archiveFile;
};
/// \brief Represents a ELF control node
class ELFGroup : public Group {
public:
ELFGroup(ELFLinkingContext &ctx, int64_t ordinal)
: Group(ordinal), _elfLinkingContext(ctx) {}
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::Control;
}
/// \brief Validate the options
virtual bool validate() {
(void)_elfLinkingContext;
return true;
}
/// \brief Dump the ELFGroup
virtual bool dump(raw_ostream &) { return true; }
/// \brief Parse the group members.
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
for (auto &ei : _elements)
if (error_code ec = ei->parse(ctx, diagnostics))
return ec;
return error_code::success();
}
private:
const ELFLinkingContext &_elfLinkingContext;
};
} // namespace lld
#endif

View File

@@ -1,101 +0,0 @@
//===- lld/Driver/WinLinkInputGraph.h - Input Graph Node for COFF linker --===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Handles Options for PECOFF linking and provides InputElements
/// for PECOFF linker
///
//===----------------------------------------------------------------------===//
#ifndef LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H
#define LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H
#include "lld/Core/InputGraph.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "lld/ReaderWriter/FileArchive.h"
#include <map>
namespace lld {
/// \brief Represents a PECOFF File
class PECOFFFileNode : public FileNode {
public:
PECOFFFileNode(PECOFFLinkingContext &ctx, StringRef path)
: FileNode(path), _ctx(ctx) {}
static inline bool classof(const InputElement *a) {
return a->kind() == InputElement::Kind::File;
}
virtual ErrorOr<StringRef> getPath(const LinkingContext &ctx) const;
/// \brief Parse the input file to lld::File.
error_code parse(const LinkingContext &ctx, raw_ostream &diagnostics) {
ErrorOr<StringRef> filePath = getPath(ctx);
if (!filePath)
return error_code(filePath);
if (error_code ec = getBuffer(*filePath))
return ec;
if (ctx.logInputFiles())
diagnostics << *filePath << "\n";
if (filePath->endswith(".objtxt"))
return ctx.getYAMLReader().parseFile(_buffer, _files);
llvm::sys::fs::file_magic FileType =
llvm::sys::fs::identify_magic(_buffer->getBuffer());
std::unique_ptr<File> f;
switch (FileType) {
case llvm::sys::fs::file_magic::archive: {
// Archive File
error_code ec;
f.reset(new FileArchive(ctx, std::move(_buffer), ec, false));
_files.push_back(std::move(f));
return ec;
}
case llvm::sys::fs::file_magic::coff_object:
default:
return _ctx.getDefaultReader().parseFile(_buffer, _files);
}
}
/// \brief validates the Input Element
virtual bool validate() { return true; }
/// \brief Dump the Input Element
virtual bool dump(raw_ostream &) { return true; }
virtual ErrorOr<File &> getNextFile() {
if (_nextFileIndex == _files.size())
return make_error_code(InputGraphError::no_more_files);
return *_files[_nextFileIndex++];
}
protected:
const PECOFFLinkingContext &_ctx;
};
/// \brief Represents a PECOFF Library File
class PECOFFLibraryNode : public PECOFFFileNode {
public:
PECOFFLibraryNode(PECOFFLinkingContext &ctx, StringRef path)
: PECOFFFileNode(ctx, path) {}
virtual ErrorOr<StringRef> getPath(const LinkingContext &ctx) const;
};
} // namespace lld
#endif

View File

@@ -1,106 +0,0 @@
//===------ Passes/LayoutPass.h - Handles Layout of atoms ------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_PASSES_LAYOUT_PASS_H
#define LLD_PASSES_LAYOUT_PASS_H
#include "lld/Core/Atom.h"
#include "lld/Core/File.h"
#include "lld/Core/Pass.h"
#include "lld/Core/range.h"
#include "lld/Core/Reference.h"
#include "llvm/ADT/DenseMap.h"
#include <map>
#include <string>
#include <vector>
namespace lld {
class DefinedAtom;
class MutableFile;
/// This linker pass does the layout of the atoms. The pass is done after the
/// order their .o files were found on the command line, then by order of the
/// atoms (address) in the .o file. But some atoms have a prefered location
/// in their section (such as pinned to the start or end of the section), so
/// the sort must take that into account too.
class LayoutPass : public Pass {
public:
// Compare and Sort Atoms by their ordinals
class CompareAtoms {
public:
explicit CompareAtoms(const LayoutPass &pass) : _layout(pass) {}
bool operator()(const DefinedAtom *left, const DefinedAtom *right) const;
private:
bool compare(const DefinedAtom *left, const DefinedAtom *right,
std::string &reason) const;
const LayoutPass &_layout;
};
LayoutPass() : Pass(), _compareAtoms(*this) {}
/// Sorts atoms in mergedFile by content type then by command line order.
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
virtual ~LayoutPass() {}
private:
// Build the followOn atoms chain as specified by the kindLayoutAfter
// reference type
void buildFollowOnTable(MutableFile::DefinedAtomRange &range);
// Build the followOn atoms chain as specified by the kindInGroup
// reference type
void buildInGroupTable(MutableFile::DefinedAtomRange &range);
// Build the PrecededBy Table as specified by the kindLayoutBefore
// reference type
void buildPrecededByTable(MutableFile::DefinedAtomRange &range);
// Build a map of Atoms to ordinals for sorting the atoms
void buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range);
typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
typedef llvm::DenseMap<const DefinedAtom *, uint64_t> AtomToOrdinalT;
// A map to be used to sort atoms. It represents the order of atoms in the
// result; if Atom X is mapped to atom Y in this map, X will be located
// immediately before Y in the output file. Y might be mapped to another
// atom, constructing a follow-on chain. An atom cannot be mapped to more
// than one atom unless all but one atom are of size zero.
AtomToAtomT _followOnNexts;
// A map to be used to sort atoms. It's a map from an atom to its root of
// follow-on chain. A root atom is mapped to itself. If an atom is not in
// _followOnNexts, the atom is not in this map, and vice versa.
AtomToAtomT _followOnRoots;
AtomToOrdinalT _ordinalOverrideMap;
CompareAtoms _compareAtoms;
// Helper methods for buildFollowOnTable().
const DefinedAtom *findAtomFollowedBy(const DefinedAtom *targetAtom);
bool checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom);
void setChainRoot(const DefinedAtom *targetAtom, const DefinedAtom *root);
#ifndef NDEBUG
// Check if the follow-on graph is a correct structure. For debugging only.
void checkFollowonChain(MutableFile::DefinedAtomRange &range);
typedef std::vector<const DefinedAtom *>::iterator DefinedAtomIter;
void checkTransitivity(DefinedAtomIter begin, DefinedAtomIter end) const;
#endif
};
} // namespace lld
#endif // LLD_PASSES_LAYOUT_PASS_H

View File

@@ -1,41 +0,0 @@
//===--Passes/RoundTripNativePass.h - Write Native file/Read it back------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_PASSES_ROUND_TRIP_NATIVE_PASS_H
#define LLD_PASSES_ROUND_TRIP_NATIVE_PASS_H
#include "lld/Core/File.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Pass.h"
#include <map>
#include <vector>
namespace lld {
class RoundTripNativePass : public Pass {
public:
RoundTripNativePass(LinkingContext &context) : Pass(), _context(context) {}
/// Writes to a native file and reads the atoms from the native file back.
/// Replaces mergedFile with the contents of the native File.
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
virtual ~RoundTripNativePass() {}
private:
LinkingContext &_context;
// Keep the parsed file alive for the rest of the link. All atoms
// that are created by the RoundTripNativePass are owned by the
// nativeFile.
std::vector<std::unique_ptr<File> > _nativeFile;
};
} // namespace lld
#endif // LLD_PASSES_ROUND_TRIP_NATIVE_PASS_H

View File

@@ -1,41 +0,0 @@
//===--Passes/RoundTripYAMLPass.h- Write YAML file/Read it back-----------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_PASSES_ROUND_TRIP_YAML_PASS_H
#define LLD_PASSES_ROUND_TRIP_YAML_PASS_H
#include "lld/Core/File.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Pass.h"
#include <map>
#include <vector>
namespace lld {
class RoundTripYAMLPass : public Pass {
public:
RoundTripYAMLPass(LinkingContext &context) : Pass(), _context(context) {}
/// Writes to a YAML file and reads the atoms from the YAML file back.
/// Replaces the mergedFile with new contents.
virtual void perform(std::unique_ptr<MutableFile> &mergedFile);
virtual ~RoundTripYAMLPass() {}
private:
LinkingContext &_context;
// Keep the parsed file alive for the rest of the link. All atoms
// that are created by the RoundTripYAMLPass are owned by the
// yamlFile.
std::vector<std::unique_ptr<File> > _yamlFile;
};
} // namespace lld
#endif // LLD_PASSES_ROUND_TRIP_YAML_PASS_H

View File

@@ -1,41 +0,0 @@
//===- include/lld/ReaderWriter/AtomLayout.h ------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ATOM_LAYOUT_H
#define LLD_READER_WRITER_ATOM_LAYOUT_H
#include <cstdint>
namespace lld {
class Atom;
/// AtomLayouts are used by a writer to manage physical positions of atoms.
/// AtomLayout has two positions; one is file offset, and the other is the
/// address when loaded into memory.
///
/// Construction of AtomLayouts is usually a multi-pass process. When an atom
/// is appended to a section, we don't know the starting address of the
/// section. Thus, we have no choice but to store the offset from the
/// beginning of the section as AtomLayout values. After all sections starting
/// address are fixed, AtomLayout is revisited to get the offsets updated by
/// adding the starting addresses of the section.
struct AtomLayout {
AtomLayout(const Atom *a, uint64_t fileOff, uint64_t virAddr)
: _atom(a), _fileOffset(fileOff), _virtualAddr(virAddr) {}
AtomLayout() : _atom(nullptr), _fileOffset(0), _virtualAddr(0) {}
const Atom *_atom;
uint64_t _fileOffset;
uint64_t _virtualAddr;
};
}
#endif

View File

@@ -1,45 +0,0 @@
//===- lld/ReaderWriter/CoreLinkingContext.h ------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_CORE_LINKER_CONTEXT_H
#define LLD_READER_WRITER_CORE_LINKER_CONTEXT_H
#include "lld/Core/LinkingContext.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "llvm/Support/ErrorHandling.h"
namespace lld {
class CoreLinkingContext : public LinkingContext {
public:
CoreLinkingContext();
virtual bool validateImpl(raw_ostream &diagnostics);
virtual void addPasses(PassManager &pm);
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
void addPassNamed(StringRef name) { _passNames.push_back(name); }
virtual Reader &getDefaultReader() const { return *_reader; }
protected:
virtual Writer &writer() const;
private:
std::unique_ptr<Reader> _reader;
std::unique_ptr<Writer> _writer;
std::vector<StringRef> _passNames;
};
} // end namespace lld
#endif

View File

@@ -1,246 +0,0 @@
//===- lld/ReaderWriter/ELFLinkingContext.h -------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
#define LLD_READER_WRITER_ELF_LINKER_CONTEXT_H
#include "lld/Core/LinkingContext.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Pass.h"
#include "lld/Core/range.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
#include <memory>
namespace lld {
class DefinedAtom;
class Reference;
namespace elf {
template <typename ELFT> class TargetHandler;
}
class TargetHandlerBase {
public:
virtual ~TargetHandlerBase() {}
};
class ELFLinkingContext : public LinkingContext {
public:
/// \brief The type of ELF executable that the linker
/// creates.
enum class OutputMagic : uint8_t {
DEFAULT, // The default mode, no specific magic set
NMAGIC, // Disallow shared libraries and dont align sections
// PageAlign Data, Mark Text Segment/Data segment RW
OMAGIC // Disallow shared libraries and dont align sections,
// Mark Text Segment/Data segment RW
};
llvm::Triple getTriple() const { return _triple; }
virtual bool is64Bits() const;
virtual bool isLittleEndian() const;
virtual uint64_t getPageSize() const { return 0x1000; }
OutputMagic getOutputMagic() const { return _outputMagic; }
uint16_t getOutputELFType() const { return _outputELFType; }
uint16_t getOutputMachine() const;
bool mergeCommonStrings() const { return _mergeCommonStrings; }
virtual uint64_t getBaseAddress() const { return _baseAddress; }
/// This controls if undefined atoms need to be created for undefines that are
/// present in a SharedLibrary. If this option is set, undefined atoms are
/// created for every undefined symbol that are present in the dynamic table
/// in the shared library
bool useShlibUndefines() const { return _useShlibUndefines; }
/// @}
/// \brief Does this relocation belong in the dynamic relocation table?
///
/// This table is evaluated at loadtime by the dynamic loader and is
/// referenced by the DT_RELA{,ENT,SZ} entries in the dynamic table.
/// Relocations that return true will be added to the dynamic relocation
/// table.
virtual bool isDynamicRelocation(const DefinedAtom &,
const Reference &) const {
return false;
}
virtual bool validateImpl(raw_ostream &diagnostics);
/// \brief Does the linker allow dynamic libraries to be linked with ?
/// This is true when the output mode of the executable is set to be
/// having NMAGIC/OMAGIC
virtual bool allowLinkWithDynamicLibraries() const {
if (_outputMagic == OutputMagic::NMAGIC ||
_outputMagic == OutputMagic::OMAGIC || _noAllowDynamicLibraries)
return false;
return true;
}
static std::unique_ptr<ELFLinkingContext> create(llvm::Triple);
/// \brief Does this relocation belong in the dynamic plt relocation table?
///
/// This table holds all of the relocations used for delayed symbol binding.
/// It will be evaluated at load time if LD_BIND_NOW is set. It is referenced
/// by the DT_{JMPREL,PLTRELSZ} entries in the dynamic table.
/// Relocations that return true will be added to the dynamic plt relocation
/// table.
virtual bool isPLTRelocation(const DefinedAtom &, const Reference &) const {
return false;
}
/// \brief The path to the dynamic interpreter
virtual StringRef getDefaultInterpreter() const {
return "/lib64/ld-linux-x86-64.so.2";
}
/// \brief The dynamic linker path set by the --dynamic-linker option
virtual StringRef getInterpreter() const {
if (_dynamicLinkerArg)
return _dynamicLinkerPath;
return getDefaultInterpreter();
}
virtual Reader &getDefaultReader() const { return *_elfReader; }
virtual Reader &getLinkerScriptReader() const { return *_linkerScriptReader; }
/// \brief Does the output have dynamic sections.
virtual bool isDynamic() const;
/// \brief Is the relocation a relative relocation
virtual bool isRelativeReloc(const Reference &r) const;
template <typename ELFT>
lld::elf::TargetHandler<ELFT> &getTargetHandler() const {
assert(_targetHandler && "Got null TargetHandler!");
return static_cast<lld::elf::TargetHandler<ELFT> &>(*_targetHandler.get());
}
virtual void addPasses(PassManager &pm);
void setTriple(llvm::Triple trip) { _triple = trip; }
void setNoInhibitExec(bool v) { _noInhibitExec = v; }
void setIsStaticExecutable(bool v) { _isStaticExecutable = v; }
void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; }
void setUseShlibUndefines(bool use) { _useShlibUndefines = use; }
void setOutputELFType(uint32_t type) { _outputELFType = type; }
/// \brief Set the dynamic linker path
void setInterpreter(StringRef dynamicLinker) {
_dynamicLinkerArg = true;
_dynamicLinkerPath = dynamicLinker;
}
/// \brief Set NMAGIC output kind when the linker specifies --nmagic
/// or -n in the command line
/// Set OMAGIC output kind when the linker specifies --omagic
/// or -N in the command line
virtual void setOutputMagic(OutputMagic magic) { _outputMagic = magic; }
/// \brief Disallow dynamic libraries during linking
virtual void setNoAllowDynamicLibraries() { _noAllowDynamicLibraries = true; }
/// Searches directories for a match on the input File
ErrorOr<StringRef>
searchLibrary(StringRef libName,
const std::vector<StringRef> &searchPath) const;
/// Get the entry symbol name
virtual StringRef entrySymbolName() const;
/// add to the list of initializer functions
void addInitFunction(StringRef name) { _initFunctions.push_back(name); }
/// add to the list of finalizer functions
void addFiniFunction(StringRef name) { _finiFunctions.push_back(name); }
/// Return the list of initializer symbols that are specified in the
/// linker command line, using the -init option.
range<const StringRef *> initFunctions() const {
return _initFunctions;
}
/// Return the list of finalizer symbols that are specified in the
/// linker command line, using the -fini option.
range<const StringRef *> finiFunctions() const { return _finiFunctions; }
void setSharedObjectName(StringRef soname) {
_soname = soname;
}
StringRef sharedObjectName() const { return _soname; }
/// \brief Set path to the system root
void setSysroot(StringRef path) {
_sysrootPath = path;
}
void addRpath(StringRef path) {
_rpathList.push_back(path);
}
range<const StringRef *> getRpathList() const {
return _rpathList;
}
void addRpathLink(StringRef path) {
_rpathLinkList.push_back(path);
}
range<const StringRef *> getRpathLinkList() const {
return _rpathLinkList;
}
private:
ELFLinkingContext() LLVM_DELETED_FUNCTION;
protected:
ELFLinkingContext(llvm::Triple, std::unique_ptr<TargetHandlerBase>);
virtual Writer &writer() const;
/// Method to create a internal file for an undefined symbol
virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
uint16_t _outputELFType; // e.g ET_EXEC
llvm::Triple _triple;
std::unique_ptr<TargetHandlerBase> _targetHandler;
uint64_t _baseAddress;
bool _isStaticExecutable;
bool _noInhibitExec;
bool _mergeCommonStrings;
bool _runLayoutPass;
bool _useShlibUndefines;
bool _dynamicLinkerArg;
bool _noAllowDynamicLibraries;
OutputMagic _outputMagic;
StringRefVector _inputSearchPaths;
std::unique_ptr<Reader> _elfReader;
std::unique_ptr<Writer> _writer;
std::unique_ptr<Reader> _linkerScriptReader;
StringRef _dynamicLinkerPath;
StringRefVector _initFunctions;
StringRefVector _finiFunctions;
StringRef _sysrootPath;
StringRef _soname;
StringRefVector _rpathList;
StringRefVector _rpathLinkList;
};
} // end namespace lld
#endif

View File

@@ -1,176 +0,0 @@
//===- lld/ReaderWriter/FileArchive.h - Archive Library File -----------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_FILE_ARCHIVE_H
#define LLD_READER_WRITER_FILE_ARCHIVE_H
#include "lld/Core/ArchiveLibraryFile.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/Archive.h"
#include "llvm/Support/MemoryBuffer.h"
#include <unordered_map>
namespace lld {
/// \brief The FileArchive class represents an Archive Library file
class FileArchive : public ArchiveLibraryFile {
public:
virtual ~FileArchive() { }
/// \brief Check if any member of the archive contains an Atom with the
/// specified name and return the File object for that member, or nullptr.
virtual const File *find(StringRef name, bool dataSymbolOnly) const {
auto member = _symbolMemberMap.find(name);
if (member == _symbolMemberMap.end())
return nullptr;
llvm::object::Archive::child_iterator ci = member->second;
if (dataSymbolOnly) {
OwningPtr<MemoryBuffer> buff;
if (ci->getMemoryBuffer(buff, true))
return nullptr;
if (isDataSymbol(buff.take(), name))
return nullptr;
}
std::vector<std::unique_ptr<File>> result;
OwningPtr<MemoryBuffer> buff;
if (ci->getMemoryBuffer(buff, true))
return nullptr;
if (_context.logInputFiles())
llvm::outs() << buff->getBufferIdentifier() << "\n";
std::unique_ptr<MemoryBuffer> mb(buff.take());
if (_context.getDefaultReader().parseFile(mb, result))
return nullptr;
assert(result.size() == 1);
// give up the pointer so that this object no longer manages it
return result[0].release();
}
/// \brief Load all members of the archive ?
virtual bool isWholeArchive() const { return _isWholeArchive; }
/// \brief parse each member
virtual error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const {
for (auto mf = _archive->begin_children(),
me = _archive->end_children(); mf != me; ++mf) {
OwningPtr<MemoryBuffer> buff;
error_code ec;
if ((ec = mf->getMemoryBuffer(buff, true)))
return ec;
if (_context.logInputFiles())
llvm::outs() << buff->getBufferIdentifier() << "\n";
std::unique_ptr<MemoryBuffer> mbc(buff.take());
if ((ec = _context.getDefaultReader().parseFile(mbc, result)))
return ec;
}
return error_code::success();
}
virtual const atom_collection<DefinedAtom> &defined() const {
return _definedAtoms;
}
virtual const atom_collection<UndefinedAtom> &undefined() const {
return _undefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
return _sharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom> &absolute() const {
return _absoluteAtoms;
}
protected:
error_code isDataSymbol(MemoryBuffer *mb, StringRef symbol) const {
std::unique_ptr<llvm::object::ObjectFile>
obj(llvm::object::ObjectFile::createObjectFile(mb));
error_code ec;
llvm::object::SymbolRef::Type symtype;
uint32_t symflags;
llvm::object::symbol_iterator ibegin = obj->begin_symbols();
llvm::object::symbol_iterator iend = obj->end_symbols();
StringRef symbolname;
for (llvm::object::symbol_iterator i = ibegin; i != iend; i.increment(ec)) {
if (ec) return ec;
// Get symbol name
if ((ec = (i->getName(symbolname)))) return ec;
if (symbolname != symbol)
continue;
// Get symbol flags
if ((ec = (i->getFlags(symflags)))) return ec;
if (symflags <= llvm::object::SymbolRef::SF_Undefined)
continue;
// Get Symbol Type
if ((ec = (i->getType(symtype)))) return ec;
if (symtype == llvm::object::SymbolRef::ST_Data) {
return error_code::success();
}
}
return llvm::object::object_error::parse_failed;
}
private:
std::unique_ptr<llvm::object::Archive> _archive;
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
bool _isWholeArchive;
public:
/// only subclasses of ArchiveLibraryFile can be instantiated
FileArchive(const LinkingContext &context,
std::unique_ptr<MemoryBuffer> mb, error_code &ec,
bool isWholeArchive)
: ArchiveLibraryFile(context, mb->getBufferIdentifier()),
_isWholeArchive(isWholeArchive) {
std::unique_ptr<llvm::object::Archive> archive_obj(
new llvm::object::Archive(mb.release(), ec));
if (ec)
return;
_archive.swap(archive_obj);
// Cache symbols.
for (auto i = _archive->begin_symbols(), e = _archive->end_symbols();
i != e; ++i) {
StringRef name;
llvm::object::Archive::child_iterator member;
if ((ec = i->getName(name)))
return;
if ((ec = i->getMember(member)))
return;
_symbolMemberMap[name] = member;
}
}
std::unordered_map<StringRef,
llvm::object::Archive::child_iterator> _symbolMemberMap;
}; // class FileArchive
} // end namespace lld
#endif // LLD_READER_WRITER_FILE_ARCHIVE_H

View File

@@ -1,228 +0,0 @@
//===- ReaderWriter/LinkerScript.h ----------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Linker script parser.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_LINKER_SCRIPT_H
#define LLD_READER_WRITER_LINKER_SCRIPT_H
#include "lld/Core/LLVM.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/system_error.h"
namespace lld {
namespace script {
class Token {
public:
enum Kind {
unknown,
eof,
identifier,
l_paren,
r_paren,
kw_entry,
kw_group,
kw_output_format,
kw_as_needed
};
Token() : _kind(unknown) {}
Token(StringRef range, Kind kind) : _range(range), _kind(kind) {}
void dump(raw_ostream &os) const;
StringRef _range;
Kind _kind;
};
class Lexer {
public:
explicit Lexer(std::unique_ptr<MemoryBuffer> mb)
: _buffer(mb->getBuffer()) {
_sourceManager.AddNewSourceBuffer(mb.release(), llvm::SMLoc());
}
void lex(Token &tok);
const llvm::SourceMgr &getSourceMgr() const { return _sourceManager; }
private:
bool canStartName(char c) const;
bool canContinueName(char c) const;
void skipWhitespace();
Token _current;
/// \brief The current buffer state.
StringRef _buffer;
// Lexer owns the input files.
llvm::SourceMgr _sourceManager;
};
class Command {
public:
enum class Kind {
Entry,
OutputFormat,
Group,
};
Kind getKind() const { return _kind; }
virtual void dump(raw_ostream &os) const = 0;
virtual ~Command() {}
protected:
explicit Command(Kind k) : _kind(k) {}
private:
Kind _kind;
};
class OutputFormat : public Command {
public:
explicit OutputFormat(StringRef format)
: Command(Kind::OutputFormat), _format(format) {}
static bool classof(const Command *c) {
return c->getKind() == Kind::OutputFormat;
}
virtual void dump(raw_ostream &os) const {
os << "OUTPUT_FORMAT(" << getFormat() << ")\n";
}
StringRef getFormat() const { return _format; }
private:
StringRef _format;
};
struct Path {
StringRef _path;
bool _asNeeded;
Path() : _asNeeded(false) {}
explicit Path(StringRef path, bool asNeeded = false)
: _path(path), _asNeeded(asNeeded) {}
};
class Group : public Command {
public:
template <class RangeT>
explicit Group(RangeT range) : Command(Kind::Group) {
using std::begin;
using std::end;
std::copy(begin(range), end(range), std::back_inserter(_paths));
}
static bool classof(const Command *c) { return c->getKind() == Kind::Group; }
virtual void dump(raw_ostream &os) const {
os << "GROUP(";
bool first = true;
for (const auto &path : getPaths()) {
if (!first)
os << " ";
else
first = false;
if (path._asNeeded)
os << "AS_NEEDED(";
os << path._path;
if (path._asNeeded)
os << ")";
}
os << ")\n";
}
const std::vector<Path> &getPaths() const { return _paths; }
private:
std::vector<Path> _paths;
};
class Entry : public Command {
public:
explicit Entry(StringRef entryName) :
Command(Kind::Entry), _entryName(entryName) { }
static bool classof(const Command *c) {
return c->getKind() == Kind::Entry;
}
virtual void dump(raw_ostream &os) const {
os << "ENTRY(" << _entryName << ")\n";
}
const StringRef getEntryName() const {
return _entryName;
}
private:
StringRef _entryName;
};
class LinkerScript {
public:
void dump(raw_ostream &os) const {
for (const auto &c : _commands)
c->dump(os);
}
std::vector<Command *> _commands;
};
class Parser {
public:
explicit Parser(Lexer &lex) : _lex(lex) {}
LinkerScript *parse();
private:
void consumeToken() { _lex.lex(_tok); }
void error(const Token &tok, Twine msg) {
_lex.getSourceMgr()
.PrintMessage(llvm::SMLoc::getFromPointer(tok._range.data()),
llvm::SourceMgr::DK_Error, msg);
}
bool expectAndConsume(Token::Kind kind, Twine msg) {
if (_tok._kind != kind) {
error(_tok, msg);
return false;
}
consumeToken();
return true;
}
OutputFormat *parseOutputFormat();
Group *parseGroup();
bool parseAsNeeded(std::vector<Path> &paths);
Entry *parseEntry();
private:
llvm::BumpPtrAllocator _alloc;
LinkerScript _script;
Lexer &_lex;
Token _tok;
};
} // end namespace script
} // end namespace lld
#endif

View File

@@ -1,627 +0,0 @@
//===- lib/ReaderWriter/MachO/MachOFormat.hpp -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains all the structs and constants needed to write a
// mach-o final linked image. The names of the structs and constants
// are the same as in the darwin native header <mach-o/loader.h> so
// they will be familiar to anyone who has used that header.
//
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Memory.h"
#ifndef LLD_READER_WRITER_MACHO_FORMAT_H
#define LLD_READER_WRITER_MACHO_FORMAT_H
namespace lld {
namespace mach_o {
enum {
MH_MAGIC = 0xfeedface,
MH_MAGIC_64 = 0xfeedfacf
};
enum {
CPU_TYPE_ARM = 0x0000000C,
CPU_TYPE_I386 = 0x00000007,
CPU_TYPE_X86_64 = 0x01000007
};
enum {
CPU_SUBTYPE_X86_ALL = 0x00000003,
CPU_SUBTYPE_X86_64_ALL = 0x00000003,
CPU_SUBTYPE_ARM_V6 = 0x00000006,
CPU_SUBTYPE_ARM_V7 = 0x00000009,
CPU_SUBTYPE_ARM_V7S = 0x0000000B
};
enum {
MH_OBJECT = 0x1,
MH_EXECUTE = 0x2,
MH_PRELOAD = 0x5,
MH_DYLIB = 0x6,
MH_DYLINKER = 0x7,
MH_BUNDLE = 0x8,
MH_DYLIB_STUB = 0x9,
MH_KEXT_BUNDLE= 0xB
};
//
// Every mach-o file starts with this header. The header size is
// 28 bytes for 32-bit architecures and 32-bytes for 64-bit architectures.
//
class mach_header {
public:
uint32_t magic;
uint32_t cputype;
uint32_t cpusubtype;
uint32_t filetype;
uint32_t ncmds;
uint32_t sizeofcmds;
uint32_t flags;
uint32_t reserved;
uint64_t size() {
return (magic == 0xfeedfacf) ? 32 : 28;
}
void copyTo(uint8_t *to, bool swap=false) {
::memcpy(to, (char*)&magic, this->size());
}
void recordLoadCommand(const class load_command *lc);
};
//
// Every mach-o file has a list of load commands after the mach_header.
// Each load command starts with a type and length, so you can iterate
// through the load commands even if you don't understand the content
// of a particular type.
//
// The model for handling endianness and 32 vs 64 bitness is that the in-memory
// object is always 64-bit and the native endianess. The endianess swapping
// and pointer sizing is done when writing (copyTo method) or when reading
// (constructor that takes a buffer).
//
// The load_command subclasses are designed so to mirror the traditional "C"
// structs, so you can get and set the same field names (e.g. seg->vmaddr = 0).
//
class load_command {
public:
const uint32_t cmd; // type of load command
const uint32_t cmdsize; // length of load command including this header
load_command(uint32_t cmdNumber, uint32_t sz, bool is64, bool align=false)
: cmd(cmdNumber), cmdsize(pointerAlign(sz, is64, align)) {
}
virtual ~load_command() {
}
virtual void copyTo(uint8_t *to, bool swap=false) = 0;
private:
// Load commands must be pointer-size aligned. Most load commands are
// a fixed size, so there is a runtime assert to check those. For variable
// length load commands, setting the align option to true will add padding
// at the end of the load command to round up its size for proper alignment.
uint32_t pointerAlign(uint32_t size, bool is64, bool align) {
if ( align ) {
if ( is64 )
return (size + 7) & (-8);
else
return (size + 3) & (-4);
}
else {
if ( is64 )
assert((size % 8) == 0);
else
assert((size % 4) == 0);
return size;
}
}
};
inline void mach_header::recordLoadCommand(const load_command *lc) {
++ncmds;
sizeofcmds += lc->cmdsize;
}
// Supported load command types
enum {
LC_SEGMENT = 0x00000001,
LC_SYMTAB = 0x00000002,
LC_UNIXTHREAD = 0x00000005,
LC_LOAD_DYLIB = 0x0000000C,
LC_LOAD_DYLINKER = 0x0000000E,
LC_SEGMENT_64 = 0x00000019,
LC_MAIN = 0x80000028,
LC_DYLD_INFO_ONLY = 0x80000022
};
// Memory protection bit used in segment_command.initprot
enum {
VM_PROT_NONE = 0x0,
VM_PROT_READ = 0x1,
VM_PROT_WRITE = 0x2,
VM_PROT_EXECUTE = 0x4,
};
// Bits for the section.flags field
enum {
// Section "type" is the low byte
SECTION_TYPE = 0x000000FF,
S_REGULAR = 0x00000000,
S_ZEROFILL = 0x00000001,
S_CSTRING_LITERALS = 0x00000002,
S_NON_LAZY_SYMBOL_POINTERS= 0x00000006,
S_LAZY_SYMBOL_POINTERS = 0x00000007,
S_SYMBOL_STUBS = 0x00000008,
// Other bits in section.flags
S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
S_ATTR_SOME_INSTRUCTIONS = 0x00000400
};
// section record for 32-bit architectures
struct section {
char sectname[16];
char segname[16];
uint32_t addr;
uint32_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
};
// section record for 64-bit architectures
struct section_64 {
char sectname[16];
char segname[16];
uint64_t addr;
uint64_t size;
uint32_t offset;
uint32_t align;
uint32_t reloff;
uint32_t nreloc;
uint32_t flags;
uint32_t reserved1;
uint32_t reserved2;
uint32_t reserved3;
};
//
// A segment load command has a fixed set of fields followed by an 'nsect'
// array of section records. The in-memory object uses a pointer to
// a dynamically allocated array of sections.
//
class segment_command : public load_command {
public:
char segname[16];
uint64_t vmaddr;
uint64_t vmsize;
uint64_t fileoff;
uint64_t filesize;
uint32_t maxprot;
uint32_t initprot;
uint32_t nsects;
uint32_t flags;
section_64 *sections;
segment_command(unsigned sectCount, bool is64)
: load_command((is64 ? LC_SEGMENT_64 : LC_SEGMENT),
(is64 ? (72 + sectCount*80) : (56 + sectCount*68)),
is64),
vmaddr(0), vmsize(0), fileoff(0), filesize(0),
maxprot(0), initprot(0), nsects(sectCount), flags(0) {
sections = new section_64[sectCount];
this->nsects = sectCount;
}
~segment_command() {
delete sections;
}
void copyTo(uint8_t *to, bool swap) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
if( is64() ) {
// in-memory matches on-disk, so copy segment fields followed by sections
::memcpy(to, (uint8_t*)&cmd, 72);
if ( nsects != 0 )
::memcpy(&to[72], sections, sizeof(section_64)*nsects);
}
else {
// on-disk is 32-bit struct, so copy each field
::memcpy(to, (uint8_t*)&cmd, 24);
copy32(to, 24, vmaddr);
copy32(to, 28, vmsize);
copy32(to, 32, fileoff);
copy32(to, 36, filesize);
copy32(to, 40, maxprot);
copy32(to, 44, initprot);
copy32(to, 48, nsects);
copy32(to, 52, flags);
for(uint32_t i=0; i < nsects; ++i) {
unsigned off = 56+i*68;
::memcpy(&to[off], sections[i].sectname, 32);
copy32(to, off+32, sections[i].addr);
copy32(to, off+36, sections[i].size);
copy32(to, off+40, sections[i].offset);
copy32(to, off+44, sections[i].align);
copy32(to, off+48, sections[i].reloff);
copy32(to, off+52, sections[i].nreloc);
copy32(to, off+56, sections[i].flags);
copy32(to, off+60, sections[i].reserved1);
copy32(to, off+64, sections[i].reserved2);
}
}
}
}
private:
void copy32(uint8_t *to, unsigned offset, uint64_t value) {
uint32_t value32 = value; // FIXME: range check
::memcpy(&to[offset], &value32, sizeof(uint32_t));
}
bool is64() {
return (cmd == LC_SEGMENT_64);
}
};
//
// The dylinker_command contains the path to the dynamic loader to use
// with the program (e.g. "/usr/lib/dyld"). So, it is variable length.
// But load commands must be pointer size aligned.
//
//
class dylinker_command : public load_command {
public:
uint32_t name_offset;
private:
StringRef _name;
public:
dylinker_command(StringRef path, bool is64)
: load_command(LC_LOAD_DYLINKER,12 + path.size(), is64, true),
name_offset(12), _name(path) {
}
virtual void copyTo(uint8_t *to, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
// in-memory matches on-disk, so copy first fields followed by path
::memcpy(to, (uint8_t*)&cmd, 12);
::memcpy(&to[12], _name.data(), _name.size());
::memset(&to[12+_name.size()], 0, cmdsize-(12+_name.size()));
}
}
};
//
// The symtab_command just holds the offset to the array of nlist structs
// and the offsets to the string pool for all symbol names.
//
class symtab_command : public load_command {
public:
uint32_t symoff;
uint32_t nsyms;
uint32_t stroff;
uint32_t strsize;
symtab_command(bool is64)
: load_command(LC_SYMTAB, 24, is64),
symoff(0), nsyms(0), stroff(0), strsize(0) {
}
virtual void copyTo(uint8_t *to, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
// in-memory matches on-disk, so copy fields
::memcpy(to, (uint8_t*)&cmd, 24);
}
}
};
//
// The entry_point_command load command holds the offset to the function
// _main in a dynamic executable.
//
class entry_point_command : public load_command {
public:
uint64_t entryoff;
uint64_t stacksize;
entry_point_command(bool is64)
: load_command(LC_MAIN, 24, is64), entryoff(0), stacksize(0) {
}
virtual void copyTo(uint8_t *to, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
// in-memory matches on-disk, so copy fields
::memcpy(to, (uint8_t*)&cmd, 24);
}
}
};
//
// The thread_command load command holds the set of initial register values
// for a dynamic executable. In reality, only the PC and SP are used.
//
class thread_command : public load_command {
public:
uint32_t fields_flavor;
uint32_t fields_count;
private:
uint32_t _cpuType;
uint8_t *_registerArray;
public:
thread_command(uint32_t cpuType, bool is64)
: load_command(LC_UNIXTHREAD, 16+registersBufferSize(cpuType), is64),
fields_count(registersBufferSize(cpuType)/4), _cpuType(cpuType) {
switch ( cpuType ) {
case CPU_TYPE_I386:
fields_flavor = 1; // i386_THREAD_STATE
break;
case CPU_TYPE_X86_64:
fields_flavor = 4; // x86_THREAD_STATE64;
break;
case CPU_TYPE_ARM:
fields_flavor = 1; // ARM_THREAD_STATE
break;
default:
assert(0 && "unsupported cpu type");
}
_registerArray = reinterpret_cast<uint8_t*>(
::calloc(registersBufferSize(cpuType), 1));
assert(_registerArray);
}
virtual void copyTo(uint8_t *to, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
// in-memory matches on-disk, so copy fixed fields
::memcpy(to, (uint8_t*)&cmd, 16);
// that register array
::memcpy(&to[16], _registerArray, registersBufferSize(_cpuType));
}
}
void setPC(uint64_t pc) {
uint32_t *regs32 = reinterpret_cast<uint32_t*>(_registerArray);
uint64_t *regs64 = reinterpret_cast<uint64_t*>(_registerArray);
switch ( _cpuType ) {
case CPU_TYPE_I386:
regs32[10] = pc;
break;
case CPU_TYPE_X86_64:
regs64[16] = pc;
break;
case CPU_TYPE_ARM:
regs32[15] = pc;
break;
default:
assert(0 && "unsupported cpu type");
}
}
virtual ~thread_command() {
::free(_registerArray);
}
private:
uint32_t registersBufferSize(uint32_t cpuType) {
switch ( cpuType ) {
case CPU_TYPE_I386:
return 64; // i386_THREAD_STATE_COUNT * 4
case CPU_TYPE_X86_64:
return 168; // x86_THREAD_STATE64_COUNT * 4
case CPU_TYPE_ARM:
return 68; // ARM_THREAD_STATE_COUNT * 4
}
assert(0 && "unsupported cpu type");
return 0;
}
};
//
// The dylib_command load command holds the name/path of a dynamic shared
// library which this mach-o image depends on.
//
struct dylib_command : public load_command {
uint32_t name_offset;
uint32_t timestamp;
uint32_t current_version;
uint32_t compatibility_version;
private:
StringRef _loadPath;
public:
dylib_command(StringRef path, bool is64)
: load_command(LC_LOAD_DYLIB, 24 + path.size(), is64, true),
name_offset(24), timestamp(0),
current_version(0x10000), compatibility_version(0x10000),
_loadPath(path) {
}
virtual void copyTo(uint8_t *to, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
// in-memory matches on-disk, so copy first fields followed by path
::memcpy(to, (uint8_t*)&cmd, 24);
::memcpy(&to[24], _loadPath.data(), _loadPath.size());
::memset(&to[24+_loadPath.size()], 0, cmdsize-(24+_loadPath.size()));
}
}
};
//
// The dyld_info_command load command holds the offsets to various tables
// of information needed by dyld to prepare the image for execution.
//
struct dyld_info_command : public load_command {
uint32_t rebase_off;
uint32_t rebase_size;
uint32_t bind_off;
uint32_t bind_size;
uint32_t weak_bind_off;
uint32_t weak_bind_size;
uint32_t lazy_bind_off;
uint32_t lazy_bind_size;
uint32_t export_off;
uint32_t export_size;
dyld_info_command(bool is64)
: load_command(LC_DYLD_INFO_ONLY, 48, is64),
rebase_off(0), rebase_size(0),
bind_off(0), bind_size(0), weak_bind_off(0), weak_bind_size(0),
lazy_bind_off(0), lazy_bind_size(0), export_off(0), export_size(0) {
}
virtual void copyTo(uint8_t *to, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
// in-memory matches on-disk, so copy fields
::memcpy(to, (uint8_t*)&cmd, 48);
}
}
};
enum {
BIND_TYPE_POINTER = 1,
BIND_TYPE_TEXT_ABSOLUTE32 = 2,
BIND_TYPE_TEXT_PCREL32 = 3
};
enum {
BIND_SPECIAL_DYLIB_SELF = 0,
BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE = -1,
BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2
};
enum {
BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1,
BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION = 0x8
};
enum {
BIND_OPCODE_MASK = 0xF0,
BIND_IMMEDIATE_MASK = 0x0F,
BIND_OPCODE_DONE = 0x00,
BIND_OPCODE_SET_DYLIB_ORDINAL_IMM = 0x10,
BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB = 0x20,
BIND_OPCODE_SET_DYLIB_SPECIAL_IMM = 0x30,
BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM = 0x40,
BIND_OPCODE_SET_TYPE_IMM = 0x50,
BIND_OPCODE_SET_ADDEND_SLEB = 0x60,
BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB = 0x70,
BIND_OPCODE_ADD_ADDR_ULEB = 0x80,
BIND_OPCODE_DO_BIND = 0x90,
BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB = 0xA0,
BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED = 0xB0,
BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB = 0xC0
};
enum {
N_UNDF = 0x00,
N_EXT = 0x01,
N_PEXT = 0x10,
N_SECT = 0x0e
};
class nlist {
public:
uint32_t n_strx;
uint8_t n_type;
uint8_t n_sect;
uint16_t n_desc;
uint64_t n_value;
static unsigned size(bool is64) {
return (is64 ? 16 : 12);
}
void copyTo(uint8_t *to, bool is64, bool swap=false) {
if ( swap ) {
assert(0 && "non-native endianness not supported yet");
}
else {
if ( is64 ) {
// in-memory matches on-disk, so just copy whole struct
::memcpy(to, (uint8_t*)&n_strx, 16);
}
else {
// on-disk uses 32-bit n_value, so special case n_value
::memcpy(to, (uint8_t*)&n_strx, 8);
uint32_t value32 = n_value; // FIXME: range check
::memcpy(&to[8], &value32, sizeof(uint32_t));
}
}
}
};
} // namespace mach_o
} // namespace lld
#endif // LLD_READER_WRITER_MACHO_FORMAT_H

View File

@@ -1,174 +0,0 @@
//===- lld/ReaderWriter/MachOLinkingContext.h -----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
#define LLD_READER_WRITER_MACHO_LINKING_CONTEXT_H
#include "lld/Core/LinkingContext.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MachO.h"
using llvm::MachO::HeaderFileType;
namespace lld {
namespace mach_o {
class KindHandler; // defined in lib. this header is in include.
}
class MachOLinkingContext : public LinkingContext {
public:
MachOLinkingContext();
~MachOLinkingContext();
virtual void addPasses(PassManager &pm);
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
virtual bool validateImpl(raw_ostream &diagnostics);
uint32_t getCPUType() const;
uint32_t getCPUSubType() const;
bool addEntryPointLoadCommand() const;
bool addUnixThreadLoadCommand() const;
bool outputTypeHasEntry() const;
bool is64Bit() const;
virtual uint64_t pageZeroSize() const { return _pageZeroSize; }
virtual uint64_t pageSize() const { return _pageSize; }
mach_o::KindHandler &kindHandler() const;
HeaderFileType outputFileType() const { return _outputFileType; }
enum Arch {
arch_unknown,
arch_ppc,
arch_x86,
arch_x86_64,
arch_armv6,
arch_armv7,
arch_armv7s,
};
enum class OS {
unknown, macOSX, iOS, iOS_simulator
};
Arch arch() const { return _arch; }
OS os() const { return _os; }
void setOutputFileType(HeaderFileType type) { _outputFileType = type; }
void setArch(Arch arch) { _arch = arch; }
bool setOS(OS os, StringRef minOSVersion);
bool minOS(StringRef mac, StringRef iOS) const;
void setDoNothing(bool value) { _doNothing = value; }
bool doNothing() const { return _doNothing; }
virtual Reader &getDefaultReader() const { return *_machoReader; }
/// \brief The dylib's binary compatibility version, in the raw uint32 format.
///
/// When building a dynamic library, this is the compatibility version that
/// gets embedded into the result. Other Mach-O binaries that link against
/// this library will store the compatibility version in its load command. At
/// runtime, the loader will verify that the binary is compatible with the
/// installed dynamic library.
uint32_t compatibilityVersion() const { return _compatibilityVersion; }
/// \brief The dylib's current version, in the the raw uint32 format.
///
/// When building a dynamic library, this is the current version that gets
/// embedded into the result. Other Mach-O binaries that link against
/// this library will store the compatibility version in its load command.
uint32_t currentVersion() const { return _currentVersion; }
/// \brief The dylib's install name.
///
/// Binaries that link against the dylib will embed this path into the dylib
/// load command. When loading the binaries at runtime, this is the location
/// on disk that the loader will look for the dylib.
StringRef installName() const { return _installName; }
/// \brief Whether or not the dylib has side effects during initialization.
///
/// Dylibs marked as being dead strippable provide the guarantee that loading
/// the dylib has no side effects, allowing the linker to strip out the dylib
/// when linking a binary that does not use any of its symbols.
bool deadStrippableDylib() const { return _deadStrippableDylib; }
/// \brief The path to the executable that will load the bundle at runtime.
///
/// When building a Mach-O bundle, this executable will be examined if there
/// are undefined symbols after the main link phase. It is expected that this
/// binary will be loading the bundle at runtime and will provide the symbols
/// at that point.
StringRef bundleLoader() const { return _bundleLoader; }
void setCompatibilityVersion(uint32_t vers) { _compatibilityVersion = vers; }
void setCurrentVersion(uint32_t vers) { _currentVersion = vers; }
void setInstallName(StringRef name) { _installName = name; }
void setDeadStrippableDylib(bool deadStrippable) {
_deadStrippableDylib = deadStrippable;
}
void setBundleLoader(StringRef loader) { _bundleLoader = loader; }
StringRef dyldPath() const { return "/usr/lib/dyld"; }
static Arch archFromCpuType(uint32_t cputype, uint32_t cpusubtype);
static Arch archFromName(StringRef archName);
static uint32_t cpuTypeFromArch(Arch arch);
static uint32_t cpuSubtypeFromArch(Arch arch);
static bool is64Bit(Arch arch);
static bool isHostEndian(Arch arch);
static bool isBigEndian(Arch arch);
/// Construct 32-bit value from string "X.Y.Z" where
/// bits are xxxx.yy.zz. Largest number is 65535.255.255
static bool parsePackedVersion(StringRef str, uint32_t &result);
private:
virtual Writer &writer() const;
struct ArchInfo {
StringRef archName;
MachOLinkingContext::Arch arch;
bool littleEndian;
uint32_t cputype;
uint32_t cpusubtype;
};
static ArchInfo _s_archInfos[];
static const uint64_t unspecifiedPageZeroSize = UINT64_MAX;
HeaderFileType _outputFileType; // e.g MH_EXECUTE
bool _outputFileTypeStatic; // Disambiguate static vs dynamic prog
bool _doNothing; // for -help and -v which just print info
Arch _arch;
OS _os;
uint32_t _osMinVersion;
uint64_t _pageZeroSize;
uint64_t _pageSize;
uint32_t _compatibilityVersion;
uint32_t _currentVersion;
StringRef _installName;
bool _deadStrippableDylib;
StringRef _bundleLoader;
mutable std::unique_ptr<mach_o::KindHandler> _kindHandler;
mutable std::unique_ptr<Reader> _machoReader;
mutable std::unique_ptr<Writer> _writer;
};
} // end namespace lld
#endif

View File

@@ -1,338 +0,0 @@
//===- lld/ReaderWriter/PECOFFLinkingContext.h ----------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H
#define LLD_READER_WRITER_PECOFF_LINKING_CONTEXT_H
#include <map>
#include <set>
#include <vector>
#include "lld/Core/LinkingContext.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/COFF.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileUtilities.h"
using llvm::COFF::MachineTypes;
using llvm::COFF::WindowsSubsystem;
static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'};
namespace lld {
class PECOFFLinkingContext : public LinkingContext {
public:
PECOFFLinkingContext()
: _baseAddress(0x400000), _stackReserve(1024 * 1024), _stackCommit(4096),
_heapReserve(1024 * 1024), _heapCommit(4096), _noDefaultLibAll(false),
_sectionDefaultAlignment(4096),
_subsystem(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN),
_machineType(llvm::COFF::IMAGE_FILE_MACHINE_I386), _imageVersion(0, 0),
_minOSVersion(6, 0), _nxCompat(true), _largeAddressAware(false),
_allowBind(true), _allowIsolation(true), _swapRunFromCD(false),
_swapRunFromNet(false), _baseRelocationEnabled(true),
_terminalServerAware(true), _dynamicBaseEnabled(true),
_createManifest(true), _embedManifest(false), _manifestId(1),
_manifestLevel("'asInvoker'"), _manifestUiAccess("'false'"),
_imageType(ImageType::IMAGE_EXE),
_dosStub(llvm::makeArrayRef(DEFAULT_DOS_STUB)) {
setDeadStripping(true);
}
struct Version {
Version(int v1, int v2) : majorVersion(v1), minorVersion(v2) {}
int majorVersion;
int minorVersion;
};
/// \brief Casting support
static inline bool classof(const LinkingContext *info) { return true; }
enum ImageType {
IMAGE_EXE,
IMAGE_DLL
};
virtual Reader &getDefaultReader() const { return *_reader; }
virtual Writer &writer() const;
virtual bool validateImpl(raw_ostream &diagnostics);
virtual void addPasses(PassManager &pm);
virtual bool
createImplicitFiles(std::vector<std::unique_ptr<File> > &result) const;
void appendInputSearchPath(StringRef dirPath) {
_inputSearchPaths.push_back(dirPath);
}
const std::vector<StringRef> getInputSearchPaths() {
return _inputSearchPaths;
}
void registerTemporaryFile(StringRef path) {
std::unique_ptr<llvm::FileRemover> fileRemover(
new llvm::FileRemover(Twine(allocateString(path))));
_tempFiles.push_back(std::move(fileRemover));
}
StringRef searchLibraryFile(StringRef path) const;
/// Returns the decorated name of the given symbol name. On 32-bit x86, it
/// adds "_" at the beginning of the string. On other architectures, the
/// return value is the same as the argument.
StringRef decorateSymbol(StringRef name) const {
if (_machineType != llvm::COFF::IMAGE_FILE_MACHINE_I386)
return name;
std::string str = "_";
str.append(name);
return allocateString(str);
}
void setEntrySymbolName(StringRef name) {
if (!name.empty())
LinkingContext::setEntrySymbolName(decorateSymbol(name));
}
void setBaseAddress(uint64_t addr) { _baseAddress = addr; }
uint64_t getBaseAddress() const { return _baseAddress; }
void setStackReserve(uint64_t size) { _stackReserve = size; }
void setStackCommit(uint64_t size) { _stackCommit = size; }
uint64_t getStackReserve() const { return _stackReserve; }
uint64_t getStackCommit() const { return _stackCommit; }
void setHeapReserve(uint64_t size) { _heapReserve = size; }
void setHeapCommit(uint64_t size) { _heapCommit = size; }
uint64_t getHeapReserve() const { return _heapReserve; }
uint64_t getHeapCommit() const { return _heapCommit; }
void setSectionDefaultAlignment(uint32_t val) {
_sectionDefaultAlignment = val;
}
uint32_t getSectionDefaultAlignment() const {
return _sectionDefaultAlignment;
}
void setSubsystem(WindowsSubsystem ss) { _subsystem = ss; }
WindowsSubsystem getSubsystem() const { return _subsystem; }
void setMachineType(MachineTypes type) { _machineType = type; }
MachineTypes getMachineType() const { return _machineType; }
void setImageVersion(const Version &version) { _imageVersion = version; }
Version getImageVersion() const { return _imageVersion; }
void setMinOSVersion(const Version &version) { _minOSVersion = version; }
Version getMinOSVersion() const { return _minOSVersion; }
void setNxCompat(bool nxCompat) { _nxCompat = nxCompat; }
bool isNxCompat() const { return _nxCompat; }
void setLargeAddressAware(bool val) { _largeAddressAware = val; }
bool getLargeAddressAware() const { return _largeAddressAware; }
void setAllowBind(bool val) { _allowBind = val; }
bool getAllowBind() const { return _allowBind; }
void setAllowIsolation(bool val) { _allowIsolation = val; }
bool getAllowIsolation() const { return _allowIsolation; }
void setSwapRunFromCD(bool val) { _swapRunFromCD = val; }
bool getSwapRunFromCD() const { return _swapRunFromCD; }
void setSwapRunFromNet(bool val) { _swapRunFromNet = val; }
bool getSwapRunFromNet() const { return _swapRunFromNet; }
void setBaseRelocationEnabled(bool val) { _baseRelocationEnabled = val; }
bool getBaseRelocationEnabled() const { return _baseRelocationEnabled; }
void setTerminalServerAware(bool val) { _terminalServerAware = val; }
bool isTerminalServerAware() const { return _terminalServerAware; }
void setDynamicBaseEnabled(bool val) { _dynamicBaseEnabled = val; }
bool getDynamicBaseEnabled() const { return _dynamicBaseEnabled; }
void setCreateManifest(bool val) { _createManifest = val; }
bool getCreateManifest() const { return _createManifest; }
void setManifestOutputPath(std::string val) { _manifestOutputPath = val; }
const std::string &getManifestOutputPath() const {
return _manifestOutputPath;
}
void setEmbedManifest(bool val) { _embedManifest = val; }
bool getEmbedManifest() const { return _embedManifest; }
void setManifestId(int val) { _manifestId = val; }
int getManifestId() const { return _manifestId; }
void setManifestLevel(std::string val) { _manifestLevel = std::move(val); }
const std::string &getManifestLevel() const { return _manifestLevel; }
void setManifestUiAccess(std::string val) { _manifestUiAccess = val; }
const std::string &getManifestUiAccess() const { return _manifestUiAccess; }
void setManifestDependency(std::string val) { _manifestDependency = val; }
const std::string &getManifestDependency() const {
return _manifestDependency;
}
void setImageType(ImageType type) { _imageType = type; }
ImageType getImageType() const { return _imageType; }
StringRef getFinalSectionName(StringRef sectionName) const;
bool addSectionRenaming(raw_ostream &diagnostics,
StringRef from, StringRef to);
void addNoDefaultLib(StringRef path) { _noDefaultLibs.insert(path); }
bool hasNoDefaultLib(StringRef path) const {
return _noDefaultLibs.count(path) == 1;
}
void addDefaultLib(StringRef path) { _defaultLibs.insert(path); }
bool hasDefaultLib(StringRef path) const {
return _defaultLibs.count(path) == 1;
}
void setNoDefaultLibAll(bool val) { _noDefaultLibAll = val; }
bool getNoDefaultLibAll() const { return _noDefaultLibAll; }
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
void setSectionAttributes(StringRef sectionName, uint32_t flags) {
_sectionAttributes[sectionName] = flags;
}
llvm::Optional<uint32_t> getSectionAttributes(StringRef sectionName) const {
auto it = _sectionAttributes.find(sectionName);
if (it == _sectionAttributes.end())
return llvm::None;
return it->second;
}
void setSectionAttributeMask(StringRef sectionName, uint32_t flags) {
_sectionAttributeMask[sectionName] = flags;
}
uint32_t getSectionAttributeMask(StringRef sectionName) const {
auto it = _sectionAttributeMask.find(sectionName);
return it == _sectionAttributeMask.end() ? 0 : it->second;
}
void setDosStub(ArrayRef<uint8_t> data) { _dosStub = data; }
ArrayRef<uint8_t> getDosStub() const { return _dosStub; }
StringRef allocateString(StringRef ref) const {
char *x = _allocator.Allocate<char>(ref.size() + 1);
memcpy(x, ref.data(), ref.size());
x[ref.size()] = '\0';
return x;
}
ArrayRef<uint8_t> allocate(ArrayRef<uint8_t> array) const {
size_t size = array.size();
uint8_t *p = _allocator.Allocate<uint8_t>(size);
memcpy(p, array.data(), size);
return ArrayRef<uint8_t>(p, p + array.size());
}
virtual bool hasInputGraph() {
if (_inputGraph)
return true;
return false;
}
protected:
/// Method to create a internal file for the entry symbol
virtual std::unique_ptr<File> createEntrySymbolFile() const;
/// Method to create a internal file for an undefined symbol
virtual std::unique_ptr<File> createUndefinedSymbolFile() const;
private:
// The start address for the program. The default value for the executable is
// 0x400000, but can be altered using -base command line option.
uint64_t _baseAddress;
uint64_t _stackReserve;
uint64_t _stackCommit;
uint64_t _heapReserve;
uint64_t _heapCommit;
bool _noDefaultLibAll;
uint32_t _sectionDefaultAlignment;
WindowsSubsystem _subsystem;
MachineTypes _machineType;
Version _imageVersion;
Version _minOSVersion;
bool _nxCompat;
bool _largeAddressAware;
bool _allowBind;
bool _allowIsolation;
bool _swapRunFromCD;
bool _swapRunFromNet;
bool _baseRelocationEnabled;
bool _terminalServerAware;
bool _dynamicBaseEnabled;
bool _createManifest;
std::string _manifestOutputPath;
bool _embedManifest;
int _manifestId;
std::string _manifestLevel;
std::string _manifestUiAccess;
std::string _manifestDependency;
ImageType _imageType;
// The set to store /nodefaultlib arguments.
std::set<std::string> _noDefaultLibs;
// A set containing all the library files specified by /defaultlib. This is to
// keep track what files are already added to the input graph, in order to
// prevent adding the same file more than once to the input graph.
std::set<std::string> _defaultLibs;
std::vector<StringRef> _inputSearchPaths;
std::unique_ptr<Reader> _reader;
std::unique_ptr<Writer> _writer;
// A map for section renaming. For example, if there is an entry in the map
// whose value is .rdata -> .text, the section contens of .rdata will be
// merged to .text in the resulting executable.
std::map<std::string, std::string> _renamedSections;
// Section attributes specified by /section option. The uint32_t value will be
// copied to the Characteristics field of the section header.
std::map<std::string, uint32_t> _sectionAttributes;
// Section attributes specified by /section option in conjunction with the
// negative flag "!". The uint32_t value is a mask of section attributes that
// should be disabled.
std::map<std::string, uint32_t> _sectionAttributeMask;
// List of files that will be removed on destruction.
std::vector<std::unique_ptr<llvm::FileRemover> > _tempFiles;
// DOS Stub. DOS stub is data located at the beginning of PE/COFF file.
// Windows loader do not really care about DOS stub contents, but it's usually
// a small DOS program that prints out a message "This program requires
// Microsoft Windows." This feature was somewhat useful before Windows 95.
ArrayRef<uint8_t> _dosStub;
};
} // end namespace lld
#endif

View File

@@ -1,56 +0,0 @@
//===- lld/ReaderWriter/Reader.h - Abstract File Format Reading Interface -===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_READER_H
#define LLD_READER_WRITER_READER_H
#include "lld/Core/LLVM.h"
#include <functional>
#include <memory>
#include <vector>
namespace lld {
class ELFLinkingContext;
class File;
class LinkingContext;
class PECOFFLinkingContext;
/// \brief An abstract class for reading object files, library files, and
/// executable files.
///
/// Each file format (e.g. ELF, mach-o, PECOFF, native, etc) have a concrete
/// subclass of Reader.
class Reader {
public:
virtual ~Reader();
/// \brief Parse a supplied buffer (already filled with the contents of a
/// file) and create a File object.
///
/// On success, the resulting File object takes ownership of the MemoryBuffer.
virtual error_code
parseFile(std::unique_ptr<MemoryBuffer> &mb,
std::vector<std::unique_ptr<File> > &result) const = 0;
protected:
// only concrete subclasses can be instantiated
Reader(const LinkingContext &context) : _context(context) {}
const LinkingContext &_context;
};
std::unique_ptr<Reader> createReaderELF(const ELFLinkingContext &);
std::unique_ptr<Reader> createReaderMachO(const LinkingContext &);
std::unique_ptr<Reader> createReaderNative(const LinkingContext &);
std::unique_ptr<Reader> createReaderPECOFF(PECOFFLinkingContext &);
std::unique_ptr<Reader> createReaderYAML(const LinkingContext &);
} // end namespace lld
#endif

View File

@@ -1,34 +0,0 @@
//===- lld/ReaderWriter/ReaderLinkerScript.h ------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_READER_LINKER_SCRIPT_H
#define LLD_READER_WRITER_READER_LINKER_SCRIPT_H
#include "lld/Core/LLVM.h"
#include "lld/ReaderWriter/Reader.h"
namespace lld {
class File;
class LinkingContext;
/// \brief ReaderLinkerScript is a class for reading linker scripts
class ReaderLinkerScript : public Reader {
public:
explicit ReaderLinkerScript(const LinkingContext &context)
: Reader(context) {}
/// \brief Returns a vector of Files that are contained in the archive file
/// pointed to by the Memorybuffer
error_code parseFile(std::unique_ptr<MemoryBuffer> &mb,
std::vector<std::unique_ptr<File> > &result) const;
};
} // end namespace lld
#endif

View File

@@ -1,53 +0,0 @@
//===- lld/ReaderWriter/RelocationHelperFunctions.h------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H
#define LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H
namespace lld {
/// \brief Return the bits that are described by the mask
template < typename T >
T gatherBits(T val, T mask)
{
T result = 0;
size_t off = 0;
for (size_t bit = 0; bit != sizeof (T) * 8; ++bit) {
const bool valBit = (val >> bit) & 1;
const bool maskBit = (mask >> bit) & 1;
if (maskBit) {
result |= static_cast <T> (valBit) << off;
++off;
}
}
return result;
}
/// \brief Set the bits as described by the mask
template <typename T>
T scatterBits(T val, T mask)
{
T result = 0;
size_t off = 0;
for (size_t bit = 0; bit != sizeof (T) * 8; ++bit) {
const bool valBit = (val >> off) & 1;
const bool maskBit = (mask >> bit) & 1;
if (maskBit) {
result |= static_cast<T>(valBit) << bit;
++off;
}
}
return result;
}
} // namespace lld
#endif // LLD_READER_WRITER_RELOCATION_HELPER_FUNCTIONS_H

View File

@@ -1,204 +0,0 @@
//===- lld/Core/Simple.h - Simple implementations of Atom and File --------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Provide simple implementations for Atoms and File.
///
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_SIMPLE_H
#define LLD_READER_WRITER_SIMPLE_H
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/Reference.h"
#include "lld/Core/UndefinedAtom.h"
namespace lld {
class SimpleFile : public MutableFile {
public:
SimpleFile(const LinkingContext &context, StringRef path)
: MutableFile(context, path) {}
virtual void addAtom(const Atom &atom) {
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(&atom)) {
_definedAtoms._atoms.push_back(defAtom);
} else if (
const UndefinedAtom *undefAtom = dyn_cast<UndefinedAtom>(&atom)) {
_undefinedAtoms._atoms.push_back(undefAtom);
} else if (
const SharedLibraryAtom *slAtom = dyn_cast<SharedLibraryAtom>(&atom)) {
_sharedLibraryAtoms._atoms.push_back(slAtom);
} else if (const AbsoluteAtom *abAtom = dyn_cast<AbsoluteAtom>(&atom)) {
_absoluteAtoms._atoms.push_back(abAtom);
} else {
llvm_unreachable("atom has unknown definition kind");
}
}
virtual const atom_collection<DefinedAtom> &defined() const {
return _definedAtoms;
}
virtual const atom_collection<UndefinedAtom> &undefined() const {
return _undefinedAtoms;
}
virtual const atom_collection<SharedLibraryAtom> &sharedLibrary() const {
return _sharedLibraryAtoms;
}
virtual const atom_collection<AbsoluteAtom> &absolute() const {
return _absoluteAtoms;
}
virtual DefinedAtomRange definedAtoms() {
return make_range(_definedAtoms._atoms);
}
protected:
atom_collection_vector<DefinedAtom> _definedAtoms;
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
atom_collection_vector<SharedLibraryAtom> _sharedLibraryAtoms;
atom_collection_vector<AbsoluteAtom> _absoluteAtoms;
};
class FileToMutable : public SimpleFile {
public:
FileToMutable(const LinkingContext &context, File &file)
: SimpleFile(context, file.path()) {
for (auto definedAtom : file.defined())
_definedAtoms._atoms.push_back(std::move(definedAtom));
for (auto undefAtom : file.undefined())
_undefinedAtoms._atoms.push_back(std::move(undefAtom));
for (auto shlibAtom : file.sharedLibrary())
_sharedLibraryAtoms._atoms.push_back(std::move(shlibAtom));
for (auto absAtom : file.absolute())
_absoluteAtoms._atoms.push_back(std::move(absAtom));
}
};
class SimpleReference : public Reference {
public:
SimpleReference(Reference::Kind k, uint64_t off, const Atom *t,
Reference::Addend a)
: _target(t), _offsetInAtom(off), _addend(a) {
_kind = k;
}
virtual uint64_t offsetInAtom() const { return _offsetInAtom; }
virtual const Atom *target() const { return _target; }
virtual Addend addend() const { return _addend; }
virtual void setAddend(Addend a) { _addend = a; }
virtual void setTarget(const Atom *newAtom) { _target = newAtom; }
private:
const Atom *_target;
uint64_t _offsetInAtom;
Addend _addend;
};
class SimpleDefinedAtom : public DefinedAtom {
public:
explicit SimpleDefinedAtom(const File &f) : _file(f) {
static uint32_t lastOrdinal = 0;
_ordinal = lastOrdinal++;
}
virtual const File &file() const { return _file; }
virtual StringRef name() const { return StringRef(); }
virtual uint64_t ordinal() const { return _ordinal; }
virtual Scope scope() const { return DefinedAtom::scopeLinkageUnit; }
virtual Interposable interposable() const { return DefinedAtom::interposeNo; }
virtual Merge merge() const { return DefinedAtom::mergeNo; }
virtual Alignment alignment() const { return Alignment(0, 0); }
virtual SectionChoice sectionChoice() const {
return DefinedAtom::sectionBasedOnContent;
}
virtual SectionPosition sectionPosition() const {
return DefinedAtom::sectionPositionAny;
}
virtual StringRef customSectionName() const { return StringRef(); }
virtual DeadStripKind deadStrip() const {
return DefinedAtom::deadStripNormal;
}
virtual bool isAlias() const { return false; }
virtual DefinedAtom::reference_iterator begin() const {
uintptr_t index = 0;
const void *it = reinterpret_cast<const void *>(index);
return reference_iterator(*this, it);
}
virtual DefinedAtom::reference_iterator end() const {
uintptr_t index = _references.size();
const void *it = reinterpret_cast<const void *>(index);
return reference_iterator(*this, it);
}
virtual const Reference *derefIterator(const void *it) const {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
assert(index < _references.size());
return &_references[index];
}
virtual void incrementIterator(const void *&it) const {
uintptr_t index = reinterpret_cast<uintptr_t>(it);
++index;
it = reinterpret_cast<const void *>(index);
}
void addReference(Reference::Kind kind, uint64_t offset, const Atom *target,
Reference::Addend addend) {
_references.push_back(SimpleReference(kind, offset, target, addend));
}
void setOrdinal(uint64_t ord) { _ordinal = ord; }
private:
const File &_file;
uint64_t _ordinal;
std::vector<SimpleReference> _references;
};
class SimpleUndefinedAtom : public UndefinedAtom {
public:
SimpleUndefinedAtom(const File &f, StringRef name) : _file(f), _name(name) {
assert(!name.empty() && "UndefinedAtoms must have a name");
}
/// file - returns the File that produced/owns this Atom
virtual const File &file() const { return _file; }
/// name - The name of the atom. For a function atom, it is the (mangled)
/// name of the function.
virtual StringRef name() const { return _name; }
virtual CanBeNull canBeNull() const { return UndefinedAtom::canBeNullNever; }
private:
const File &_file;
StringRef _name;
};
} // end namespace lld
#endif

View File

@@ -1,52 +0,0 @@
//===- lld/ReaderWriter/Writer.h - Abstract File Format Interface ---------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_WRITER_H
#define LLD_READER_WRITER_WRITER_H
#include "lld/Core/LLVM.h"
#include <memory>
#include <vector>
namespace lld {
class ELFLinkingContext;
class File;
class MachOLinkingContext;
class PECOFFLinkingContext;
class LinkingContext;
/// \brief The Writer is an abstract class for writing object files, shared
/// library files, and executable files. Each file format (e.g. ELF, mach-o,
/// PECOFF, native, etc) have a concrete subclass of Writer.
class Writer {
public:
virtual ~Writer();
/// \brief Write a file from the supplied File object
virtual error_code writeFile(const File &linkedFile, StringRef path) = 0;
/// \brief This method is called by Core Linking to give the Writer a chance
/// to add file format specific "files" to set of files to be linked. This is
/// how file format specific atoms can be added to the link.
virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
protected:
// only concrete subclasses can be instantiated
Writer();
};
std::unique_ptr<Writer> createWriterELF(const ELFLinkingContext &);
std::unique_ptr<Writer> createWriterMachO(const MachOLinkingContext &);
std::unique_ptr<Writer> createWriterNative(const LinkingContext &);
std::unique_ptr<Writer> createWriterPECOFF(const PECOFFLinkingContext &);
std::unique_ptr<Writer> createWriterYAML(const LinkingContext &);
} // end namespace lld
#endif

View File

@@ -1,4 +0,0 @@
add_subdirectory(Core)
add_subdirectory(Driver)
add_subdirectory(Passes)
add_subdirectory(ReaderWriter)

View File

@@ -1,17 +0,0 @@
set(LLVM_LINK_COMPONENTS support)
add_lld_library(lldCore
DefinedAtom.cpp
Error.cpp
File.cpp
InputGraph.cpp
LinkingContext.cpp
PassManager.cpp
Resolver.cpp
SymbolTable.cpp
)
target_link_libraries(lldCore
lldNative
lldYAML
)

View File

@@ -1,84 +0,0 @@
//===- DefinedAtom.cpp ------------------------------------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/ErrorHandling.h"
#include "lld/Core/DefinedAtom.h"
namespace lld {
DefinedAtom::ContentPermissions DefinedAtom::permissions() const {
// By default base permissions on content type.
return permissions(this->contentType());
}
// Utility function for deriving permissions from content type
DefinedAtom::ContentPermissions DefinedAtom::permissions(ContentType type) {
switch (type) {
case typeCode:
case typeResolver:
case typeBranchIsland:
case typeBranchShim:
case typeStub:
case typeStubHelper:
return permR_X;
case typeConstant:
case typeCString:
case typeUTF16String:
case typeCFI:
case typeLSDA:
case typeLiteral4:
case typeLiteral8:
case typeLiteral16:
case typeDTraceDOF:
case typeCompactUnwindInfo:
case typeRONote:
case typeNoAlloc:
return permR__;
case typeData:
case typeDataFast:
case typeZeroFill:
case typeZeroFillFast:
case typeObjC1Class:
case typeLazyPointer:
case typeLazyDylibPointer:
case typeThunkTLV:
case typeDataDirectoryEntry:
case typeRWNote:
return permRW_;
case typeGOT:
case typeConstData:
case typeCFString:
case typeInitializerPtr:
case typeTerminatorPtr:
case typeCStringPtr:
case typeObjCClassPtr:
case typeObjC2CategoryList:
case typeTLVInitialData:
case typeTLVInitialZeroFill:
case typeTLVInitializerPtr:
case typeThreadData:
case typeThreadZeroFill:
return permRW_L;
case typeUnknown:
case typeTempLTO:
return permUnknown;
}
llvm_unreachable("unknown content type");
}
} // namespace

View File

@@ -1,129 +0,0 @@
//===- Error.cpp - system_error extensions for lld --------------*- C++ -*-===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/Error.h"
#include "llvm/Support/ErrorHandling.h"
using namespace lld;
class _NativeReaderErrorCategory : public llvm::_do_message {
public:
virtual const char* name() const {
return "lld.native.reader";
}
virtual std::string message(int ev) const {
if (NativeReaderError(ev) == NativeReaderError::success)
return "Success";
if (NativeReaderError(ev) == NativeReaderError::unknown_file_format)
return "Unknown file format";
if (NativeReaderError(ev) == NativeReaderError::file_too_short)
return "file truncated";
if (NativeReaderError(ev) == NativeReaderError::file_malformed)
return "file malformed";
if (NativeReaderError(ev) == NativeReaderError::memory_error)
return "out of memory";
if (NativeReaderError(ev) == NativeReaderError::unknown_chunk_type)
return "unknown chunk type";
llvm_unreachable("An enumerator of NativeReaderError does not have a "
"message defined.");
}
virtual llvm::error_condition default_error_condition(int ev) const {
if (NativeReaderError(ev) == NativeReaderError::success)
return llvm::errc::success;
return llvm::errc::invalid_argument;
}
};
const llvm::error_category &lld::native_reader_category() {
static _NativeReaderErrorCategory o;
return o;
}
class _YamlReaderErrorCategory : public llvm::_do_message {
public:
virtual const char* name() const {
return "lld.yaml.reader";
}
virtual std::string message(int ev) const {
if (YamlReaderError(ev) == YamlReaderError::success)
return "Success";
if (YamlReaderError(ev) == YamlReaderError::unknown_keyword)
return "Unknown keyword found in yaml file";
if (YamlReaderError(ev) == YamlReaderError::illegal_value)
return "Bad value found in yaml file";
llvm_unreachable("An enumerator of YamlReaderError does not have a "
"message defined.");
}
virtual llvm::error_condition default_error_condition(int ev) const {
if (YamlReaderError(ev) == YamlReaderError::success)
return llvm::errc::success;
return llvm::errc::invalid_argument;
}
};
const llvm::error_category &lld::YamlReaderCategory() {
static _YamlReaderErrorCategory o;
return o;
}
class _LinkerScriptReaderErrorCategory : public llvm::_do_message {
public:
virtual const char *name() const { return "lld.linker-script.reader"; }
virtual std::string message(int ev) const {
LinkerScriptReaderError e = LinkerScriptReaderError(ev);
if (e == LinkerScriptReaderError::success)
return "Success";
if (e == LinkerScriptReaderError::parse_error)
return "Error parsing linker script";
llvm_unreachable(
"An enumerator of LinkerScriptReaderError does not have a "
"message defined.");
}
virtual llvm::error_condition default_error_condition(int ev) const {
LinkerScriptReaderError e = LinkerScriptReaderError(ev);
if (e == LinkerScriptReaderError::success)
return llvm::errc::success;
return llvm::errc::invalid_argument;
}
};
const llvm::error_category &lld::LinkerScriptReaderCategory() {
static _LinkerScriptReaderErrorCategory o;
return o;
}
class _InputGraphErrorCategory : public llvm::_do_message {
public:
virtual const char *name() const { return "lld.inputGraph.parse"; }
virtual std::string message(int ev) const {
if (InputGraphError(ev) == InputGraphError::success)
return "Success";
llvm_unreachable("An enumerator of InputGraphError does not have a "
"message defined.");
}
virtual llvm::error_condition default_error_condition(int ev) const {
if (InputGraphError(ev) == InputGraphError::success)
return llvm::errc::success;
return llvm::errc::invalid_argument;
}
};
const llvm::error_category &lld::InputGraphErrorCategory() {
static _InputGraphErrorCategory i;
return i;
}

View File

@@ -1,30 +0,0 @@
//===- Core/File.cpp - A Container of Atoms -------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
namespace lld {
File::~File() {}
StringRef File::translationUnitSource() const {
return StringRef();
}
File::atom_collection_empty<DefinedAtom> File::_noDefinedAtoms;
File::atom_collection_empty<UndefinedAtom> File::_noUndefinedAtoms;
File::atom_collection_empty<SharedLibraryAtom> File::_noSharedLibraryAtoms;
File::atom_collection_empty<AbsoluteAtom> File::_noAbsoluteAtoms;
} // namespace lld

View File

@@ -1,178 +0,0 @@
//===- lib/Core/InputGraph.cpp --------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/InputGraph.h"
#include "lld/Core/Resolver.h"
using namespace lld;
namespace {
bool sortInputElements(const std::unique_ptr<InputElement> &a,
const std::unique_ptr<InputElement> &b) {
return a->getOrdinal() < b->getOrdinal();
}
}
bool InputGraph::addInputElement(std::unique_ptr<InputElement> ie) {
_inputArgs.push_back(std::move(ie));
return true;
}
bool InputGraph::assignOrdinals() {
for (auto &ie : _inputArgs)
ie->setOrdinal(++_ordinal);
return true;
}
void InputGraph::doPostProcess() {
std::stable_sort(_inputArgs.begin(), _inputArgs.end(), sortInputElements);
}
bool InputGraph::validate() {
for (auto &ie : _inputArgs)
if (!ie->validate())
return false;
return true;
}
bool InputGraph::dump(raw_ostream &diagnostics) {
for (auto &ie : _inputArgs)
if (!ie->dump(diagnostics))
return false;
return true;
}
/// \brief Insert element at position
void InputGraph::insertElementsAt(
std::vector<std::unique_ptr<InputElement> > inputElements,
Position position, size_t pos) {
if (position == InputGraph::Position::BEGIN)
pos = 0;
else if (position == InputGraph::Position::END)
pos = _inputArgs.size();
_inputArgs.insert(_inputArgs.begin() + pos,
std::make_move_iterator(inputElements.begin()),
std::make_move_iterator(inputElements.end()));
}
void InputGraph::insertOneElementAt(std::unique_ptr<InputElement> element,
Position position, size_t pos) {
if (position == InputGraph::Position::BEGIN)
pos = 0;
else if (position == InputGraph::Position::END)
pos = _inputArgs.size();
_inputArgs.insert(_inputArgs.begin() + pos, std::move(element));
}
/// \brief Helper functions for the resolver
ErrorOr<InputElement *> InputGraph::getNextInputElement() {
if (_nextElementIndex >= _inputArgs.size())
return make_error_code(InputGraphError::no_more_elements);
return _inputArgs[_nextElementIndex++].get();
}
/// \brief Set the index on what inputElement has to be returned
error_code InputGraph::setNextElementIndex(uint32_t index) {
if (index > _inputArgs.size())
return make_error_code(llvm::errc::invalid_argument);
_nextElementIndex = index;
return error_code::success();
}
/// InputElement
/// \brief Initialize the Input Element, The ordinal value of an input Element
/// is initially set to -1, if the user wants to override its ordinal,
/// let the user do it
InputElement::InputElement(Kind type, int64_t ordinal)
: _kind(type), _ordinal(ordinal), _weight(0) {}
/// FileNode
FileNode::FileNode(StringRef path, int64_t ordinal)
: InputElement(InputElement::Kind::File, ordinal), _path(path),
_resolveState(Resolver::StateNoChange), _nextFileIndex(0) {}
/// \brief Read the file into _buffer.
error_code FileNode::getBuffer(StringRef filePath) {
// Create a memory buffer
OwningPtr<MemoryBuffer> opmb;
if (error_code ec = MemoryBuffer::getFileOrSTDIN(filePath, opmb))
return ec;
std::unique_ptr<MemoryBuffer> mb(opmb.take());
_buffer = std::move(mb);
return error_code::success();
}
// Reset the next file that would be be processed by the resolver.
// Reset the resolve state too.
void FileNode::resetNextIndex() {
_nextFileIndex = 0;
setResolveState(Resolver::StateNoChange);
}
/// ControlNode
/// \brief Get the resolver State. The return value of the resolve
/// state for a control node is the or'ed value of the resolve states
/// contained in it.
uint32_t ControlNode::getResolveState() const {
uint32_t resolveState = Resolver::StateNoChange;
for (auto &elem : _elements)
resolveState |= elem->getResolveState();
return resolveState;
}
/// \brief Set the resolve state for the current element
/// thats processed by the resolver.
void ControlNode::setResolveState(uint32_t resolveState) {
if (_elements.empty())
return;
_elements[_currentElementIndex]->setResolveState(resolveState);
}
/// SimpleFileNode
SimpleFileNode::SimpleFileNode(StringRef path, int64_t ordinal)
: InputElement(InputElement::Kind::SimpleFile, ordinal), _path(path),
_nextFileIndex(0), _resolveState(Resolver::StateNoChange) {}
/// Group
/// \brief Return the next file that need to be processed by the resolver.
/// This also processes input elements depending on the resolve status
/// of the input elements contained in the group.
ErrorOr<File &> Group::getNextFile() {
// If there are no elements, move on to the next input element
if (_elements.empty())
return make_error_code(InputGraphError::no_more_files);
for (;;) {
// If we have processed all the elements as part of this node
// check the resolver status for each input element and if the status
// has not changed, move onto the next file.
if (_nextElementIndex == _elements.size()) {
if (getResolveState() == Resolver::StateNoChange)
return make_error_code(InputGraphError::no_more_files);
resetNextIndex();
}
_currentElementIndex = _nextElementIndex;
auto file = _elements[_nextElementIndex]->getNextFile();
// Move on to the next element if we have finished processing all
// the files in the input element
if (error_code(file) == InputGraphError::no_more_files) {
_nextElementIndex++;
continue;
}
return *file;
}
}

View File

@@ -1,113 +0,0 @@
//===- lib/Core/LinkingContext.cpp - Linker Context Object Interface ------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/LinkingContext.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/Writer.h"
#include "lld/ReaderWriter/Simple.h"
#include "llvm/ADT/Triple.h"
namespace lld {
LinkingContext::LinkingContext()
: _deadStrip(false), _globalsAreDeadStripRoots(false),
_searchArchivesToOverrideTentativeDefinitions(false),
_searchSharedLibrariesToOverrideTentativeDefinitions(false),
_warnIfCoalesableAtomsHaveDifferentCanBeNull(false),
_warnIfCoalesableAtomsHaveDifferentLoadName(false),
_printRemainingUndefines(true), _allowRemainingUndefines(false),
_logInputFiles(false), _allowShlibUndefines(false),
_outputFileType(OutputFileType::Default), _currentInputElement(nullptr),
_nextOrdinal(0) {}
LinkingContext::~LinkingContext() {}
bool LinkingContext::validate(raw_ostream &diagnostics) {
_yamlReader = createReaderYAML(*this);
_nativeReader = createReaderNative(*this);
return validateImpl(diagnostics);
}
error_code LinkingContext::writeFile(const File &linkedFile) const {
return this->writer().writeFile(linkedFile, _outputPath);
}
bool LinkingContext::createImplicitFiles(
std::vector<std::unique_ptr<File> > &result) const {
return this->writer().createImplicitFiles(result);
}
std::unique_ptr<File> LinkingContext::createEntrySymbolFile() const {
if (entrySymbolName().empty())
return nullptr;
std::unique_ptr<SimpleFile> entryFile(
new SimpleFile(*this, "command line option -entry"));
entryFile->addAtom(
*(new (_allocator) SimpleUndefinedAtom(*entryFile, entrySymbolName())));
return std::move(entryFile);
}
std::unique_ptr<File> LinkingContext::createUndefinedSymbolFile() const {
if (_initialUndefinedSymbols.empty())
return nullptr;
std::unique_ptr<SimpleFile> undefinedSymFile(
new SimpleFile(*this, "command line option -u"));
for (auto undefSymStr : _initialUndefinedSymbols)
undefinedSymFile->addAtom(*(new (_allocator) SimpleUndefinedAtom(
*undefinedSymFile, undefSymStr)));
return std::move(undefinedSymFile);
}
bool LinkingContext::createInternalFiles(
std::vector<std::unique_ptr<File> > &result) const {
std::unique_ptr<File> internalFile;
internalFile = createEntrySymbolFile();
if (internalFile)
result.push_back(std::move(internalFile));
internalFile = createUndefinedSymbolFile();
if (internalFile)
result.push_back(std::move(internalFile));
return true;
}
void LinkingContext::setResolverState(uint32_t state) {
_currentInputElement->setResolveState(state);
}
ErrorOr<File &> LinkingContext::nextFile() {
// When nextFile() is called for the first time, _currentInputElement is not
// initialized. Initialize it with the first element of the input graph.
if (_currentInputElement == nullptr) {
ErrorOr<InputElement *> elem = inputGraph().getNextInputElement();
if (error_code(elem) == InputGraphError::no_more_elements)
return make_error_code(InputGraphError::no_more_files);
_currentInputElement = *elem;
}
// Otherwise, try to get the next file of _currentInputElement. If the current
// input element points to an archive file, and there's a file left in the
// archive, it will succeed. If not, try to get the next file in the input
// graph.
for (;;) {
ErrorOr<File &> nextFile = _currentInputElement->getNextFile();
if (error_code(nextFile) != InputGraphError::no_more_files)
return std::move(nextFile);
ErrorOr<InputElement *> elem = inputGraph().getNextInputElement();
if (error_code(elem) == InputGraphError::no_more_elements ||
*elem == nullptr)
return make_error_code(InputGraphError::no_more_files);
_currentInputElement = *elem;
}
}
void LinkingContext::addPasses(PassManager &pm) {}
} // end namespace lld

View File

@@ -1,24 +0,0 @@
//===- lib/Core/PassManager.cpp - Manage linker passes --------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/PassManager.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/Pass.h"
#include "llvm/Support/ErrorOr.h"
namespace lld {
error_code PassManager::runOnFile(std::unique_ptr<MutableFile> &mf) {
for (auto &pass : _passes) {
pass->perform(mf);
}
return error_code::success();
}
} // end namespace lld

View File

@@ -1,493 +0,0 @@
//===- Core/Resolver.cpp - Resolves Atom References -----------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/Atom.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/File.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/SymbolTable.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/UndefinedAtom.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <vector>
namespace lld {
namespace {
/// This is used as a filter function to std::remove_if to dead strip atoms.
class NotLive {
public:
explicit NotLive(const llvm::DenseSet<const Atom*>& la) : _liveAtoms(la) { }
bool operator()(const Atom *atom) const {
// don't remove if live
if ( _liveAtoms.count(atom) )
return false;
// don't remove if marked never-dead-strip
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(atom)) {
if ( defAtom->deadStrip() == DefinedAtom::deadStripNever )
return false;
}
// do remove this atom
return true;
}
private:
const llvm::DenseSet<const Atom*> _liveAtoms;
};
/// This is used as a filter function to std::remove_if to coalesced atoms.
class AtomCoalescedAway {
public:
explicit AtomCoalescedAway(SymbolTable &sym) : _symbolTable(sym) {}
bool operator()(const Atom *atom) const {
const Atom *rep = _symbolTable.replacement(atom);
return rep != atom;
}
private:
SymbolTable &_symbolTable;
};
} // namespace
// called before the first atom in any file is added with doAtom()
void Resolver::doFile(const File &file) {}
void Resolver::handleFile(const File &file) {
uint32_t resolverState = Resolver::StateNoChange;
doFile(file);
for (const DefinedAtom *atom : file.defined()) {
doDefinedAtom(*atom);
resolverState |= StateNewDefinedAtoms;
}
for (const UndefinedAtom *undefAtom : file.undefined()) {
doUndefinedAtom(*undefAtom);
resolverState |= StateNewUndefinedAtoms;
}
for (const SharedLibraryAtom *shlibAtom : file.sharedLibrary()) {
doSharedLibraryAtom(*shlibAtom);
resolverState |= StateNewSharedLibraryAtoms;
}
for (const AbsoluteAtom *absAtom : file.absolute()) {
doAbsoluteAtom(*absAtom);
resolverState |= StateNewAbsoluteAtoms;
}
_context.setResolverState(resolverState);
}
void
Resolver::forEachUndefines(UndefCallback callback, bool searchForOverrides) {
// Handle normal archives
int64_t undefineGenCount = 0;
do {
undefineGenCount = _symbolTable.size();
std::vector<const UndefinedAtom *> undefines;
_symbolTable.undefines(undefines);
for (const UndefinedAtom *undefAtom : undefines) {
StringRef undefName = undefAtom->name();
// load for previous undefine may also have loaded this undefine
if (!_symbolTable.isDefined(undefName))
callback(undefName, false);
// If the undefined symbol has an alternative name, try to resolve the
// symbol with the name to give it a second chance. This feature is used
// for COFF "weak external" symbol.
if (!_symbolTable.isDefined(undefName)) {
if (const UndefinedAtom *fallbackUndefAtom = undefAtom->fallback()) {
_symbolTable.addReplacement(undefAtom, fallbackUndefAtom);
_symbolTable.add(*fallbackUndefAtom);
}
}
}
// search libraries for overrides of common symbols
if (searchForOverrides) {
std::vector<StringRef> tentDefNames;
_symbolTable.tentativeDefinitions(tentDefNames);
for (StringRef tentDefName : tentDefNames) {
// Load for previous tentative may also have loaded
// something that overrode this tentative, so always check.
const Atom *curAtom = _symbolTable.findByName(tentDefName);
assert(curAtom != nullptr);
if (const DefinedAtom *curDefAtom = dyn_cast<DefinedAtom>(curAtom)) {
if (curDefAtom->merge() == DefinedAtom::mergeAsTentative)
callback(tentDefName, true);
}
}
}
} while (undefineGenCount != _symbolTable.size());
}
void Resolver::handleArchiveFile(const File &file) {
const ArchiveLibraryFile *archiveFile = dyn_cast<ArchiveLibraryFile>(&file);
auto callback = [&](StringRef undefName, bool dataSymbolOnly) {
if (const File *member = archiveFile->find(undefName, dataSymbolOnly)) {
member->setOrdinal(_context.getNextOrdinalAndIncrement());
handleFile(*member);
}
};
bool searchForOverrides = _context.searchArchivesToOverrideTentativeDefinitions();
forEachUndefines(callback, searchForOverrides);
}
void Resolver::handleSharedLibrary(const File &file) {
// Add all the atoms from the shared library
const SharedLibraryFile *sharedLibrary = dyn_cast<SharedLibraryFile>(&file);
handleFile(*sharedLibrary);
auto callback = [&](StringRef undefName, bool dataSymbolOnly) {
if (const SharedLibraryAtom *shAtom = sharedLibrary->exports(
undefName, dataSymbolOnly))
doSharedLibraryAtom(*shAtom);
};
bool searchForOverrides =
_context.searchSharedLibrariesToOverrideTentativeDefinitions();
forEachUndefines(callback, searchForOverrides);
}
void Resolver::doUndefinedAtom(const UndefinedAtom& atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " UndefinedAtom: "
<< llvm::format("0x%09lX", &atom)
<< ", name="
<< atom.name()
<< "\n");
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
_symbolTable.add(atom);
}
// called on each atom when a file is added
void Resolver::doDefinedAtom(const DefinedAtom &atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " DefinedAtom: "
<< llvm::format("0x%09lX", &atom)
<< ", file=#"
<< atom.file().ordinal()
<< ", atom=#"
<< atom.ordinal()
<< ", name="
<< atom.name()
<< "\n");
// Verify on zero-size atoms are pinned to start or end of section.
switch ( atom.sectionPosition() ) {
case DefinedAtom::sectionPositionStart:
case DefinedAtom::sectionPositionEnd:
assert(atom.size() == 0);
break;
case DefinedAtom::sectionPositionEarly:
case DefinedAtom::sectionPositionAny:
break;
}
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
_symbolTable.add(atom);
if (_context.deadStrip()) {
// add to set of dead-strip-roots, all symbols that
// the compiler marks as don't strip
if (atom.deadStrip() == DefinedAtom::deadStripNever)
_deadStripRoots.insert(&atom);
}
}
void Resolver::doSharedLibraryAtom(const SharedLibraryAtom& atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " SharedLibraryAtom: "
<< llvm::format("0x%09lX", &atom)
<< ", name="
<< atom.name()
<< "\n");
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
_symbolTable.add(atom);
}
void Resolver::doAbsoluteAtom(const AbsoluteAtom& atom) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< " AbsoluteAtom: "
<< llvm::format("0x%09lX", &atom)
<< ", name="
<< atom.name()
<< "\n");
// add to list of known atoms
_atoms.push_back(&atom);
// tell symbol table
if (atom.scope() != Atom::scopeTranslationUnit) {
_symbolTable.add(atom);
}
}
// utility to add a vector of atoms
void Resolver::addAtoms(const std::vector<const DefinedAtom*>& newAtoms) {
for (const DefinedAtom *newAtom : newAtoms) {
this->doDefinedAtom(*newAtom);
}
}
// Keep adding atoms until _context.nextFile() returns an error. This function
// is where undefined atoms are resolved.
bool Resolver::resolveUndefines() {
ScopedTask task(getDefaultDomain(), "resolveUndefines");
for (;;) {
ErrorOr<File &> file = _context.nextFile();
_context.setResolverState(Resolver::StateNoChange);
if (error_code(file) == InputGraphError::no_more_files)
return true;
if (!file) {
llvm::errs() << "Error occurred in nextFile: "
<< error_code(file).message() << "\n";
return false;
}
switch (file->kind()) {
case File::kindObject:
assert(!file->hasOrdinal());
file->setOrdinal(_context.getNextOrdinalAndIncrement());
handleFile(*file);
break;
case File::kindArchiveLibrary:
if (!file->hasOrdinal())
file->setOrdinal(_context.getNextOrdinalAndIncrement());
handleArchiveFile(*file);
break;
case File::kindSharedLibrary:
if (!file->hasOrdinal())
file->setOrdinal(_context.getNextOrdinalAndIncrement());
handleSharedLibrary(*file);
break;
case File::kindLinkerScript:
llvm_unreachable("linker script should not be returned by nextFile()");
}
}
}
// switch all references to undefined or coalesced away atoms
// to the new defined atom
void Resolver::updateReferences() {
ScopedTask task(getDefaultDomain(), "updateReferences");
for(const Atom *atom : _atoms) {
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(atom)) {
for (const Reference *ref : *defAtom) {
const Atom* newTarget = _symbolTable.replacement(ref->target());
(const_cast<Reference*>(ref))->setTarget(newTarget);
}
}
}
}
// for dead code stripping, recursively mark atoms "live"
void Resolver::markLive(const Atom &atom) {
// if already marked live, then done (stop recursion)
if ( _liveAtoms.count(&atom) )
return;
// mark this atom is live
_liveAtoms.insert(&atom);
// mark all atoms it references as live
if ( const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(&atom)) {
for (const Reference *ref : *defAtom) {
const Atom *target = ref->target();
if ( target != nullptr )
this->markLive(*target);
}
}
}
// remove all atoms not actually used
void Resolver::deadStripOptimize() {
ScopedTask task(getDefaultDomain(), "deadStripOptimize");
// only do this optimization with -dead_strip
if (!_context.deadStrip())
return;
// clear liveness on all atoms
_liveAtoms.clear();
// By default, shared libraries are built with all globals as dead strip roots
if (_context.globalsAreDeadStripRoots()) {
for (const Atom *atom : _atoms) {
const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom);
if (defAtom == nullptr)
continue;
if ( defAtom->scope() == DefinedAtom::scopeGlobal )
_deadStripRoots.insert(defAtom);
}
}
// Or, use list of names that are dead stip roots.
for (const StringRef &name : _context.deadStripRoots()) {
const Atom *symAtom = _symbolTable.findByName(name);
assert(symAtom);
if (symAtom->definition() == Atom::definitionUndefined)
// Dead-strip root atoms can be undefined at this point only when
// allowUndefines flag is on. Skip such undefines.
continue;
_deadStripRoots.insert(symAtom);
}
// mark all roots as live, and recursively all atoms they reference
for ( const Atom *dsrAtom : _deadStripRoots) {
this->markLive(*dsrAtom);
}
// now remove all non-live atoms from _atoms
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
NotLive(_liveAtoms)), _atoms.end());
}
// error out if some undefines remain
bool Resolver::checkUndefines(bool final) {
// when using LTO, undefines are checked after bitcode is optimized
if (_haveLLVMObjs && !final)
return false;
// build vector of remaining undefined symbols
std::vector<const UndefinedAtom *> undefinedAtoms;
_symbolTable.undefines(undefinedAtoms);
if (_context.deadStrip()) {
// When dead code stripping, we don't care if dead atoms are undefined.
undefinedAtoms.erase(std::remove_if(
undefinedAtoms.begin(), undefinedAtoms.end(),
NotLive(_liveAtoms)), undefinedAtoms.end());
}
// error message about missing symbols
if (!undefinedAtoms.empty()) {
// FIXME: need diagnostics interface for writing error messages
bool foundUndefines = false;
for (const UndefinedAtom *undefAtom : undefinedAtoms) {
const File &f = undefAtom->file();
// Skip over a weak symbol.
if (undefAtom->canBeNull() != UndefinedAtom::canBeNullNever)
continue;
// If this is a library and undefined symbols are allowed on the
// target platform, skip over it.
if (isa<SharedLibraryFile>(f) && _context.allowShlibUndefines())
continue;
// If the undefine is coalesced away, skip over it.
if (_symbolTable.replacement(undefAtom) != undefAtom)
continue;
// Seems like this symbol is undefined. Warn that.
foundUndefines = true;
if (_context.printRemainingUndefines()) {
llvm::errs() << "Undefined Symbol: " << undefAtom->file().path()
<< " : " << undefAtom->name() << "\n";
}
}
if (foundUndefines) {
if (_context.printRemainingUndefines())
llvm::errs() << "symbol(s) not found\n";
return true;
}
}
return false;
}
// remove from _atoms all coaleseced away atoms
void Resolver::removeCoalescedAwayAtoms() {
ScopedTask task(getDefaultDomain(), "removeCoalescedAwayAtoms");
_atoms.erase(std::remove_if(_atoms.begin(), _atoms.end(),
AtomCoalescedAway(_symbolTable)), _atoms.end());
}
void Resolver::linkTimeOptimize() {
// FIX ME
}
bool Resolver::resolve() {
if (!this->resolveUndefines())
return false;
this->updateReferences();
this->deadStripOptimize();
if (this->checkUndefines(false)) {
if (!_context.allowRemainingUndefines())
return false;
}
this->removeCoalescedAwayAtoms();
this->linkTimeOptimize();
this->_result->addAtoms(_atoms);
return true;
}
void Resolver::MergedFile::addAtom(const Atom& atom) {
if (const DefinedAtom* defAtom = dyn_cast<DefinedAtom>(&atom)) {
_definedAtoms._atoms.push_back(defAtom);
} else if (const UndefinedAtom* undefAtom = dyn_cast<UndefinedAtom>(&atom)) {
_undefinedAtoms._atoms.push_back(undefAtom);
} else if (const SharedLibraryAtom* slAtom =
dyn_cast<SharedLibraryAtom>(&atom)) {
_sharedLibraryAtoms._atoms.push_back(slAtom);
} else if (const AbsoluteAtom* abAtom = dyn_cast<AbsoluteAtom>(&atom)) {
_absoluteAtoms._atoms.push_back(abAtom);
} else {
llvm_unreachable("atom has unknown definition kind");
}
}
MutableFile::DefinedAtomRange Resolver::MergedFile::definedAtoms() {
return range<std::vector<const DefinedAtom*>::iterator>(
_definedAtoms._atoms.begin(), _definedAtoms._atoms.end());
}
void Resolver::MergedFile::addAtoms(std::vector<const Atom*>& all) {
ScopedTask task(getDefaultDomain(), "addAtoms");
DEBUG_WITH_TYPE("resolver", llvm::dbgs() << "Resolver final atom list:\n");
for ( const Atom *atom : all ) {
DEBUG_WITH_TYPE("resolver", llvm::dbgs()
<< llvm::format(" 0x%09lX", atom)
<< ", name="
<< atom->name()
<< "\n");
this->addAtom(*atom);
}
}
} // namespace lld

View File

@@ -1,364 +0,0 @@
//===- Core/SymbolTable.cpp - Main Symbol Table ---------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Core/SymbolTable.h"
#include "lld/Core/AbsoluteAtom.h"
#include "lld/Core/Atom.h"
#include "lld/Core/DefinedAtom.h"
#include "lld/Core/File.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Resolver.h"
#include "lld/Core/SharedLibraryAtom.h"
#include "lld/Core/LinkingContext.h"
#include "lld/Core/UndefinedAtom.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <vector>
namespace lld {
SymbolTable::SymbolTable(const LinkingContext &context) : _context(context) {}
void SymbolTable::add(const UndefinedAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const SharedLibraryAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const AbsoluteAtom &atom) {
this->addByName(atom);
}
void SymbolTable::add(const DefinedAtom &atom) {
if (!atom.name().empty() &&
(atom.scope() != DefinedAtom::scopeTranslationUnit)) {
// Named atoms cannot be merged by content.
assert(atom.merge() != DefinedAtom::mergeByContent);
// Track named atoms that are not scoped to file (static).
this->addByName(atom);
} else if (atom.merge() == DefinedAtom::mergeByContent) {
// Named atoms cannot be merged by content.
assert(atom.name().empty());
this->addByContent(atom);
}
}
enum NameCollisionResolution {
NCR_First,
NCR_Second,
NCR_DupDef,
NCR_DupUndef,
NCR_DupShLib,
NCR_Error
};
static NameCollisionResolution cases[4][4] = {
//regular absolute undef sharedLib
{
// first is regular
NCR_DupDef, NCR_Error, NCR_First, NCR_First
},
{
// first is absolute
NCR_Error, NCR_Error, NCR_First, NCR_First
},
{
// first is undef
NCR_Second, NCR_Second, NCR_DupUndef, NCR_Second
},
{
// first is sharedLib
NCR_Second, NCR_Second, NCR_First, NCR_DupShLib
}
};
static NameCollisionResolution collide(Atom::Definition first,
Atom::Definition second) {
return cases[first][second];
}
enum MergeResolution {
MCR_First,
MCR_Second,
MCR_Largest,
MCR_Error
};
static MergeResolution mergeCases[4][4] = {
// no tentative weak weakAddressUsed
{
// first is no
MCR_Error, MCR_First, MCR_First, MCR_First
},
{
// first is tentative
MCR_Second, MCR_Largest, MCR_Second, MCR_Second
},
{
// first is weak
MCR_Second, MCR_First, MCR_First, MCR_Second
},
{
// first is weakAddressUsed
MCR_Second, MCR_First, MCR_First, MCR_First
}
};
static MergeResolution mergeSelect(DefinedAtom::Merge first,
DefinedAtom::Merge second) {
return mergeCases[first][second];
}
void SymbolTable::addByName(const Atom & newAtom) {
StringRef name = newAtom.name();
assert(!name.empty());
const Atom *existing = this->findByName(name);
if (existing == nullptr) {
// Name is not in symbol table yet, add it associate with this atom.
_nameTable[name] = &newAtom;
return;
}
// Name is already in symbol table and associated with another atom.
bool useNew = true;
switch (collide(existing->definition(), newAtom.definition())) {
case NCR_First:
useNew = false;
break;
case NCR_Second:
useNew = true;
break;
case NCR_DupDef:
assert(existing->definition() == Atom::definitionRegular);
assert(newAtom.definition() == Atom::definitionRegular);
switch (mergeSelect(((DefinedAtom*)existing)->merge(),
((DefinedAtom*)(&newAtom))->merge())) {
case MCR_First:
useNew = false;
break;
case MCR_Second:
useNew = true;
break;
case MCR_Largest:
useNew = true;
break;
case MCR_Error:
llvm::errs() << "Duplicate symbols: "
<< existing->name()
<< ":"
<< existing->file().path()
<< " and "
<< newAtom.name()
<< ":"
<< newAtom.file().path()
<< "\n";
llvm::report_fatal_error("duplicate symbol error");
break;
}
break;
case NCR_DupUndef: {
const UndefinedAtom* existingUndef = dyn_cast<UndefinedAtom>(existing);
const UndefinedAtom* newUndef = dyn_cast<UndefinedAtom>(&newAtom);
assert(existingUndef != nullptr);
assert(newUndef != nullptr);
bool sameCanBeNull = (existingUndef->canBeNull() == newUndef->canBeNull());
if (!sameCanBeNull &&
_context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
llvm::errs() << "lld warning: undefined symbol "
<< existingUndef->name()
<< " has different weakness in "
<< existingUndef->file().path()
<< " and in " << newUndef->file().path() << "\n";
}
const UndefinedAtom *existingFallback = existingUndef->fallback();
const UndefinedAtom *newFallback = newUndef->fallback();
bool hasDifferentFallback =
(existingFallback && newFallback &&
existingFallback->name() != newFallback->name());
if (hasDifferentFallback) {
llvm::errs() << "lld warning: undefined symbol "
<< existingUndef->name() << " has different fallback: "
<< existingFallback->name() << " in "
<< existingUndef->file().path() << " and "
<< newFallback->name() << " in "
<< newUndef->file().path() << "\n";
}
bool hasNewFallback = newUndef->fallback();
if (sameCanBeNull)
useNew = hasNewFallback;
else
useNew = (newUndef->canBeNull() < existingUndef->canBeNull());
break;
}
case NCR_DupShLib: {
const SharedLibraryAtom* curShLib =
dyn_cast<SharedLibraryAtom>(existing);
const SharedLibraryAtom* newShLib =
dyn_cast<SharedLibraryAtom>(&newAtom);
assert(curShLib != nullptr);
assert(newShLib != nullptr);
bool sameNullness = (curShLib->canBeNullAtRuntime()
== newShLib->canBeNullAtRuntime());
bool sameName = curShLib->loadName().equals(newShLib->loadName());
if (!sameName) {
useNew = false;
if (_context.warnIfCoalesableAtomsHaveDifferentLoadName()) {
// FIXME: need diagonstics interface for writing warning messages
llvm::errs() << "lld warning: shared library symbol "
<< curShLib->name()
<< " has different load path in "
<< curShLib->file().path()
<< " and in "
<< newShLib->file().path();
}
} else if (!sameNullness) {
useNew = false;
if (_context.warnIfCoalesableAtomsHaveDifferentCanBeNull()) {
// FIXME: need diagonstics interface for writing warning messages
llvm::errs() << "lld warning: shared library symbol "
<< curShLib->name()
<< " has different weakness in "
<< curShLib->file().path()
<< " and in "
<< newShLib->file().path();
}
} else {
// Both shlib atoms are identical and can be coalesced.
useNew = false;
}
}
break;
case NCR_Error:
llvm::errs() << "SymbolTable: error while merging " << name << "\n";
llvm::report_fatal_error("duplicate symbol error");
break;
}
if (useNew) {
// Update name table to use new atom.
_nameTable[name] = &newAtom;
// Add existing atom to replacement table.
_replacedAtoms[existing] = &newAtom;
} else {
// New atom is not being used. Add it to replacement table.
_replacedAtoms[&newAtom] = existing;
}
}
unsigned SymbolTable::AtomMappingInfo::getHashValue(const DefinedAtom *atom) {
auto content = atom->rawContent();
return llvm::hash_combine(atom->size(),
atom->contentType(),
llvm::hash_combine_range(content.begin(),
content.end()));
}
bool SymbolTable::AtomMappingInfo::isEqual(const DefinedAtom * const l,
const DefinedAtom * const r) {
if (l == r)
return true;
if (l == getEmptyKey())
return false;
if (r == getEmptyKey())
return false;
if (l == getTombstoneKey())
return false;
if (r == getTombstoneKey())
return false;
if (l->contentType() != r->contentType())
return false;
if (l->size() != r->size())
return false;
ArrayRef<uint8_t> lc = l->rawContent();
ArrayRef<uint8_t> rc = r->rawContent();
return memcmp(lc.data(), rc.data(), lc.size()) == 0;
}
void SymbolTable::addByContent(const DefinedAtom & newAtom) {
// Currently only read-only constants can be merged.
assert(newAtom.permissions() == DefinedAtom::permR__);
AtomContentSet::iterator pos = _contentTable.find(&newAtom);
if (pos == _contentTable.end()) {
_contentTable.insert(&newAtom);
return;
}
const Atom* existing = *pos;
// New atom is not being used. Add it to replacement table.
_replacedAtoms[&newAtom] = existing;
}
const Atom *SymbolTable::findByName(StringRef sym) {
NameToAtom::iterator pos = _nameTable.find(sym);
if (pos == _nameTable.end())
return nullptr;
return pos->second;
}
bool SymbolTable::isDefined(StringRef sym) {
const Atom *atom = this->findByName(sym);
if (atom == nullptr)
return false;
return atom->definition() != Atom::definitionUndefined;
}
void SymbolTable::addReplacement(const Atom *replaced,
const Atom *replacement) {
_replacedAtoms[replaced] = replacement;
}
const Atom *SymbolTable::replacement(const Atom *atom) {
AtomToAtom::iterator pos = _replacedAtoms.find(atom);
if (pos == _replacedAtoms.end())
return atom;
// might be chain, recurse to end
return this->replacement(pos->second);
}
unsigned int SymbolTable::size() {
return _nameTable.size();
}
void SymbolTable::undefines(std::vector<const UndefinedAtom *> &undefs) {
for (NameToAtom::iterator it = _nameTable.begin(),
end = _nameTable.end(); it != end; ++it) {
const Atom *atom = it->second;
assert(atom != nullptr);
if (const auto undef = dyn_cast<const UndefinedAtom>(atom)) {
AtomToAtom::iterator pos = _replacedAtoms.find(undef);
if (pos != _replacedAtoms.end())
continue;
undefs.push_back(undef);
}
}
}
void SymbolTable::tentativeDefinitions(std::vector<StringRef> &names) {
for (auto entry : _nameTable) {
const Atom *atom = entry.second;
StringRef name = entry.first;
assert(atom != nullptr);
if (const DefinedAtom *defAtom = dyn_cast<DefinedAtom>(atom))
if (defAtom->merge() == DefinedAtom::mergeAsTentative)
names.push_back(name);
}
}
} // namespace lld

View File

@@ -1,18 +0,0 @@
lib/Core
~~~~~~~~
* Add endianness support to the native reader and writer.
* The NativeReader has lots of similar code for converting arrays of ivar
data in mapped memory into arrays of objects. The commonality can be
factored out, maybe templatized.
* The NativeFileFormat.h is old school C structs and constants. We scope
things better by defining constants used with a struct inside the struct
declaration.
* The native reader and writer currently just blast in memory enumeration
values (e.g. DefinedAtom::Scope) into a byte in the disk format. To support
future changes to the enumerations, there should be a translation layer
to map disk values to in-memory values.

View File

@@ -1,36 +0,0 @@
set(LLVM_TARGET_DEFINITIONS UniversalDriverOptions.td)
tablegen(LLVM UniversalDriverOptions.inc -gen-opt-parser-defs)
set(LLVM_TARGET_DEFINITIONS GnuLdOptions.td)
tablegen(LLVM GnuLdOptions.inc -gen-opt-parser-defs)
set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
set(LLVM_TARGET_DEFINITIONS WinLinkOptions.td)
tablegen(LLVM WinLinkOptions.inc -gen-opt-parser-defs)
add_public_tablegen_target(DriverOptionsTableGen)
add_lld_library(lldDriver
CoreDriver.cpp
DarwinLdDriver.cpp
Driver.cpp
GnuLdDriver.cpp
WinLinkDriver.cpp
UniversalDriver.cpp
)
add_dependencies(lldDriver DriverOptionsTableGen)
target_link_libraries(lldDriver
lldPasses
lldMachO
lldPECOFF
lldELF
lldCore
lldNative
lldReaderWriter
lldYAML
LLVMObject
LLVMOption
LLVMSupport
)

View File

@@ -1,159 +0,0 @@
//===- lib/Driver/CoreDriver.cpp ------------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Driver/CoreInputGraph.h"
#include "lld/ReaderWriter/CoreLinkingContext.h"
#include "lld/ReaderWriter/Reader.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
using namespace lld;
namespace {
// Create enum with OPT_xxx values for each option in DarwinOptions.td
enum {
OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, META) \
OPT_##ID,
#include "CoreOptions.inc"
#undef OPTION
};
// Create prefix string literals used in CoreOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "CoreOptions.inc"
#undef PREFIX
// Create table mapping all options defined in CoreOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "CoreOptions.inc"
#undef OPTION
};
// Create OptTable class for parsing actual command line arguments
class CoreOptTable : public llvm::opt::OptTable {
public:
CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};
} // namespace anonymous
namespace lld {
bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) {
CoreLinkingContext info;
if (!parse(argc, argv, info))
return false;
return Driver::link(info);
}
bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
raw_ostream &diagnostics) {
// Parse command line options using CoreOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
CoreOptTable table;
unsigned missingIndex;
unsigned missingCount;
parsedArgs.reset(
table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
diagnostics << "error: missing arg value for '"
<< parsedArgs->getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
std::unique_ptr<InputGraph> inputGraph(new InputGraph());
// Set default options
ctx.setOutputPath("-");
ctx.setDeadStripping(false);
ctx.setGlobalsAreDeadStripRoots(false);
ctx.setPrintRemainingUndefines(false);
ctx.setAllowRemainingUndefines(true);
ctx.setSearchArchivesToOverrideTentativeDefinitions(false);
// Process all the arguments and create Input Elements
for (auto inputArg : *parsedArgs) {
switch (inputArg->getOption().getID()) {
case OPT_mllvm:
ctx.appendLLVMOption(inputArg->getValue());
break;
case OPT_entry:
ctx.setEntrySymbolName(inputArg->getValue());
break;
case OPT_output:
ctx.setOutputPath(inputArg->getValue());
break;
case OPT_dead_strip:
ctx.setDeadStripping(true);
break;
case OPT_keep_globals:
ctx.setGlobalsAreDeadStripRoots(true);
break;
case OPT_undefines_are_errors:
ctx.setPrintRemainingUndefines(true);
ctx.setAllowRemainingUndefines(false);
break;
case OPT_commons_search_archives:
ctx.setSearchArchivesToOverrideTentativeDefinitions(true);
break;
case OPT_add_pass:
ctx.addPassNamed(inputArg->getValue());
break;
case OPT_INPUT:
inputGraph->addInputElement(std::unique_ptr<InputElement>(
new COREFileNode(ctx, inputArg->getValue())));
break;
default:
break;
}
}
if (!inputGraph->size()) {
diagnostics << "No input files\n";
return false;
}
ctx.setInputGraph(std::move(inputGraph));
// Validate the combination of options used.
return ctx.validate(diagnostics);
}
} // namespace lld

View File

@@ -1,15 +0,0 @@
include "llvm/Option/OptParser.td"
def output : Separate<["-"], "o">;
def entry : Separate<["-"], "e">;
def dead_strip : Flag<["--"], "dead-strip">;
def undefines_are_errors : Flag<["--"], "undefines-are-errors">;
def keep_globals : Flag<["--"], "keep-globals">;
def commons_search_archives : Flag<["--"], "commons-search-archives">;
def add_pass : Separate<["--"], "add-pass">;
def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;

View File

@@ -1,267 +0,0 @@
//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instance of the Driver for darwin's ld.
///
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Driver/DarwinInputGraph.h"
#include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
namespace {
// Create enum with OPT_xxx values for each option in DarwinLdOptions.td
enum {
OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, META) \
OPT_##ID,
#include "DarwinLdOptions.inc"
#undef OPTION
};
// Create prefix string literals used in DarwinLdOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "DarwinLdOptions.inc"
#undef PREFIX
// Create table mapping all options defined in DarwinLdOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "DarwinLdOptions.inc"
#undef OPTION
};
// Create OptTable class for parsing actual command line arguments
class DarwinLdOptTable : public llvm::opt::OptTable {
public:
DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};
} // namespace anonymous
namespace lld {
bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
raw_ostream &diagnostics) {
MachOLinkingContext ctx;
if (!parse(argc, argv, ctx, diagnostics))
return false;
if (ctx.doNothing())
return true;
return link(ctx, diagnostics);
}
bool DarwinLdDriver::parse(int argc, const char *argv[],
MachOLinkingContext &ctx, raw_ostream &diagnostics) {
// Parse command line options using DarwinLdOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
DarwinLdOptTable table;
unsigned missingIndex;
unsigned missingCount;
bool globalWholeArchive = false;
parsedArgs.reset(
table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
diagnostics << "error: missing arg value for '"
<< parsedArgs->getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
ie = parsedArgs->filtered_end(); it != ie; ++it) {
diagnostics << "warning: ignoring unknown argument: "
<< (*it)->getAsString(*parsedArgs) << "\n";
}
// Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable,
OPT_bundle, OPT_static, OPT_preload)) {
switch (kind->getOption().getID()) {
case OPT_dylib:
ctx.setOutputFileType(llvm::MachO::MH_DYLIB);
ctx.setGlobalsAreDeadStripRoots(true);
break;
case OPT_relocatable:
ctx.setPrintRemainingUndefines(false);
ctx.setAllowRemainingUndefines(true);
ctx.setOutputFileType(llvm::MachO::MH_OBJECT);
break;
case OPT_bundle:
ctx.setOutputFileType(llvm::MachO::MH_BUNDLE);
break;
case OPT_static:
ctx.setOutputFileType(llvm::MachO::MH_EXECUTE);
break;
case OPT_preload:
ctx.setOutputFileType(llvm::MachO::MH_PRELOAD);
break;
}
}
// Handle -e xxx
if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
ctx.setEntrySymbolName(entry->getValue());
// Handle -o xxx
if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
ctx.setOutputPath(outpath->getValue());
// Handle -dead_strip
if (parsedArgs->getLastArg(OPT_dead_strip))
ctx.setDeadStripping(true);
// Handle -all_load
if (parsedArgs->getLastArg(OPT_all_load))
globalWholeArchive = true;
// Handle -install_name
if (llvm::opt::Arg *installName = parsedArgs->getLastArg(OPT_install_name))
ctx.setInstallName(installName->getValue());
// Handle -mark_dead_strippable_dylib
if (parsedArgs->getLastArg(OPT_mark_dead_strippable_dylib))
ctx.setDeadStrippableDylib(true);
// Handle -compatibility_version and -current_version
if (llvm::opt::Arg *vers =
parsedArgs->getLastArg(OPT_compatibility_version)) {
if (ctx.outputFileType() != llvm::MachO::MH_DYLIB) {
diagnostics
<< "error: -compatibility_version can only be used with -dylib\n";
return false;
}
uint32_t parsedVers;
if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
diagnostics << "error: -compatibility_version value is malformed\n";
return false;
}
ctx.setCompatibilityVersion(parsedVers);
}
if (llvm::opt::Arg *vers = parsedArgs->getLastArg(OPT_current_version)) {
if (ctx.outputFileType() != llvm::MachO::MH_DYLIB) {
diagnostics << "-current_version can only be used with -dylib\n";
return false;
}
uint32_t parsedVers;
if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) {
diagnostics << "error: -current_version value is malformed\n";
return false;
}
ctx.setCurrentVersion(parsedVers);
}
// Handle -bundle_loader
if (llvm::opt::Arg *loader = parsedArgs->getLastArg(OPT_bundle_loader))
ctx.setBundleLoader(loader->getValue());
// Handle -arch xxx
if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) {
ctx.setArch(MachOLinkingContext::archFromName(archStr->getValue()));
if (ctx.arch() == MachOLinkingContext::arch_unknown) {
diagnostics << "error: unknown arch named '" << archStr->getValue()
<< "'\n";
return false;
}
}
// Handle -macosx_version_min or -ios_version_min
if (llvm::opt::Arg *minOS = parsedArgs->getLastArg(
OPT_macosx_version_min,
OPT_ios_version_min,
OPT_ios_simulator_version_min)) {
switch (minOS->getOption().getID()) {
case OPT_macosx_version_min:
if (ctx.setOS(MachOLinkingContext::OS::macOSX, minOS->getValue())) {
diagnostics << "error: malformed macosx_version_min value\n";
return false;
}
break;
case OPT_ios_version_min:
if (ctx.setOS(MachOLinkingContext::OS::iOS, minOS->getValue())) {
diagnostics << "error: malformed ios_version_min value\n";
return false;
}
break;
case OPT_ios_simulator_version_min:
if (ctx.setOS(MachOLinkingContext::OS::iOS_simulator,
minOS->getValue())) {
diagnostics << "error: malformed ios_simulator_version_min value\n";
return false;
}
break;
}
}
else {
// No min-os version on command line, check environment variables
}
// Handle -help
if (parsedArgs->getLastArg(OPT_help)) {
table.PrintHelp(llvm::outs(), argv[0], "LLVM Darwin Linker", false);
// If only -help on command line, don't try to do any linking
if (argc == 2) {
ctx.setDoNothing(true);
return true;
}
}
// Handle -mllvm
for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
ie = parsedArgs->filtered_end();
it != ie; ++it) {
ctx.appendLLVMOption((*it)->getValue());
}
std::unique_ptr<InputGraph> inputGraph(new InputGraph());
// Handle input files
for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
ie = parsedArgs->filtered_end();
it != ie; ++it) {
inputGraph->addInputElement(std::unique_ptr<InputElement>(
new MachOFileNode(ctx, (*it)->getValue(), globalWholeArchive)));
}
if (!inputGraph->size()) {
diagnostics << "No input files\n";
return false;
}
ctx.setInputGraph(std::move(inputGraph));
// Validate the combination of options used.
return ctx.validate(diagnostics);
}
} // namespace lld

View File

@@ -1,79 +0,0 @@
include "llvm/Option/OptParser.td"
// output kinds
def grp_kind : OptionGroup<"outs">, HelpText<"OUTPUT KIND">;
def relocatable : Flag<["-"], "r">,
HelpText<"Create relocatable object file">, Group<grp_kind>;
def static : Flag<["-"], "static">,
HelpText<"Create static executable">, Group<grp_kind>;
def dynamic : Flag<["-"], "dynamic">,
HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
def dylib : Flag<["-"], "dylib">,
HelpText<"Create dynamic library">, Group<grp_kind>;
def bundle : Flag<["-"], "bundle">,
HelpText<"Create dynamic bundle">, Group<grp_kind>;
def execute : Flag<["-"], "execute">,
HelpText<"Create main executable (default)">, Group<grp_kind>;
def preload : Flag<["-"], "preload">,
HelpText<"Create preload">, Group<grp_kind>;
// optimizations
def grp_opts : OptionGroup<"opts">, HelpText<"OPTIMIZATIONS">;
def dead_strip : Flag<["-"], "dead_strip">,
HelpText<"Remove unreference code and data">, Group<grp_opts>;
def macosx_version_min : Separate<["-"], "macosx_version_min">,
HelpText<"Minimum Mac OS X version">, Group<grp_opts>;
def ios_version_min : Separate<["-"], "ios_version_min">,
HelpText<"Minimum iOS version">, Group<grp_opts>;
def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
HelpText<"Minimum iOS simulator version">, Group<grp_opts>;
def mllvm : Separate<["-"], "mllvm">,
HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
// main executable options
def grp_main : OptionGroup<"opts">, HelpText<"MAIN EXECUTABLE OPTIONS">;
def entry : Separate<["-"], "e">, HelpText<"entry symbol name">,Group<grp_main>;
// dylib executable options
def grp_dylib : OptionGroup<"opts">, HelpText<"DYLIB EXECUTABLE OPTIONS">;
def install_name : Separate<["-"], "install_name">,
HelpText<"The dylib's install name">, Group<grp_dylib>;
def mark_dead_strippable_dylib : Flag<["-"], "mark_dead_strippable_dylib">,
HelpText<"Marks the dylib as having no side effects during initialization">,
Group<grp_dylib>;
def compatibility_version : Separate<["-"], "compatibility_version">,
HelpText<"The dylib's compatibility version">, Group<grp_dylib>;
def current_version : Separate<["-"], "current_version">,
HelpText<"The dylib's current version">, Group<grp_dylib>;
// dylib executable options - compatibility aliases
def dylib_install_name : Separate<["-"], "dylib_install_name">,
Alias<install_name>;
def dylib_compatibility_version :
Separate<["-"], "dylib_compatibility_version">,
Alias<compatibility_version>;
def dylib_current_version : Separate<["-"], "dylib_current_version">,
Alias<current_version>;
// bundle executable options
def grp_bundle : OptionGroup<"opts">, HelpText<"BUNDLE EXECUTABLE OPTIONS">;
def bundle_loader : Separate<["-"], "bundle_loader">,
HelpText<"The executable that will be loading this Mach-O bundle">,
Group<grp_bundle>;
// library options
def grp_libs : OptionGroup<"libs">, HelpText<"LIBRARY OPTIONS">;
def L : Joined<["-"], "L">,
HelpText<"Add directory to library search path">, Group<grp_libs>;
def all_load : Flag<["-"], "all_load">,
HelpText<"Forces all members of all static libraries to be loaded">,
Group<grp_libs>;
// general options
def output : Separate<["-"], "o">, HelpText<"Output file path">;
def arch : Separate<["-"], "arch">, HelpText<"Architecture to link">;
// extras
def help : Flag<["-"], "help">;

View File

@@ -1,137 +0,0 @@
//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Core/LLVM.h"
#include "lld/Core/Instrumentation.h"
#include "lld/Core/PassManager.h"
#include "lld/Core/Parallel.h"
#include "lld/Core/Resolver.h"
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
#include "lld/Passes/RoundTripNativePass.h"
#include "lld/Passes/RoundTripYAMLPass.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
namespace lld {
/// This is where the link is actually performed.
bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
// Honor -mllvm
if (!context.llvmOptions().empty()) {
unsigned numArgs = context.llvmOptions().size();
const char **args = new const char *[numArgs + 2];
args[0] = "lld (LLVM option parsing)";
for (unsigned i = 0; i != numArgs; ++i)
args[i + 1] = context.llvmOptions()[i];
args[numArgs + 1] = 0;
llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
}
InputGraph &inputGraph = context.inputGraph();
if (!inputGraph.size())
return false;
bool fail = false;
// Read inputs
ScopedTask readTask(getDefaultDomain(), "Read Args");
TaskGroup tg;
std::mutex diagnosticsMutex;
for (auto &ie : inputGraph.inputElements()) {
tg.spawn([&] {
// Writes to the same output stream is not guaranteed to be thread-safe.
// We buffer the diagnostics output to a separate string-backed output
// stream, acquire the lock, and then print it out.
std::string buf;
llvm::raw_string_ostream stream(buf);
if (error_code ec = ie->parse(context, stream)) {
FileNode *fileNode = dyn_cast<FileNode>(ie.get());
stream << fileNode->errStr(ec) << "\n";
fail = true;
}
stream.flush();
if (!buf.empty()) {
std::lock_guard<std::mutex> lock(diagnosticsMutex);
diagnostics << buf;
}
});
}
tg.sync();
readTask.end();
if (fail)
return false;
std::unique_ptr<SimpleFileNode> fileNode(
new SimpleFileNode("Internal Files"));
InputGraph::FileVectorT internalFiles;
context.createInternalFiles(internalFiles);
if (internalFiles.size())
fileNode->appendInputFiles(std::move(internalFiles));
// Give target a chance to add files.
InputGraph::FileVectorT implicitFiles;
context.createImplicitFiles(implicitFiles);
if (implicitFiles.size())
fileNode->appendInputFiles(std::move(implicitFiles));
context.inputGraph().insertOneElementAt(std::move(fileNode),
InputGraph::Position::BEGIN);
context.inputGraph().assignOrdinals();
context.inputGraph().doPostProcess();
// Do core linking.
ScopedTask resolveTask(getDefaultDomain(), "Resolve");
Resolver resolver(context);
if (!resolver.resolve())
return false;
std::unique_ptr<MutableFile> merged = resolver.resultFile();
resolveTask.end();
// Run passes on linked atoms.
ScopedTask passTask(getDefaultDomain(), "Passes");
PassManager pm;
context.addPasses(pm);
#ifndef NDEBUG
pm.add(std::unique_ptr<Pass>(new RoundTripYAMLPass(context)));
pm.add(std::unique_ptr<Pass>(new RoundTripNativePass(context)));
#endif
pm.runOnFile(merged);
passTask.end();
// Give linked atoms to Writer to generate output file.
ScopedTask writeTask(getDefaultDomain(), "Write");
if (error_code ec = context.writeFile(*merged)) {
diagnostics << "Failed to write file '" << context.outputPath()
<< "': " << ec.message() << "\n";
return false;
}
return true;
}
} // namespace

View File

@@ -1,362 +0,0 @@
//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instance of the Driver for GNU's ld.
///
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Driver/GnuLdInputGraph.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"
using namespace lld;
namespace {
// Create enum with OPT_xxx values for each option in GnuLdOptions.td
enum {
OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, META) \
OPT_##ID,
#include "GnuLdOptions.inc"
#undef OPTION
};
// Create prefix string literals used in GnuLdOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "GnuLdOptions.inc"
#undef PREFIX
// Create table mapping all options defined in GnuLdOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "GnuLdOptions.inc"
#undef OPTION
};
// Create OptTable class for parsing actual command line arguments
class GnuLdOptTable : public llvm::opt::OptTable {
public:
GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
};
} // namespace
llvm::ErrorOr<StringRef> ELFFileNode::getPath(const LinkingContext &) const {
if (!_isDashlPrefix)
return _path;
return _elfLinkingContext.searchLibrary(_path, _libraryPaths);
}
std::string ELFFileNode::errStr(error_code errc) {
if (errc == llvm::errc::no_such_file_or_directory) {
if (_isDashlPrefix)
return (Twine("Unable to find library -l") + _path).str();
return (Twine("Unable to find file ") + _path).str();
}
return FileNode::errStr(errc);
}
bool GnuLdDriver::linkELF(int argc, const char *argv[],
raw_ostream &diagnostics) {
std::unique_ptr<ELFLinkingContext> options;
if (!parse(argc, argv, options, diagnostics))
return false;
if (!options)
return true;
return link(*options, diagnostics);
}
bool GnuLdDriver::parse(int argc, const char *argv[],
std::unique_ptr<ELFLinkingContext> &context,
raw_ostream &diagnostics) {
// Parse command line options using GnuLdOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
GnuLdOptTable table;
unsigned missingIndex;
unsigned missingCount;
parsedArgs.reset(
table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
diagnostics << "error: missing arg value for '"
<< parsedArgs->getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
// Handle --help
if (parsedArgs->getLastArg(OPT_help)) {
table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
return true;
}
// Use -target or use default target triple to instantiate LinkingContext
llvm::Triple triple;
if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target))
triple = llvm::Triple(trip->getValue());
else
triple = getDefaultTarget(argv[0]);
std::unique_ptr<ELFLinkingContext> ctx(ELFLinkingContext::create(triple));
if (!ctx) {
diagnostics << "unknown target triple\n";
return false;
}
std::unique_ptr<InputGraph> inputGraph(new InputGraph());
std::stack<InputElement *> controlNodeStack;
// Positional options for an Input File
std::vector<StringRef> searchPath;
bool isWholeArchive = false;
bool asNeeded = false;
bool _outputOptionSet = false;
// Create a dynamic executable by default
ctx->setOutputELFType(llvm::ELF::ET_EXEC);
ctx->setIsStaticExecutable(false);
ctx->setAllowShlibUndefines(false);
ctx->setUseShlibUndefines(true);
int index = 0;
// Process all the arguments and create Input Elements
for (auto inputArg : *parsedArgs) {
switch (inputArg->getOption().getID()) {
case OPT_mllvm:
ctx->appendLLVMOption(inputArg->getValue());
break;
case OPT_relocatable:
ctx->setOutputELFType(llvm::ELF::ET_REL);
ctx->setPrintRemainingUndefines(false);
ctx->setAllowRemainingUndefines(true);
break;
case OPT_static:
ctx->setOutputELFType(llvm::ELF::ET_EXEC);
ctx->setIsStaticExecutable(true);
break;
case OPT_shared:
ctx->setOutputELFType(llvm::ELF::ET_DYN);
ctx->setAllowShlibUndefines(true);
ctx->setUseShlibUndefines(false);
break;
case OPT_e:
ctx->setEntrySymbolName(inputArg->getValue());
break;
case OPT_output:
_outputOptionSet = true;
ctx->setOutputPath(inputArg->getValue());
break;
case OPT_noinhibit_exec:
ctx->setAllowRemainingUndefines(true);
break;
case OPT_merge_strings:
ctx->setMergeCommonStrings(true);
break;
case OPT_t:
ctx->setLogInputFiles(true);
break;
case OPT_no_allow_shlib_undefs:
ctx->setAllowShlibUndefines(false);
break;
case OPT_allow_shlib_undefs:
ctx->setAllowShlibUndefines(true);
break;
case OPT_use_shlib_undefs:
ctx->setUseShlibUndefines(true);
break;
case OPT_dynamic_linker:
ctx->setInterpreter(inputArg->getValue());
break;
case OPT_nmagic:
ctx->setOutputMagic(ELFLinkingContext::OutputMagic::NMAGIC);
ctx->setIsStaticExecutable(true);
break;
case OPT_omagic:
ctx->setOutputMagic(ELFLinkingContext::OutputMagic::OMAGIC);
ctx->setIsStaticExecutable(true);
break;
case OPT_no_omagic:
ctx->setOutputMagic(ELFLinkingContext::OutputMagic::DEFAULT);
ctx->setNoAllowDynamicLibraries();
break;
case OPT_u:
ctx->addInitialUndefinedSymbol(inputArg->getValue());
break;
case OPT_init:
ctx->addInitFunction(inputArg->getValue());
break;
case OPT_fini:
ctx->addFiniFunction(inputArg->getValue());
break;
case OPT_output_filetype:
ctx->setOutputFileType(inputArg->getValue());
break;
case OPT_no_whole_archive:
isWholeArchive = false;
break;
case OPT_whole_archive:
isWholeArchive = true;
break;
case OPT_as_needed:
asNeeded = true;
break;
case OPT_no_as_needed:
asNeeded = false;
break;
case OPT_L:
searchPath.push_back(inputArg->getValue());
break;
case OPT_start_group: {
std::unique_ptr<InputElement> controlStart(new ELFGroup(*ctx, index++));
controlNodeStack.push(controlStart.get());
dyn_cast<ControlNode>(controlNodeStack.top())->processControlEnter();
inputGraph->addInputElement(std::move(controlStart));
break;
}
case OPT_end_group:
dyn_cast<ControlNode>(controlNodeStack.top())->processControlExit();
controlNodeStack.pop();
break;
case OPT_INPUT:
case OPT_l: {
std::unique_ptr<InputElement> inputFile(new ELFFileNode(
*ctx, inputArg->getValue(), searchPath, index++, isWholeArchive,
asNeeded, inputArg->getOption().getID() == OPT_l));
if (controlNodeStack.empty())
inputGraph->addInputElement(std::move(inputFile));
else
dyn_cast<ControlNode>(controlNodeStack.top())
->processInputElement(std::move(inputFile));
break;
}
case OPT_rpath: {
SmallVector<StringRef, 2> rpaths;
StringRef(inputArg->getValue()).split(rpaths, ":");
for (auto path : rpaths)
ctx->addRpath(path);
break;
}
case OPT_rpath_link: {
SmallVector<StringRef, 2> rpaths;
StringRef(inputArg->getValue()).split(rpaths, ":");
for (auto path : rpaths)
ctx->addRpathLink(path);
break;
}
case OPT_sysroot:
ctx->setSysroot(inputArg->getValue());
break;
case OPT_soname:
ctx->setSharedObjectName(inputArg->getValue());
break;
default:
break;
} // end switch on option ID
} // end for
if (!inputGraph->size()) {
diagnostics << "No input files\n";
return false;
}
// Set default output file name if the output file was not
// specified.
if (!_outputOptionSet) {
switch (ctx->outputFileType()) {
case LinkingContext::OutputFileType::YAML:
ctx->setOutputPath("-");
break;
case LinkingContext::OutputFileType::Native:
ctx->setOutputPath("a.native");
break;
default:
ctx->setOutputPath("a.out");
break;
}
}
if (ctx->outputFileType() == LinkingContext::OutputFileType::YAML)
inputGraph->dump(diagnostics);
// Validate the combination of options used.
if (!ctx->validate(diagnostics))
return false;
ctx->setInputGraph(std::move(inputGraph));
context.swap(ctx);
return true;
}
/// Get the default target triple based on either the program name
/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
SmallVector<StringRef, 4> components;
llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
// If has enough parts to be start with a triple.
if (components.size() >= 4) {
llvm::Triple triple(components[0], components[1], components[2],
components[3]);
// If first component looks like an arch.
if (triple.getArch() != llvm::Triple::UnknownArch)
return triple;
}
// Fallback to use whatever default triple llvm was configured for.
return llvm::Triple(llvm::sys::getDefaultTargetTriple());
}

View File

@@ -1,240 +0,0 @@
include "llvm/Option/OptParser.td"
//===----------------------------------------------------------------------===//
/// Utility Functions
//===----------------------------------------------------------------------===//
// Single and multiple dash options combined
multiclass smDash<string opt1, string opt2, string help> {
// Option
def "" : Separate<["-"], opt1>, HelpText<help>;
def opt1_eq : Separate<["-"], opt1#"=">,
Alias<!cast<Option>(opt1)>;
// Compatibility aliases
def opt2_dashdash : Separate<["--"], opt2>,
Alias<!cast<Option>(opt1)>;
def opt2_dashdash_eq : Separate<["--"], opt2#"=">,
Alias<!cast<Option>(opt1)>;
}
// Support -<option>,-<option>=
multiclass dashEq<string opt1, string opt2, string help> {
// Option
def "" : Separate<["-"], opt1>, HelpText<help>;
// Compatibility aliases
def opt2_eq : Separate<["-"], opt2#"=">,
Alias<!cast<Option>(opt1)>;
}
//===----------------------------------------------------------------------===//
/// Output Kinds
//===----------------------------------------------------------------------===//
def grp_kind : OptionGroup<"outs">,
HelpText<"OUTPUT KIND">;
def relocatable : Flag<["-"], "r">,
HelpText<"Create relocatable object file">, Group<grp_kind>;
def static : Flag<["-"], "static">,
HelpText<"Create static executable">, Group<grp_kind>;
def dynamic : Flag<["-"], "dynamic">,
HelpText<"Create dynamic executable (default)">,Group<grp_kind>;
def shared : Flag<["-"], "shared">,
HelpText<"Create dynamic library">, Group<grp_kind>;
// output kinds - compatibility aliases
def Bstatic : Flag<["-"], "Bstatic">, Alias<static>;
def Bshareable : Flag<["-"], "Bshareable">, Alias<shared>;
//===----------------------------------------------------------------------===//
/// General Options
//===----------------------------------------------------------------------===//
def grp_general : OptionGroup<"opts">,
HelpText<"GENERAL OPTIONS">;
def target : Separate<["-"], "target">, MetaVarName<"<triple>">,
HelpText<"Target triple to link for">,
Group<grp_general>;
def output : Separate<["-"], "o">, MetaVarName<"<path>">,
HelpText<"Path to file to write output">,
Group<grp_general>;
def m : Separate<["-"], "m">,
HelpText<"Emulate the emulation linker">,
Group<grp_general>;
def build_id : Flag<["--"], "build-id">,
HelpText<"Request creation of \".note.gnu.build-id\" ELF note section">,
Group<grp_general>;
def sysroot : Joined<["--"], "sysroot=">,
HelpText<"Set the system root">,
Group<grp_general>;
//===----------------------------------------------------------------------===//
/// Executable Options
//===----------------------------------------------------------------------===//
def grp_main : OptionGroup<"opts">,
HelpText<"EXECUTABLE OPTIONS">;
def L : Joined<["-"], "L">, MetaVarName<"<dir>">,
HelpText<"Directory to search for libraries">,
Group<grp_main>;
def l : Joined<["-"], "l">, MetaVarName<"<libName>">,
HelpText<"Root name of library to use">,
Group<grp_main>;
def noinhibit_exec : Flag<["--"], "noinhibit-exec">,
HelpText<"Retain the executable output file whenever"
" it is still usable">,
Group<grp_main>;
defm e : smDash<"e", "entry",
"Name of entry point symbol">,
Group<grp_main>;
defm init: dashEq<"init", "init",
"Specify an initializer function">,
Group<grp_main>;
defm fini: dashEq<"fini", "fini",
"Specify a finalizer function">,
Group<grp_main>;
def whole_archive: Flag<["--"], "whole-archive">,
HelpText<"Force load of all members in a static library">,
Group<grp_main>;
def no_whole_archive: Flag<["--"], "no-whole-archive">,
HelpText<"Restores the default behavior of loading archive members">,
Group<grp_main>;
//===----------------------------------------------------------------------===//
/// Static Executable Options
//===----------------------------------------------------------------------===//
def grp_staticexec : OptionGroup<"opts">,
HelpText<"STATIC EXECUTABLE OPTIONS">;
def nmagic : Flag<["--"], "nmagic">,
HelpText<"Turn off page alignment of sections,"
" and disable linking against shared libraries">,
Group<grp_staticexec>;
def omagic : Flag<["--"], "omagic">,
HelpText<"Set the text and data sections to be readable and writable."
" Also, do not page-align the data segment, and"
" disable linking against shared libraries.">,
Group<grp_staticexec>;
def no_omagic : Flag<["--"], "no-omagic">,
HelpText<"This option negates most of the effects of the -N option."
"Disable linking with shared libraries">,
Group<grp_staticexec>;
// Compatible Aliases
def nmagic_alias : Flag<["-"], "n">,
Alias<nmagic>;
def omagic_alias : Flag<["-"], "N">,
Alias<omagic>;
//===----------------------------------------------------------------------===//
/// Dynamic Library/Executable Options
//===----------------------------------------------------------------------===//
def grp_dynlibexec : OptionGroup<"opts">,
HelpText<"DYNAMIC LIBRARY/EXECUTABLE OPTIONS">;
def dynamic_linker : Joined<["--"], "dynamic-linker=">,
HelpText<"Set the path to the dynamic linker">, Group<grp_dynlibexec>;
// Executable options - compatibility aliases
def dynamic_linker_alias : Separate<["-"], "dynamic-linker">,
Alias<dynamic_linker>;
def rpath : Separate<["-"], "rpath">,
HelpText<"Add a directory to the runtime library search path">,
Group<grp_dynlibexec>;
def rpath_link : Separate<["-"], "rpath-link">,
HelpText<"Specifies the first set of directories to search">,
Group<grp_dynlibexec>;
//===----------------------------------------------------------------------===//
/// Dynamic Library Options
//===----------------------------------------------------------------------===//
def grp_dynlib : OptionGroup<"opts">,
HelpText<"DYNAMIC LIBRARY OPTIONS">;
def soname : Separate<["-"], "soname">,
HelpText<"Set the internal DT_SONAME field to the specified name">,
Group<grp_dynlib>;
//===----------------------------------------------------------------------===//
/// Resolver Options
//===----------------------------------------------------------------------===//
def grp_resolveropt : OptionGroup<"opts">,
HelpText<"SYMBOL RESOLUTION OPTIONS">;
defm u : smDash<"u", "undefined",
"Force symbol to be entered in the output file"
" as an undefined symbol">,
Group<grp_resolveropt>;
def start_group : Flag<["--"], "start-group">,
HelpText<"Start a group">,
Group<grp_resolveropt>;
def alias_start_group: Flag<["-"], "(">,
Alias<start_group>;
def end_group : Flag<["--"], "end-group">,
HelpText<"End a group">,
Group<grp_resolveropt>;
def alias_end_group: Flag<["-"], ")">,
Alias<end_group>;
def as_needed : Flag<["--"], "as-needed">,
HelpText<"This option affects ELF DT_NEEDED tags for "
"dynamic libraries mentioned on the command line">,
Group<grp_resolveropt>;
def no_as_needed : Flag<["--"], "no-as-needed">,
HelpText<"This option restores the default behavior"
" of adding DT_NEEDED entries">,
Group<grp_resolveropt>;
def no_allow_shlib_undefs : Flag<["--"], "no-allow-shlib-undefined">,
HelpText<"Do not allow undefined symbols from dynamic"
" library when creating executables">,
Group<grp_resolveropt>;
def allow_shlib_undefs : Flag<["--"], "allow-shlib-undefined">,
HelpText<"Allow undefined symbols from dynamic"
" library when creating executables">,
Group<grp_resolveropt>;
def use_shlib_undefs: Flag<["--"], "use-shlib-undefines">,
HelpText<"Resolve undefined symbols from dynamic libraries">,
Group<grp_resolveropt>;
//===----------------------------------------------------------------------===//
/// Custom Options
//===----------------------------------------------------------------------===//
def grp_customopts : OptionGroup<"opts">,
HelpText<"CUSTOM OPTIONS">;
def z : Separate<["-"], "z">,
HelpText<"Linker Option extensions">,
Group<grp_customopts>;
//===----------------------------------------------------------------------===//
/// Optimization Options
//===----------------------------------------------------------------------===//
def grp_opts : OptionGroup<"opts">,
HelpText<"OPTIMIZATIONS">;
def mllvm : Separate<["-"], "mllvm">,
HelpText<"Options to pass to LLVM during LTO">, Group<grp_opts>;
def hash_style : Joined <["--"], "hash-style=">,
HelpText<"Set the type of linker's hash table(s)">,
Group<grp_opts>;
def merge_strings : Flag<["--"], "merge-strings">,
HelpText<"Merge common strings across mergeable sections">,
Group<grp_opts>;
def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
HelpText<"Request creation of .eh_frame_hdr section and ELF "
" PT_GNU_EH_FRAME segment header">,
Group<grp_opts>;
//===----------------------------------------------------------------------===//
/// Tracing Options
//===----------------------------------------------------------------------===//
def grp_tracingopts : OptionGroup<"opts">,
HelpText<"TRACING OPTIONS">;
def t : Flag<["-"], "t">,
HelpText<"Print the names of the input files as ld processes them">,
Group<grp_tracingopts>;
//===----------------------------------------------------------------------===//
/// Extensions
//===----------------------------------------------------------------------===//
def grp_extns : OptionGroup<"opts">,
HelpText<"Extensions">;
def output_filetype: Separate<["--"], "output-filetype">,
HelpText<"Specify what type of output file that lld creates, YAML/Native">,
Group<grp_extns>;
def alias_output_filetype: Joined<["--"], "output-filetype=">,
Alias<output_filetype>;
//===----------------------------------------------------------------------===//
/// Help
//===----------------------------------------------------------------------===//
def help : Flag<["--"], "help">,
HelpText<"Display this help message">;

View File

@@ -1,183 +0,0 @@
//===- lib/Driver/UniversalDriver.cpp -------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Driver for "universal" lld tool which can mimic any linker command line
/// parsing once it figures out which command line flavor to use.
///
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
#include "lld/Core/LLVM.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
using namespace lld;
namespace {
// Create enum with OPT_xxx values for each option in GnuLdOptions.td
enum {
OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, META) \
OPT_##ID,
#include "UniversalDriverOptions.inc"
#undef OPTION
};
// Create prefix string literals used in GnuLdOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "UniversalDriverOptions.inc"
#undef PREFIX
// Create table mapping all options defined in GnuLdOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ \
PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \
} \
,
#include "UniversalDriverOptions.inc"
#undef OPTION
};
// Create OptTable class for parsing actual command line arguments
class UniversalDriverOptTable : public llvm::opt::OptTable {
public:
UniversalDriverOptTable()
: OptTable(infoTable, llvm::array_lengthof(infoTable)) {}
};
enum class Flavor {
invalid,
gnu_ld, // -flavor gnu
win_link, // -flavor link
darwin_ld, // -flavor darwin
core // -flavor core OR -core
};
Flavor strToFlavor(StringRef str) {
return llvm::StringSwitch<Flavor>(str)
.Case("gnu", Flavor::gnu_ld)
.Case("link", Flavor::win_link)
.Case("darwin", Flavor::darwin_ld)
.Case("core", Flavor::core)
.Case("ld", Flavor::gnu_ld) // deprecated
.Default(Flavor::invalid);
}
struct ProgramNameParts {
StringRef _target;
StringRef _flavor;
};
ProgramNameParts parseProgramName(StringRef programName) {
SmallVector<StringRef, 3> components;
llvm::SplitString(programName, components, "-");
ProgramNameParts ret;
using std::begin;
using std::end;
// Erase any lld components.
components.erase(std::remove(components.begin(), components.end(), "lld"),
components.end());
// Find the flavor component.
auto flIter = std::find_if(components.begin(), components.end(),
[](StringRef str)->bool {
return strToFlavor(str) != Flavor::invalid;
});
if (flIter != components.end()) {
ret._flavor = *flIter;
components.erase(flIter);
}
// Any remaining component must be the target.
if (components.size() == 1)
ret._target = components[0];
return ret;
}
} // namespace
namespace lld {
bool UniversalDriver::link(int argc, const char *argv[],
raw_ostream &diagnostics) {
// Parse command line options using GnuLdOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
UniversalDriverOptTable table;
unsigned missingIndex;
unsigned missingCount;
// Program name
StringRef programName = llvm::sys::path::stem(argv[0]);
parsedArgs.reset(
table.ParseArgs(&argv[1], &argv[argc], missingIndex, missingCount));
if (missingCount) {
diagnostics << "error: missing arg value for '"
<< parsedArgs->getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return false;
}
// Handle --help
if (parsedArgs->getLastArg(OPT_help)) {
table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
return true;
}
Flavor flavor;
if (parsedArgs->getLastArg(OPT_core)) {
flavor = Flavor::core;
argv++;
argc--;
} else if (llvm::opt::Arg *argFlavor = parsedArgs->getLastArg(OPT_flavor)) {
flavor = strToFlavor(argFlavor->getValue());
argv += 2;
argc -= 2;
} else
flavor = strToFlavor(parseProgramName(programName)._flavor);
std::vector<const char *> args(argv, argv + argc);
// Switch to appropriate driver.
switch (flavor) {
case Flavor::gnu_ld:
return GnuLdDriver::linkELF(args.size(), args.data(), diagnostics);
case Flavor::darwin_ld:
return DarwinLdDriver::linkMachO(args.size(), args.data(), diagnostics);
case Flavor::win_link:
return WinLinkDriver::linkPECOFF(args.size(), args.data(), diagnostics);
case Flavor::core:
return CoreDriver::link(args.size(), args.data(), diagnostics);
case Flavor::invalid:
diagnostics << "Select the appropriate flavor\n";
table.PrintHelp(llvm::outs(), programName.data(), "LLVM Linker", false);
return false;
}
llvm_unreachable("Unrecognised flavor");
}
} // end namespace lld

View File

@@ -1,16 +0,0 @@
include "llvm/Option/OptParser.td"
// Select an optional flavor
def flavor: Separate<["-"], "flavor">,
HelpText<"Flavor for linking, options are gnu/darwin/link">;
// Select the core flavor
def core : Flag<["-"], "core">,
HelpText<"CORE linking">;
def target: Separate<["-"], "target">,
HelpText<"Select the target">;
// Help message
def help : Flag<["-"], "help">,
HelpText<"Display this help message">;

View File

@@ -1,976 +0,0 @@
//===- lib/Driver/WinLinkDriver.cpp ---------------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// Concrete instance of the Driver for Windows link.exe.
///
//===----------------------------------------------------------------------===//
#include <cctype>
#include <sstream>
#include <map>
#include "lld/Driver/Driver.h"
#include "lld/Driver/WinLinkInputGraph.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
namespace lld {
namespace {
//
// Option definitions
//
// Create enum with OPT_xxx values for each option in WinLinkOptions.td
enum {
OPT_INVALID = 0,
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELP, META) \
OPT_##ID,
#include "WinLinkOptions.inc"
#undef OPTION
};
// Create prefix string literals used in WinLinkOptions.td
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "WinLinkOptions.inc"
#undef PREFIX
// Create table mapping all options defined in WinLinkOptions.td
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "WinLinkOptions.inc"
#undef OPTION
};
// Create OptTable class for parsing actual command line arguments
class WinLinkOptTable : public llvm::opt::OptTable {
public:
// link.exe's command line options are case insensitive, unlike
// other driver's options for Unix.
WinLinkOptTable()
: OptTable(infoTable, llvm::array_lengthof(infoTable),
/* ignoreCase */ true) {}
};
//
// Functions to parse each command line option
//
// Split the given string with spaces.
std::vector<std::string> splitArgList(const std::string &str) {
std::stringstream stream(str);
std::istream_iterator<std::string> begin(stream);
std::istream_iterator<std::string> end;
return std::vector<std::string>(begin, end);
}
// Split the given string with the path separator.
std::vector<StringRef> splitPathList(StringRef str) {
std::vector<StringRef> ret;
while (!str.empty()) {
StringRef path;
llvm::tie(path, str) = str.split(';');
ret.push_back(path);
}
return ret;
}
// Parse an argument for /base, /stack or /heap. The expected string
// is "<integer>[,<integer>]".
bool parseMemoryOption(StringRef arg, uint64_t &reserve, uint64_t &commit) {
StringRef reserveStr, commitStr;
llvm::tie(reserveStr, commitStr) = arg.split(',');
if (reserveStr.getAsInteger(0, reserve))
return false;
if (!commitStr.empty() && commitStr.getAsInteger(0, commit))
return false;
return true;
}
// Parse an argument for /version or /subsystem. The expected string is
// "<integer>[.<integer>]".
bool parseVersion(StringRef arg, uint32_t &major, uint32_t &minor) {
StringRef majorVersion, minorVersion;
llvm::tie(majorVersion, minorVersion) = arg.split('.');
if (minorVersion.empty())
minorVersion = "0";
if (majorVersion.getAsInteger(0, major))
return false;
if (minorVersion.getAsInteger(0, minor))
return false;
return true;
}
// Returns subsystem type for the given string.
llvm::COFF::WindowsSubsystem stringToWinSubsystem(StringRef str) {
return llvm::StringSwitch<llvm::COFF::WindowsSubsystem>(str.lower())
.Case("windows", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI)
.Case("console", llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI)
.Case("boot_application",
llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION)
.Case("efi_application", llvm::COFF::IMAGE_SUBSYSTEM_EFI_APPLICATION)
.Case("efi_boot_service_driver",
llvm::COFF::IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER)
.Case("efi_rom", llvm::COFF::IMAGE_SUBSYSTEM_EFI_ROM)
.Case("efi_runtime_driver",
llvm::COFF::IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)
.Case("native", llvm::COFF::IMAGE_SUBSYSTEM_NATIVE)
.Case("posix", llvm::COFF::IMAGE_SUBSYSTEM_POSIX_CUI)
.Default(llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN);
}
llvm::COFF::MachineTypes stringToMachineType(StringRef str) {
return llvm::StringSwitch<llvm::COFF::MachineTypes>(str.lower())
.Case("arm", llvm::COFF::IMAGE_FILE_MACHINE_ARM)
.Case("ebc", llvm::COFF::IMAGE_FILE_MACHINE_EBC)
.Case("x64", llvm::COFF::IMAGE_FILE_MACHINE_AMD64)
.Case("x86", llvm::COFF::IMAGE_FILE_MACHINE_I386)
.Default(llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN);
}
// Parse /section:name,[[!]{DEKPRSW}]
//
// /section option is to set non-default bits in the Characteristics fields of
// the section header. D, E, K, P, R, S, and W represent discardable,
// not_cachable, not_pageable, shared, execute, read, and write bits,
// respectively. You can specify multiple flags in one /section option.
//
// If the flag starts with "!", the flags represent a mask that should be turned
// off regardless of the default value. You can even create a section which is
// not readable, writable nor executable with this -- although it's probably
// useless.
bool parseSection(StringRef option, std::string &section,
llvm::Optional<uint32_t> &flags,
llvm::Optional<uint32_t> &mask) {
StringRef flagString;
llvm::tie(section, flagString) = option.split(",");
bool negative = false;
if (flagString.startswith("!")) {
negative = true;
flagString = flagString.substr(1);
}
if (flagString.empty())
return false;
uint32_t attribs = 0;
for (size_t i = 0, e = flagString.size(); i < e; ++i) {
switch (tolower(flagString[i])) {
#define CASE(c, flag) \
case c: \
attribs |= flag; \
break
CASE('d', llvm::COFF::IMAGE_SCN_MEM_DISCARDABLE);
CASE('e', llvm::COFF::IMAGE_SCN_MEM_NOT_CACHED);
CASE('k', llvm::COFF::IMAGE_SCN_MEM_NOT_PAGED);
CASE('p', llvm::COFF::IMAGE_SCN_MEM_SHARED);
CASE('r', llvm::COFF::IMAGE_SCN_MEM_EXECUTE);
CASE('s', llvm::COFF::IMAGE_SCN_MEM_READ);
CASE('w', llvm::COFF::IMAGE_SCN_MEM_WRITE);
#undef CASE
default:
return false;
}
}
if (negative) {
mask = attribs;
} else {
flags = attribs;
}
return true;
}
bool readFile(PECOFFLinkingContext &ctx, StringRef path,
ArrayRef<uint8_t> &result) {
OwningPtr<MemoryBuffer> buf;
if (MemoryBuffer::getFile(path, buf))
return false;
result = ctx.allocate(ArrayRef<uint8_t>(
reinterpret_cast<const uint8_t *>(buf->getBufferStart()),
buf->getBufferSize()));
return true;
}
// Parse /manifest:EMBED[,ID=#]|NO.
bool parseManifest(StringRef option, bool &enable, bool &embed, int &id) {
if (option.equals_lower("no")) {
enable = false;
return true;
}
if (!option.startswith_lower("embed"))
return false;
embed = true;
option = option.substr(strlen("embed"));
if (option.empty())
return true;
if (!option.startswith_lower(",id="))
return false;
option = option.substr(strlen(",id="));
if (option.getAsInteger(0, id))
return false;
return true;
}
// Parse /manifestuac:(level=<string>|uiAccess=<string>).
//
// The arguments will be embedded to the manifest XML file with no error check,
// so the values given via the command line must be valid as XML attributes.
// This may sound a bit odd, but that's how link.exe works, so we will follow.
bool parseManifestUac(StringRef option, llvm::Optional<std::string> &level,
llvm::Optional<std::string> &uiAccess) {
for (;;) {
option = option.ltrim();
if (option.empty())
return true;
if (option.startswith_lower("level=")) {
option = option.substr(strlen("level="));
StringRef value;
llvm::tie(value, option) = option.split(" ");
level = value.str();
continue;
}
if (option.startswith_lower("uiaccess=")) {
option = option.substr(strlen("uiaccess="));
StringRef value;
llvm::tie(value, option) = option.split(" ");
uiAccess = value.str();
continue;
}
return false;
}
}
StringRef replaceExtension(PECOFFLinkingContext &ctx,
StringRef path, StringRef extension) {
SmallString<128> val = path;
llvm::sys::path::replace_extension(val, extension);
return ctx.allocateString(val.str());
}
// Create a manifest file contents.
std::string createManifestXml(PECOFFLinkingContext &ctx) {
std::string ret;
llvm::raw_string_ostream out(ret);
// Emit the XML. Note that we do *not* verify that the XML attributes are
// syntactically correct. This is intentional for link.exe compatibility.
out << "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\"\n"
" manifestVersion=\"1.0\">\n"
" <trustInfo>\n"
" <security>\n"
" <requestedPrivileges>\n"
" <requestedExecutionLevel level=" << ctx.getManifestLevel()
<< " uiAccess=" << ctx.getManifestUiAccess()
<< "/>\n"
" </requestedPrivileges>\n"
" </security>\n"
" </trustInfo>\n";
const std::string &dependency = ctx.getManifestDependency();
if (!dependency.empty()) {
out << " <dependency>\n"
" <dependentAssembly>\n"
" <assemblyIdentity " << dependency
<< " />\n"
" </dependentAssembly>\n"
" </dependency>\n";
}
out << "</assembly>\n";
out.flush();
return ret;
}
// Convert one doublequote to two doublequotes, so that we can embed the string
// into a resource script file.
void quoteAndPrintXml(raw_ostream &out, StringRef str) {
for (;;) {
if (str.empty())
return;
StringRef line;
llvm::tie(line, str) = str.split("\n");
if (line.empty())
continue;
out << '\"';
const char *p = line.data();
for (int i = 0, size = line.size(); i < size; ++i) {
switch (p[i]) {
case '\"':
out << '\"';
// fallthrough
default:
out << p[i];
}
}
out << "\"\n";
}
}
// Create a resource file (.res file) containing the manifest XML. This is done
// in two steps:
//
// 1. Create a resource script file containing the XML as a literal string.
// 2. Run RC.EXE command to compile the script file to a resource file.
//
// The temporary file created in step 1 will be deleted on exit from this
// function. The file created in step 2 will have the same lifetime as the
// PECOFFLinkingContext.
bool createManifestResourceFile(PECOFFLinkingContext &ctx,
raw_ostream &diagnostics,
std::string &resFile) {
// Create a temporary file for the resource script file.
SmallString<128> rcFileSmallString;
if (llvm::sys::fs::createTemporaryFile("tmp", "rc", rcFileSmallString)) {
diagnostics << "Cannot create a temporary file\n";
return false;
}
StringRef rcFile(rcFileSmallString.str());
llvm::FileRemover rcFileRemover((Twine(rcFile)));
// Open the temporary file for writing.
std::string errorInfo;
llvm::raw_fd_ostream out(rcFileSmallString.c_str(), errorInfo);
if (!errorInfo.empty()) {
diagnostics << "Failed to open " << ctx.getManifestOutputPath() << ": "
<< errorInfo << "\n";
return false;
}
// Write resource script to the RC file.
out << "#define LANG_ENGLISH 9\n"
<< "#define SUBLANG_DEFAULT 1\n"
<< "#define APP_MANIFEST " << ctx.getManifestId() << "\n"
<< "#define RT_MANIFEST 24\n"
<< "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"
<< "APP_MANIFEST RT_MANIFEST {\n";
quoteAndPrintXml(out, createManifestXml(ctx));
out << "}\n";
out.close();
// Create output resource file.
SmallString<128> resFileSmallString;
if (llvm::sys::fs::createTemporaryFile("tmp", "res", resFileSmallString)) {
diagnostics << "Cannot create a temporary file";
return false;
}
resFile = resFileSmallString.str();
// Register the resource file path so that the file will be deleted when the
// context's destructor is called.
ctx.registerTemporaryFile(resFile);
// Run RC.EXE /fo tmp.res tmp.rc
std::string program = "rc.exe";
std::string programPath = llvm::sys::FindProgramByName(program);
if (programPath.empty()) {
diagnostics << "Unable to find " << program << " in PATH\n";
return false;
}
std::vector<const char *> args;
args.push_back(programPath.c_str());
args.push_back("/fo");
args.push_back(resFile.c_str());
args.push_back("/nologo");
args.push_back(rcFileSmallString.c_str());
args.push_back(nullptr);
if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {
diagnostics << program << " failed\n";
return false;
}
return true;
}
// Create a side-by-side manifest file. The side-by-side manifest file is a
// separate XML file having ".manifest" extension. It will be created in the
// same directory as the resulting executable.
bool createSideBySideManifestFile(PECOFFLinkingContext &ctx,
raw_ostream &diagnostics) {
std::string errorInfo;
llvm::raw_fd_ostream out(ctx.getManifestOutputPath().data(), errorInfo);
if (!errorInfo.empty()) {
diagnostics << "Failed to open " << ctx.getManifestOutputPath() << ": "
<< errorInfo << "\n";
return false;
}
out << createManifestXml(ctx);
return true;
}
// Create the a side-by-side manifest file, or create a resource file for the
// manifest file and add it to the input graph.
//
// The manifest file will convey some information to the linker, such as whether
// the binary needs to run as Administrator or not. Instead of being placed in
// the PE/COFF header, it's in XML format for some reason -- I guess it's
// probably because it's invented in the early dot-com era.
bool createManifest(PECOFFLinkingContext &ctx, raw_ostream &diagnostics) {
if (ctx.getEmbedManifest()) {
std::string resourceFilePath;
if (!createManifestResourceFile(ctx, diagnostics, resourceFilePath))
return false;
std::unique_ptr<InputElement> inputElement(
new PECOFFFileNode(ctx, ctx.allocateString(resourceFilePath)));
ctx.inputGraph().addInputElement(std::move(inputElement));
return true;
}
return createSideBySideManifestFile(ctx, diagnostics);
}
// Handle /failifmismatch option.
bool handleFailIfMismatchOption(StringRef option,
std::map<StringRef, StringRef> &mustMatch,
raw_ostream &diagnostics) {
StringRef key, value;
llvm::tie(key, value) = option.split('=');
if (key.empty() || value.empty()) {
diagnostics << "error: malformed /failifmismatch option: " << option << "\n";
return true;
}
auto it = mustMatch.find(key);
if (it != mustMatch.end() && it->second != value) {
diagnostics << "error: mismatch detected: '" << it->second << "' and '"
<< value << "' for key '" << key << "'\n";
return true;
}
mustMatch[key] = value;
return false;
}
//
// Environment variable
//
// Process "LINK" environment variable. If defined, the value of the variable
// should be processed as command line arguments.
std::vector<const char *> processLinkEnv(PECOFFLinkingContext &context,
int argc, const char **argv) {
std::vector<const char *> ret;
// The first argument is the name of the command. This should stay at the head
// of the argument list.
assert(argc > 0);
ret.push_back(argv[0]);
// Add arguments specified by the LINK environment variable.
llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LINK");
if (env.hasValue())
for (std::string &arg : splitArgList(*env))
ret.push_back(context.allocateString(arg).data());
// Add the rest of arguments passed via the command line.
for (int i = 1; i < argc; ++i)
ret.push_back(argv[i]);
ret.push_back(nullptr);
return ret;
}
// Process "LIB" environment variable. The variable contains a list of search
// paths separated by semicolons.
void processLibEnv(PECOFFLinkingContext &context) {
llvm::Optional<std::string> env = llvm::sys::Process::GetEnv("LIB");
if (env.hasValue())
for (StringRef path : splitPathList(*env))
context.appendInputSearchPath(context.allocateString(path));
}
// Returns a default entry point symbol name depending on context image type and
// subsystem. These default names are MS CRT compliant.
StringRef getDefaultEntrySymbolName(PECOFFLinkingContext &context) {
if (context.getImageType() == PECOFFLinkingContext::ImageType::IMAGE_DLL)
return "_DllMainCRTStartup";
llvm::COFF::WindowsSubsystem subsystem = context.getSubsystem();
if (subsystem == llvm::COFF::WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_GUI)
return "WinMainCRTStartup";
if (subsystem == llvm::COFF::WindowsSubsystem::IMAGE_SUBSYSTEM_WINDOWS_CUI)
return "mainCRTStartup";
return "";
}
// Parses the given command line options and returns the result. Returns NULL if
// there's an error in the options.
std::unique_ptr<llvm::opt::InputArgList>
parseArgs(int argc, const char *argv[], raw_ostream &diagnostics,
bool isReadingDirectiveSection) {
// Parse command line options using WinLinkOptions.td
std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
WinLinkOptTable table;
unsigned missingIndex;
unsigned missingCount;
parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
missingIndex, missingCount));
if (missingCount) {
diagnostics << "error: missing arg value for '"
<< parsedArgs->getArgString(missingIndex) << "' expected "
<< missingCount << " argument(s).\n";
return nullptr;
}
// Show warning for unknown arguments. In .drectve section, unknown options
// starting with "-?" are silently ignored. This is a COFF's feature to embed a
// new linker option to an object file while keeping backward compatibility.
for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
ie = parsedArgs->filtered_end(); it != ie; ++it) {
StringRef arg = (*it)->getSpelling();
if (isReadingDirectiveSection && arg.startswith("-?"))
continue;
diagnostics << "warning: ignoring unknown argument: " << arg << "\n";
}
return parsedArgs;
}
} // namespace
//
// Main driver
//
ErrorOr<StringRef> PECOFFFileNode::getPath(const LinkingContext &) const {
if (_path.endswith_lower(".lib"))
return _ctx.searchLibraryFile(_path);
if (llvm::sys::path::extension(_path).empty())
return _ctx.allocateString(_path.str() + ".obj");
return _path;
}
ErrorOr<StringRef> PECOFFLibraryNode::getPath(const LinkingContext &) const {
if (!_path.endswith_lower(".lib"))
return _ctx.searchLibraryFile(_ctx.allocateString(_path.str() + ".lib"));
return _ctx.searchLibraryFile(_path);
}
bool WinLinkDriver::linkPECOFF(int argc, const char *argv[],
raw_ostream &diagnostics) {
PECOFFLinkingContext context;
std::vector<const char *> newargv = processLinkEnv(context, argc, argv);
processLibEnv(context);
if (!parse(newargv.size() - 1, &newargv[0], context, diagnostics))
return false;
// Create the file if needed.
if (context.getCreateManifest())
if (!createManifest(context, diagnostics))
return false;
return link(context, diagnostics);
}
bool
WinLinkDriver::parse(int argc, const char *argv[], PECOFFLinkingContext &ctx,
raw_ostream &diagnostics, bool isReadingDirectiveSection) {
std::map<StringRef, StringRef> failIfMismatchMap;
// Parse the options.
std::unique_ptr<llvm::opt::InputArgList> parsedArgs = parseArgs(
argc, argv, diagnostics, isReadingDirectiveSection);
if (!parsedArgs)
return false;
// The list of input files.
std::vector<std::unique_ptr<InputElement> > inputElements;
// Handle /help
if (parsedArgs->getLastArg(OPT_help)) {
WinLinkOptTable table;
table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
return false;
}
// Handle /nodefaultlib:<lib>. The same option without argument is handled in
// the following for loop.
for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_nodefaultlib),
ie = parsedArgs->filtered_end();
it != ie; ++it) {
ctx.addNoDefaultLib((*it)->getValue());
}
// Handle /defaultlib. Argument of the option is added to the input file list
// unless it's blacklisted by /nodefaultlib.
std::vector<StringRef> defaultLibs;
for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_defaultlib),
ie = parsedArgs->filtered_end();
it != ie; ++it) {
defaultLibs.push_back((*it)->getValue());
}
// Process all the arguments and create Input Elements
for (auto inputArg : *parsedArgs) {
switch (inputArg->getOption().getID()) {
case OPT_mllvm:
ctx.appendLLVMOption(inputArg->getValue());
break;
case OPT_base:
// Parse /base command line option. The argument for the parameter is in
// the form of "<address>[:<size>]".
uint64_t addr, size;
// Size should be set to SizeOfImage field in the COFF header, and if
// it's smaller than the actual size, the linker should warn about that.
// Currently we just ignore the value of size parameter.
if (!parseMemoryOption(inputArg->getValue(), addr, size))
return false;
ctx.setBaseAddress(addr);
break;
case OPT_stack: {
// Parse /stack command line option
uint64_t reserve;
uint64_t commit = ctx.getStackCommit();
if (!parseMemoryOption(inputArg->getValue(), reserve, commit))
return false;
ctx.setStackReserve(reserve);
ctx.setStackCommit(commit);
break;
}
case OPT_heap: {
// Parse /heap command line option
uint64_t reserve;
uint64_t commit = ctx.getHeapCommit();
if (!parseMemoryOption(inputArg->getValue(), reserve, commit))
return false;
ctx.setHeapReserve(reserve);
ctx.setHeapCommit(commit);
break;
}
case OPT_align: {
uint32_t align;
StringRef arg = inputArg->getValue();
if (arg.getAsInteger(10, align)) {
diagnostics << "error: invalid value for /align: " << arg << "\n";
return false;
}
ctx.setSectionDefaultAlignment(align);
break;
}
case OPT_machine: {
StringRef arg = inputArg->getValue();
llvm::COFF::MachineTypes type = stringToMachineType(arg);
if (type == llvm::COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
diagnostics << "error: unknown machine type: " << arg << "\n";
return false;
}
ctx.setMachineType(type);
break;
}
case OPT_version: {
uint32_t major, minor;
if (!parseVersion(inputArg->getValue(), major, minor))
return false;
ctx.setImageVersion(PECOFFLinkingContext::Version(major, minor));
break;
}
case OPT_merge: {
// Parse /merge:<from>=<to>.
StringRef from, to;
llvm::tie(from, to) = StringRef(inputArg->getValue()).split('=');
if (from.empty() || to.empty()) {
diagnostics << "error: malformed /merge option: "
<< inputArg->getValue() << "\n";
return false;
}
if (!ctx.addSectionRenaming(diagnostics, from, to))
return false;
break;
}
case OPT_subsystem: {
// Parse /subsystem command line option. The form of /subsystem is
// "subsystem_name[,majorOSVersion[.minorOSVersion]]".
StringRef subsystemStr, osVersion;
llvm::tie(subsystemStr, osVersion) =
StringRef(inputArg->getValue()).split(',');
if (!osVersion.empty()) {
uint32_t major, minor;
if (!parseVersion(osVersion, major, minor))
return false;
ctx.setMinOSVersion(PECOFFLinkingContext::Version(major, minor));
}
// Parse subsystem name.
llvm::COFF::WindowsSubsystem subsystem =
stringToWinSubsystem(subsystemStr);
if (subsystem == llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN) {
diagnostics << "error: unknown subsystem name: " << subsystemStr
<< "\n";
return false;
}
ctx.setSubsystem(subsystem);
break;
}
case OPT_section: {
// Parse /section:name,[[!]{DEKPRSW}]
std::string section;
llvm::Optional<uint32_t> flags, mask;
if (!parseSection(inputArg->getValue(), section, flags, mask)) {
diagnostics << "Unknown argument for /section: "
<< inputArg->getValue() << "\n";
return false;
}
if (flags.hasValue())
ctx.setSectionAttributes(section, *flags);
if (mask.hasValue())
ctx.setSectionAttributeMask(section, *mask);
break;
}
case OPT_manifest:
// Do nothing. This is default.
break;
case OPT_manifest_colon: {
// Parse /manifest:EMBED[,ID=#]|NO.
bool enable = true;
bool embed = false;
int id = 1;
if (!parseManifest(inputArg->getValue(), enable, embed, id)) {
diagnostics << "Unknown argument for /manifest: "
<< inputArg->getValue() << "\n";
return false;
}
ctx.setCreateManifest(enable);
ctx.setEmbedManifest(embed);
ctx.setManifestId(id);
break;
}
case OPT_manifestuac: {
// Parse /manifestuac.
llvm::Optional<std::string> privilegeLevel;
llvm::Optional<std::string> uiAccess;
if (!parseManifestUac(inputArg->getValue(), privilegeLevel, uiAccess)) {
diagnostics << "Unknown argument for /manifestuac: "
<< inputArg->getValue() << "\n";
return false;
}
if (privilegeLevel.hasValue())
ctx.setManifestLevel(privilegeLevel.getValue());
if (uiAccess.hasValue())
ctx.setManifestUiAccess(uiAccess.getValue());
break;
}
case OPT_manifestfile:
ctx.setManifestOutputPath(ctx.allocateString(inputArg->getValue()));
break;
case OPT_manifestdependency:
// /manifestdependency:<string> option. Note that the argument will be
// embedded to the manifest XML file with no error check, for link.exe
// compatibility. We do not gurantete that the resulting XML file is
// valid.
ctx.setManifestDependency(ctx.allocateString(inputArg->getValue()));
break;
case OPT_failifmismatch:
if (handleFailIfMismatchOption(inputArg->getValue(), failIfMismatchMap,
diagnostics))
return false;
break;
case OPT_entry:
ctx.setEntrySymbolName(ctx.allocateString(inputArg->getValue()));
break;
case OPT_libpath:
ctx.appendInputSearchPath(ctx.allocateString(inputArg->getValue()));
break;
case OPT_debug:
// LLD is not yet capable of creating a PDB file, so /debug does not have
// any effect, other than disabling dead stripping.
ctx.setDeadStripping(false);
// Prints out input files during core linking to help debugging.
ctx.setLogInputFiles(true);
break;
case OPT_force:
case OPT_force_unresolved:
// /force and /force:unresolved mean the same thing. We do not currently
// support /force:multiple.
ctx.setAllowRemainingUndefines(true);
break;
case OPT_fixed:
// /fixed is not compatible with /dynamicbase. Check for it.
if (parsedArgs->getLastArg(OPT_dynamicbase)) {
diagnostics << "/dynamicbase must not be specified with /fixed\n";
return false;
}
ctx.setBaseRelocationEnabled(false);
ctx.setDynamicBaseEnabled(false);
break;
case OPT_swaprun_cd:
// /swaprun:{cd,net} options set IMAGE_FILE_{REMOVABLE,NET}_RUN_FROM_SWAP
// bits in the COFF header, respectively. If one of the bits is on, the
// Windows loader will copy the entire file to swap area then execute it,
// so that the user can eject a CD or disconnect from the network.
ctx.setSwapRunFromCD(true);
break;
case OPT_swaprun_net:
ctx.setSwapRunFromNet(true);
break;
case OPT_stub: {
ArrayRef<uint8_t> contents;
if (!readFile(ctx, inputArg->getValue(), contents)) {
diagnostics << "Failed to read DOS stub file "
<< inputArg->getValue() << "\n";
return false;
}
ctx.setDosStub(contents);
break;
}
case OPT_incl:
ctx.addInitialUndefinedSymbol(ctx.allocateString(inputArg->getValue()));
break;
case OPT_nodefaultlib_all:
ctx.setNoDefaultLibAll(true);
break;
case OPT_out:
ctx.setOutputPath(ctx.allocateString(inputArg->getValue()));
break;
case OPT_INPUT:
inputElements.push_back(std::unique_ptr<InputElement>(
new PECOFFFileNode(ctx, ctx.allocateString(inputArg->getValue()))));
break;
#define DEFINE_BOOLEAN_FLAG(name, setter) \
case OPT_##name: \
ctx.setter(true); \
break; \
case OPT_##name##_no: \
ctx.setter(false); \
break
DEFINE_BOOLEAN_FLAG(ref, setDeadStripping);
DEFINE_BOOLEAN_FLAG(nxcompat, setNxCompat);
DEFINE_BOOLEAN_FLAG(largeaddressaware, setLargeAddressAware);
DEFINE_BOOLEAN_FLAG(allowbind, setAllowBind);
DEFINE_BOOLEAN_FLAG(allowisolation, setAllowIsolation);
DEFINE_BOOLEAN_FLAG(dynamicbase, setDynamicBaseEnabled);
DEFINE_BOOLEAN_FLAG(tsaware, setTerminalServerAware);
#undef DEFINE_BOOLEAN_FLAG
default:
break;
}
}
// Use the default entry name if /entry option is not given.
if (ctx.entrySymbolName().empty())
ctx.setEntrySymbolName(getDefaultEntrySymbolName(ctx));
StringRef entry = ctx.entrySymbolName();
if (!entry.empty())
ctx.addInitialUndefinedSymbol(entry);
// Specifying both /opt:ref and /opt:noref is an error.
if (parsedArgs->getLastArg(OPT_ref) && parsedArgs->getLastArg(OPT_ref_no)) {
diagnostics << "/opt:ref must not be specified with /opt:noref\n";
return false;
}
// If dead-stripping is enabled, we need to add the entry symbol and
// symbols given by /include to the dead strip root set, so that it
// won't be removed from the output.
if (ctx.deadStrip())
for (const StringRef symbolName : ctx.initialUndefinedSymbols())
ctx.addDeadStripRoot(symbolName);
// Arguments after "--" are interpreted as filenames even if they
// start with a hypen or a slash. This is not compatible with link.exe
// but useful for us to test lld on Unix.
if (llvm::opt::Arg *dashdash = parsedArgs->getLastArg(OPT_DASH_DASH)) {
for (const StringRef value : dashdash->getValues()) {
std::unique_ptr<InputElement> elem(
new PECOFFFileNode(ctx, ctx.allocateString(value)));
inputElements.push_back(std::move(elem));
}
}
// Add the libraries specified by /defaultlib unless they are already added
// nor blacklisted by /nodefaultlib.
if (!ctx.getNoDefaultLibAll()) {
for (const StringRef path : defaultLibs) {
if (!ctx.hasNoDefaultLib(path) && !ctx.hasDefaultLib(path)) {
inputElements.push_back(std::unique_ptr<InputElement>(
new PECOFFLibraryNode(ctx, path)));
ctx.addDefaultLib(path);
}
}
}
if (inputElements.empty() && !isReadingDirectiveSection) {
diagnostics << "No input files\n";
return false;
}
// If /out option was not specified, the default output file name is
// constructed by replacing an extension of the first input file
// with ".exe".
if (ctx.outputPath().empty()) {
StringRef path = *dyn_cast<FileNode>(&*inputElements[0])->getPath(ctx);
ctx.setOutputPath(replaceExtension(ctx, path, ".exe"));
}
// Default name of the manifest file is "foo.exe.manifest" where "foo.exe" is
// the output path.
if (ctx.getManifestOutputPath().empty()) {
std::string path = ctx.outputPath();
path.append(".manifest");
ctx.setManifestOutputPath(ctx.allocateString(path));
}
// If the core linker already started, we need to explicitly call parse() for
// each input element, because the pass to parse input files in Driver::link
// has already done.
if (isReadingDirectiveSection)
for (auto &e : inputElements)
if (e->parse(ctx, diagnostics))
return false;
// Add the input files to the input graph.
if (!ctx.hasInputGraph())
ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph()));
for (auto &e : inputElements)
ctx.inputGraph().addInputElement(std::move(e));
// Validate the combination of options used.
return ctx.validate(diagnostics);
}
} // namespace lld

View File

@@ -1,103 +0,0 @@
include "llvm/Option/OptParser.td"
// link.exe accepts options starting with either a dash or a slash.
// Flag that takes no arguments.
class F<string name> : Flag<["/", "-", "-?"], name>;
// Flag that takes one argument after ":".
class P<string name, string help> :
Joined<["/", "-", "-?"], name#":">, HelpText<help>;
// Boolean flag suffixed by ":no".
multiclass B<string name, string help> {
def "" : F<name>;
def _no : F<name#":no">, HelpText<help>;
}
def base : P<"base", "Base address of the program">;
def defaultlib : P<"defaultlib", "Add the library to the list of input files">;
def nodefaultlib : P<"nodefaultlib", "Remove a default library">;
def disallowlib : Joined<["/", "-", "-?"], "disallowlib:">, Alias<nodefaultlib>;
def entry : P<"entry", "Name of entry point symbol">;
// No help text because /failifmismatch is not intended to be used by the user.
def failifmismatch : P<"failifmismatch", "">;
def heap : P<"heap", "Size of the heap">;
def align : P<"align", "Section alignment">;
def libpath : P<"libpath", "Additional library search path">;
def mllvm : P<"mllvm", "Options to pass to LLVM">;
def out : P<"out", "Path to file to write output">;
def stack : P<"stack", "Size of the stack">;
def machine : P<"machine", "Specify target platform">;
def version : P<"version", "Specify a version number in the PE header">;
def merge : P<"merge", "Combine sections">;
def section : P<"section", "Specify section attributes">;
def subsystem : P<"subsystem", "Specify subsystem">;
def stub : P<"stub", "Specify DOS stub file">;
def manifest : F<"manifest">;
def manifest_colon : P<"manifest", "Create manifest file">;
def manifestuac : P<"manifestuac", "User access control">;
def manifestfile : P<"manifestfile", "Manifest file path">;
def manifestdependency : P<"manifestdependency",
"Attributes for <dependency> in manifest file">;
// We cannot use multiclass P because class name "incl" is different
// from its command line option name. We do this because "include" is
// a reserved keyword in tablegen.
def incl : Joined<["/", "-"], "include:">,
HelpText<"Force symbol to be added to symbol table as undefined one">;
def incl_c : Separate<["/", "-"], "include">, Alias<incl>;
def nodefaultlib_all : F<"nodefaultlib">;
def debug : F<"debug">;
def swaprun_cd : F<"swaprun:cd">;
def swaprun_net : F<"swaprun:net">;
def force : F<"force">,
HelpText<"Allow undefined symbols when creating executables">;
def force_unresolved : F<"force:unresolved">;
def ref : F<"opt:ref">;
def ref_no : F<"opt:noref">,
HelpText<"Keep unreferenced symbols to be included to the output">;
defm nxcompat : B<"nxcompat", "Disable data execution provention">;
defm largeaddressaware : B<"largeaddressaware", "Disable large addresses">;
defm allowbind: B<"allowbind", "Disable DLL binding">;
defm fixed : B<"fixed", "Enable base relocations">;
defm tsaware : B<"tsaware", "Create non-Terminal Server aware executable">;
defm allowisolation : B<"allowisolation", "Set NO_ISOLATION bit">;
defm dynamicbase : B<"dynamicbase",
"Disable address space layout randomization">;
def help : F<"help">;
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
def DASH_DASH : Option<["--"], "", KIND_REMAINING_ARGS>;
//
// The flags below do nothing. They are defined only for link.exe compatibility.
//
class QF<string name> : Joined<["/", "-", "-?"], name#":">;
multiclass QB<string name> {
def "" : F<name>;
def _no : F<name#":no">;
}
def incremental : F<"incremental">;
def no_incremental : F<"incremental:no">;
def nologo : F<"nologo">;
def verbose : F<"verbose">;
def delay : QF<"delay">;
def delayload : QF<"delayload">;
def errorreport : QF<"errorreport">;
def pdb : QF<"pdb">;
def pdbaltpath : QF<"pdbaltpath">;
def verbose_all : QF<"verbose">;
defm wx : QB<"wx">;

Some files were not shown because too many files have changed in this diff Show More