Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6f76b8fb2 | |||
|
|
35b65c5af1 | ||
|
|
0dd719f1bd | ||
|
|
5e9e5b98f6 | ||
|
|
7c3424c244 | ||
|
|
a27e58e1f7 | ||
|
|
4667c87c4d | ||
|
|
2117e99cef | ||
|
|
9866ad31fd | ||
|
|
24f3305be0 | ||
|
|
b2ee0702ff |
9
distrib/sets/lists/minix-tests/md.evbarm
Normal file
9
distrib/sets/lists/minix-tests/md.evbarm
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#
|
||||||
|
# Sorted using sort_set.pl in releasetools.
|
||||||
|
# to add an entry simply add it at the end of the
|
||||||
|
# file and run
|
||||||
|
# ../../../../releasetools/sort_set.pl < mi > out
|
||||||
|
# mv out mi
|
||||||
|
#
|
||||||
|
./usr/tests/minix-posix/test_arm_segfault minix-tests
|
||||||
|
./usr/tests/minix-posix/test_arm_unaligned minix-tests
|
||||||
4
external/bsd/llvm/dist/lld/.arcconfig
vendored
Normal file
4
external/bsd/llvm/dist/lld/.arcconfig
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"project_id" : "lld",
|
||||||
|
"conduit_uri" : "http://llvm-reviews.chandlerc.com/"
|
||||||
|
}
|
||||||
169
external/bsd/llvm/dist/lld/CMakeLists.txt
vendored
Normal file
169
external/bsd/llvm/dist/lld/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
# 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()
|
||||||
62
external/bsd/llvm/dist/lld/LICENSE.TXT
vendored
Normal file
62
external/bsd/llvm/dist/lld/LICENSE.TXT
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
==============================================================================
|
||||||
|
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>
|
||||||
10
external/bsd/llvm/dist/lld/README.md
vendored
Normal file
10
external/bsd/llvm/dist/lld/README.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
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.
|
||||||
31
external/bsd/llvm/dist/lld/cmake/modules/FindVTune.cmake
vendored
Normal file
31
external/bsd/llvm/dist/lld/cmake/modules/FindVTune.cmake
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# - 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)
|
||||||
35
external/bsd/llvm/dist/lld/docs/C++11.rst
vendored
Normal file
35
external/bsd/llvm/dist/lld/docs/C++11.rst
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
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.
|
||||||
79
external/bsd/llvm/dist/lld/docs/Driver.rst
vendored
Normal file
79
external/bsd/llvm/dist/lld/docs/Driver.rst
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
======
|
||||||
|
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`.
|
||||||
155
external/bsd/llvm/dist/lld/docs/Makefile
vendored
Normal file
155
external/bsd/llvm/dist/lld/docs/Makefile
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# 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."
|
||||||
12
external/bsd/llvm/dist/lld/docs/README.txt
vendored
Normal file
12
external/bsd/llvm/dist/lld/docs/README.txt
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
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
|
||||||
|
|
||||||
172
external/bsd/llvm/dist/lld/docs/Readers.rst
vendored
Normal file
172
external/bsd/llvm/dist/lld/docs/Readers.rst
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
.. _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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
external/bsd/llvm/dist/lld/docs/_static/favicon.ico
vendored
Normal file
BIN
external/bsd/llvm/dist/lld/docs/_static/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
4
external/bsd/llvm/dist/lld/docs/_templates/indexsidebar.html
vendored
Normal file
4
external/bsd/llvm/dist/lld/docs/_templates/indexsidebar.html
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<h3>Bugs</h3>
|
||||||
|
|
||||||
|
<p>lld bugs should be reported at the
|
||||||
|
LLVM <a href="http://llvm.org/bugs">Bugzilla</a>.</p>
|
||||||
12
external/bsd/llvm/dist/lld/docs/_templates/layout.html
vendored
Normal file
12
external/bsd/llvm/dist/lld/docs/_templates/layout.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{% 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> | </li>
|
||||||
|
{% endblock %}
|
||||||
251
external/bsd/llvm/dist/lld/docs/conf.py
vendored
Normal file
251
external/bsd/llvm/dist/lld/docs/conf.py
vendored
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
# -*- 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
|
||||||
470
external/bsd/llvm/dist/lld/docs/design.rst
vendored
Normal file
470
external/bsd/llvm/dist/lld/docs/design.rst
vendored
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
.. _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.
|
||||||
48
external/bsd/llvm/dist/lld/docs/development.rst
vendored
Normal file
48
external/bsd/llvm/dist/lld/docs/development.rst
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
.. _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
|
||||||
106
external/bsd/llvm/dist/lld/docs/getting_started.rst
vendored
Normal file
106
external/bsd/llvm/dist/lld/docs/getting_started.rst
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
.. _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
|
||||||
BIN
external/bsd/llvm/dist/lld/docs/hello.png
vendored
Normal file
BIN
external/bsd/llvm/dist/lld/docs/hello.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
82
external/bsd/llvm/dist/lld/docs/index.rst
vendored
Normal file
82
external/bsd/llvm/dist/lld/docs/index.rst
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
.. _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
|
||||||
22
external/bsd/llvm/dist/lld/docs/llvm-theme/layout.html
vendored
Normal file
22
external/bsd/llvm/dist/lld/docs/llvm-theme/layout.html
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{#
|
||||||
|
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 %}
|
||||||
BIN
external/bsd/llvm/dist/lld/docs/llvm-theme/static/contents.png
vendored
Normal file
BIN
external/bsd/llvm/dist/lld/docs/llvm-theme/static/contents.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 202 B |
345
external/bsd/llvm/dist/lld/docs/llvm-theme/static/llvm.css
vendored
Normal file
345
external/bsd/llvm/dist/lld/docs/llvm-theme/static/llvm.css
vendored
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
BIN
external/bsd/llvm/dist/lld/docs/llvm-theme/static/logo.png
vendored
Normal file
BIN
external/bsd/llvm/dist/lld/docs/llvm-theme/static/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
BIN
external/bsd/llvm/dist/lld/docs/llvm-theme/static/navigation.png
vendored
Normal file
BIN
external/bsd/llvm/dist/lld/docs/llvm-theme/static/navigation.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 218 B |
4
external/bsd/llvm/dist/lld/docs/llvm-theme/theme.conf
vendored
Normal file
4
external/bsd/llvm/dist/lld/docs/llvm-theme/theme.conf
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[theme]
|
||||||
|
inherit = basic
|
||||||
|
stylesheet = llvm.css
|
||||||
|
pygments_style = friendly
|
||||||
190
external/bsd/llvm/dist/lld/docs/make.bat
vendored
Normal file
190
external/bsd/llvm/dist/lld/docs/make.bat
vendored
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
@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
|
||||||
13
external/bsd/llvm/dist/lld/docs/open_projects.rst
vendored
Normal file
13
external/bsd/llvm/dist/lld/docs/open_projects.rst
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.. _open_projects:
|
||||||
|
|
||||||
|
Open Projects
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. include:: ../include/lld/Core/TODO.txt
|
||||||
|
.. include:: ../lib/Core/TODO.txt
|
||||||
|
.. include:: ../tools/lld/TODO.txt
|
||||||
|
|
||||||
|
Documentation TODOs
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. todolist::
|
||||||
147
external/bsd/llvm/dist/lld/docs/sphinx_intro.rst
vendored
Normal file
147
external/bsd/llvm/dist/lld/docs/sphinx_intro.rst
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
.. _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.
|
||||||
43
external/bsd/llvm/dist/lld/include/lld/Core/AbsoluteAtom.h
vendored
Normal file
43
external/bsd/llvm/dist/lld/include/lld/Core/AbsoluteAtom.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//===- 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
|
||||||
48
external/bsd/llvm/dist/lld/include/lld/Core/ArchiveLibraryFile.h
vendored
Normal file
48
external/bsd/llvm/dist/lld/include/lld/Core/ArchiveLibraryFile.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
//===- 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
|
||||||
84
external/bsd/llvm/dist/lld/include/lld/Core/Atom.h
vendored
Normal file
84
external/bsd/llvm/dist/lld/include/lld/Core/Atom.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//===- 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
|
||||||
357
external/bsd/llvm/dist/lld/include/lld/Core/DefinedAtom.h
vendored
Normal file
357
external/bsd/llvm/dist/lld/include/lld/Core/DefinedAtom.h
vendored
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
//===- 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
|
||||||
84
external/bsd/llvm/dist/lld/include/lld/Core/Error.h
vendored
Normal file
84
external/bsd/llvm/dist/lld/include/lld/Core/Error.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//===- 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
|
||||||
251
external/bsd/llvm/dist/lld/include/lld/Core/File.h
vendored
Normal file
251
external/bsd/llvm/dist/lld/include/lld/Core/File.h
vendored
Normal file
@@ -0,0 +1,251 @@
|
|||||||
|
//===- 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
|
||||||
411
external/bsd/llvm/dist/lld/include/lld/Core/InputGraph.h
vendored
Normal file
411
external/bsd/llvm/dist/lld/include/lld/Core/InputGraph.h
vendored
Normal file
@@ -0,0 +1,411 @@
|
|||||||
|
//===- 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
|
||||||
133
external/bsd/llvm/dist/lld/include/lld/Core/Instrumentation.h
vendored
Normal file
133
external/bsd/llvm/dist/lld/include/lld/Core/Instrumentation.h
vendored
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
//===- 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
|
||||||
92
external/bsd/llvm/dist/lld/include/lld/Core/LLVM.h
vendored
Normal file
92
external/bsd/llvm/dist/lld/include/lld/Core/LLVM.h
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
//===--- 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
|
||||||
378
external/bsd/llvm/dist/lld/include/lld/Core/LinkingContext.h
vendored
Normal file
378
external/bsd/llvm/dist/lld/include/lld/Core/LinkingContext.h
vendored
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
//===- 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
|
||||||
271
external/bsd/llvm/dist/lld/include/lld/Core/Parallel.h
vendored
Normal file
271
external/bsd/llvm/dist/lld/include/lld/Core/Parallel.h
vendored
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
//===- 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
|
||||||
118
external/bsd/llvm/dist/lld/include/lld/Core/Pass.h
vendored
Normal file
118
external/bsd/llvm/dist/lld/include/lld/Core/Pass.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
//===------ 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
|
||||||
43
external/bsd/llvm/dist/lld/include/lld/Core/PassManager.h
vendored
Normal file
43
external/bsd/llvm/dist/lld/include/lld/Core/PassManager.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//===- 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
|
||||||
112
external/bsd/llvm/dist/lld/include/lld/Core/Reference.h
vendored
Normal file
112
external/bsd/llvm/dist/lld/include/lld/Core/Reference.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
//===- 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
|
||||||
128
external/bsd/llvm/dist/lld/include/lld/Core/Resolver.h
vendored
Normal file
128
external/bsd/llvm/dist/lld/include/lld/Core/Resolver.h
vendored
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
//===- 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
|
||||||
33
external/bsd/llvm/dist/lld/include/lld/Core/STDExtras.h
vendored
Normal file
33
external/bsd/llvm/dist/lld/include/lld/Core/STDExtras.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
//===- 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
|
||||||
57
external/bsd/llvm/dist/lld/include/lld/Core/SharedLibraryAtom.h
vendored
Normal file
57
external/bsd/llvm/dist/lld/include/lld/Core/SharedLibraryAtom.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//===- 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
|
||||||
42
external/bsd/llvm/dist/lld/include/lld/Core/SharedLibraryFile.h
vendored
Normal file
42
external/bsd/llvm/dist/lld/include/lld/Core/SharedLibraryFile.h
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
//===- 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
|
||||||
110
external/bsd/llvm/dist/lld/include/lld/Core/SymbolTable.h
vendored
Normal file
110
external/bsd/llvm/dist/lld/include/lld/Core/SymbolTable.h
vendored
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
//===- 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
|
||||||
17
external/bsd/llvm/dist/lld/include/lld/Core/TODO.txt
vendored
Normal file
17
external/bsd/llvm/dist/lld/include/lld/Core/TODO.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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
|
||||||
74
external/bsd/llvm/dist/lld/include/lld/Core/UndefinedAtom.h
vendored
Normal file
74
external/bsd/llvm/dist/lld/include/lld/Core/UndefinedAtom.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
//===- 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
|
||||||
739
external/bsd/llvm/dist/lld/include/lld/Core/range.h
vendored
Normal file
739
external/bsd/llvm/dist/lld/include/lld/Core/range.h
vendored
Normal file
@@ -0,0 +1,739 @@
|
|||||||
|
//===-- 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
|
||||||
79
external/bsd/llvm/dist/lld/include/lld/Driver/CoreInputGraph.h
vendored
Normal file
79
external/bsd/llvm/dist/lld/include/lld/Driver/CoreInputGraph.h
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
//===- 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
|
||||||
82
external/bsd/llvm/dist/lld/include/lld/Driver/DarwinInputGraph.h
vendored
Normal file
82
external/bsd/llvm/dist/lld/include/lld/Driver/DarwinInputGraph.h
vendored
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
//===- 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
|
||||||
135
external/bsd/llvm/dist/lld/include/lld/Driver/Driver.h
vendored
Normal file
135
external/bsd/llvm/dist/lld/include/lld/Driver/Driver.h
vendored
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
//===- 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
|
||||||
187
external/bsd/llvm/dist/lld/include/lld/Driver/GnuLdInputGraph.h
vendored
Normal file
187
external/bsd/llvm/dist/lld/include/lld/Driver/GnuLdInputGraph.h
vendored
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
//===- 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
|
||||||
101
external/bsd/llvm/dist/lld/include/lld/Driver/WinLinkInputGraph.h
vendored
Normal file
101
external/bsd/llvm/dist/lld/include/lld/Driver/WinLinkInputGraph.h
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
//===- 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
|
||||||
106
external/bsd/llvm/dist/lld/include/lld/Passes/LayoutPass.h
vendored
Normal file
106
external/bsd/llvm/dist/lld/include/lld/Passes/LayoutPass.h
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
//===------ 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
|
||||||
41
external/bsd/llvm/dist/lld/include/lld/Passes/RoundTripNativePass.h
vendored
Normal file
41
external/bsd/llvm/dist/lld/include/lld/Passes/RoundTripNativePass.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//===--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
|
||||||
41
external/bsd/llvm/dist/lld/include/lld/Passes/RoundTripYAMLPass.h
vendored
Normal file
41
external/bsd/llvm/dist/lld/include/lld/Passes/RoundTripYAMLPass.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//===--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
|
||||||
41
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/AtomLayout.h
vendored
Normal file
41
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/AtomLayout.h
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//===- 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
|
||||||
45
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/CoreLinkingContext.h
vendored
Normal file
45
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/CoreLinkingContext.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
//===- 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
|
||||||
246
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/ELFLinkingContext.h
vendored
Normal file
246
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/ELFLinkingContext.h
vendored
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
//===- 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
|
||||||
176
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/FileArchive.h
vendored
Normal file
176
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/FileArchive.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
//===- 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
|
||||||
228
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/LinkerScript.h
vendored
Normal file
228
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/LinkerScript.h
vendored
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
//===- 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
|
||||||
627
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/MachOFormat.hpp
vendored
Normal file
627
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/MachOFormat.hpp
vendored
Normal file
@@ -0,0 +1,627 @@
|
|||||||
|
//===- 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
|
||||||
|
|
||||||
174
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/MachOLinkingContext.h
vendored
Normal file
174
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/MachOLinkingContext.h
vendored
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
//===- 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
|
||||||
338
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/PECOFFLinkingContext.h
vendored
Normal file
338
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/PECOFFLinkingContext.h
vendored
Normal file
@@ -0,0 +1,338 @@
|
|||||||
|
//===- 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
|
||||||
56
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/Reader.h
vendored
Normal file
56
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/Reader.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
//===- 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
|
||||||
34
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/ReaderLinkerScript.h
vendored
Normal file
34
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/ReaderLinkerScript.h
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
//===- 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
|
||||||
53
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/RelocationHelperFunctions.h
vendored
Normal file
53
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/RelocationHelperFunctions.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//===- 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
|
||||||
204
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/Simple.h
vendored
Normal file
204
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/Simple.h
vendored
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
//===- 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
|
||||||
52
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/Writer.h
vendored
Normal file
52
external/bsd/llvm/dist/lld/include/lld/ReaderWriter/Writer.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
//===- 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
|
||||||
4
external/bsd/llvm/dist/lld/lib/CMakeLists.txt
vendored
Normal file
4
external/bsd/llvm/dist/lld/lib/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
add_subdirectory(Core)
|
||||||
|
add_subdirectory(Driver)
|
||||||
|
add_subdirectory(Passes)
|
||||||
|
add_subdirectory(ReaderWriter)
|
||||||
17
external/bsd/llvm/dist/lld/lib/Core/CMakeLists.txt
vendored
Normal file
17
external/bsd/llvm/dist/lld/lib/Core/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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
|
||||||
|
)
|
||||||
84
external/bsd/llvm/dist/lld/lib/Core/DefinedAtom.cpp
vendored
Normal file
84
external/bsd/llvm/dist/lld/lib/Core/DefinedAtom.cpp
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
//===- 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
|
||||||
|
|
||||||
129
external/bsd/llvm/dist/lld/lib/Core/Error.cpp
vendored
Normal file
129
external/bsd/llvm/dist/lld/lib/Core/Error.cpp
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
//===- 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;
|
||||||
|
}
|
||||||
30
external/bsd/llvm/dist/lld/lib/Core/File.cpp
vendored
Normal file
30
external/bsd/llvm/dist/lld/lib/Core/File.cpp
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
//===- 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
|
||||||
178
external/bsd/llvm/dist/lld/lib/Core/InputGraph.cpp
vendored
Normal file
178
external/bsd/llvm/dist/lld/lib/Core/InputGraph.cpp
vendored
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
//===- 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
113
external/bsd/llvm/dist/lld/lib/Core/LinkingContext.cpp
vendored
Normal file
113
external/bsd/llvm/dist/lld/lib/Core/LinkingContext.cpp
vendored
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
//===- 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
|
||||||
24
external/bsd/llvm/dist/lld/lib/Core/PassManager.cpp
vendored
Normal file
24
external/bsd/llvm/dist/lld/lib/Core/PassManager.cpp
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
//===- 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
|
||||||
493
external/bsd/llvm/dist/lld/lib/Core/Resolver.cpp
vendored
Normal file
493
external/bsd/llvm/dist/lld/lib/Core/Resolver.cpp
vendored
Normal file
@@ -0,0 +1,493 @@
|
|||||||
|
//===- 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
|
||||||
364
external/bsd/llvm/dist/lld/lib/Core/SymbolTable.cpp
vendored
Normal file
364
external/bsd/llvm/dist/lld/lib/Core/SymbolTable.cpp
vendored
Normal file
@@ -0,0 +1,364 @@
|
|||||||
|
//===- 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
|
||||||
18
external/bsd/llvm/dist/lld/lib/Core/TODO.txt
vendored
Normal file
18
external/bsd/llvm/dist/lld/lib/Core/TODO.txt
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
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.
|
||||||
|
|
||||||
36
external/bsd/llvm/dist/lld/lib/Driver/CMakeLists.txt
vendored
Normal file
36
external/bsd/llvm/dist/lld/lib/Driver/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
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
|
||||||
|
)
|
||||||
159
external/bsd/llvm/dist/lld/lib/Driver/CoreDriver.cpp
vendored
Normal file
159
external/bsd/llvm/dist/lld/lib/Driver/CoreDriver.cpp
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
//===- 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
|
||||||
15
external/bsd/llvm/dist/lld/lib/Driver/CoreOptions.td
vendored
Normal file
15
external/bsd/llvm/dist/lld/lib/Driver/CoreOptions.td
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
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">;
|
||||||
|
|
||||||
267
external/bsd/llvm/dist/lld/lib/Driver/DarwinLdDriver.cpp
vendored
Normal file
267
external/bsd/llvm/dist/lld/lib/Driver/DarwinLdDriver.cpp
vendored
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
//===- 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
|
||||||
79
external/bsd/llvm/dist/lld/lib/Driver/DarwinLdOptions.td
vendored
Normal file
79
external/bsd/llvm/dist/lld/lib/Driver/DarwinLdOptions.td
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
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">;
|
||||||
137
external/bsd/llvm/dist/lld/lib/Driver/Driver.cpp
vendored
Normal file
137
external/bsd/llvm/dist/lld/lib/Driver/Driver.cpp
vendored
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
//===- 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
|
||||||
362
external/bsd/llvm/dist/lld/lib/Driver/GnuLdDriver.cpp
vendored
Normal file
362
external/bsd/llvm/dist/lld/lib/Driver/GnuLdDriver.cpp
vendored
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
//===- 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());
|
||||||
|
}
|
||||||
240
external/bsd/llvm/dist/lld/lib/Driver/GnuLdOptions.td
vendored
Normal file
240
external/bsd/llvm/dist/lld/lib/Driver/GnuLdOptions.td
vendored
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
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">;
|
||||||
|
|
||||||
183
external/bsd/llvm/dist/lld/lib/Driver/UniversalDriver.cpp
vendored
Normal file
183
external/bsd/llvm/dist/lld/lib/Driver/UniversalDriver.cpp
vendored
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
//===- 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
|
||||||
16
external/bsd/llvm/dist/lld/lib/Driver/UniversalDriverOptions.td
vendored
Normal file
16
external/bsd/llvm/dist/lld/lib/Driver/UniversalDriverOptions.td
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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">;
|
||||||
976
external/bsd/llvm/dist/lld/lib/Driver/WinLinkDriver.cpp
vendored
Normal file
976
external/bsd/llvm/dist/lld/lib/Driver/WinLinkDriver.cpp
vendored
Normal file
@@ -0,0 +1,976 @@
|
|||||||
|
//===- 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 §ion,
|
||||||
|
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
|
||||||
103
external/bsd/llvm/dist/lld/lib/Driver/WinLinkOptions.td
vendored
Normal file
103
external/bsd/llvm/dist/lld/lib/Driver/WinLinkOptions.td
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
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">;
|
||||||
9
external/bsd/llvm/dist/lld/lib/Passes/CMakeLists.txt
vendored
Normal file
9
external/bsd/llvm/dist/lld/lib/Passes/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
add_lld_library(lldPasses
|
||||||
|
GOTPass.cpp
|
||||||
|
StubsPass.cpp
|
||||||
|
LayoutPass.cpp
|
||||||
|
RoundTripNativePass.cpp
|
||||||
|
RoundTripYAMLPass.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(lldPasses lldReaderWriter)
|
||||||
108
external/bsd/llvm/dist/lld/lib/Passes/GOTPass.cpp
vendored
Normal file
108
external/bsd/llvm/dist/lld/lib/Passes/GOTPass.cpp
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
//===- Passes/GOTPass.cpp - Adds GOT entries ------------------------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Linker
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// This linker pass transforms all GOT kind references to real references.
|
||||||
|
/// That is, in assembly you can write something like:
|
||||||
|
/// movq foo@GOTPCREL(%rip), %rax
|
||||||
|
/// which means you want to load a pointer to "foo" out of the GOT (global
|
||||||
|
/// Offsets Table). In the object file, the Atom containing this instruction
|
||||||
|
/// has a Reference whose target is an Atom named "foo" and the Reference
|
||||||
|
/// kind is a GOT load. The linker needs to instantiate a pointer sized
|
||||||
|
/// GOT entry. This is done be creating a GOT Atom to represent that pointer
|
||||||
|
/// sized data in this pass, and altering the Atom graph so the Reference now
|
||||||
|
/// points to the GOT Atom entry (corresponding to "foo") and changing the
|
||||||
|
/// Reference Kind to reflect it is now pointing to a GOT entry (rather
|
||||||
|
/// then needing a GOT entry).
|
||||||
|
///
|
||||||
|
/// There is one optimization the linker can do here. If the target of the GOT
|
||||||
|
/// is in the same linkage unit and does not need to be interposable, and
|
||||||
|
/// the GOT use is just a load (not some other operation), this pass can
|
||||||
|
/// transform that load into an LEA (add). This optimizes away one memory load
|
||||||
|
/// which at runtime that could stall the pipeline. This optimization only
|
||||||
|
/// works for architectures in which a (GOT) load instruction can be change to
|
||||||
|
/// an LEA instruction that is the same size. The method isGOTAccess() should
|
||||||
|
/// only return true for "canBypassGOT" if this optimization is supported.
|
||||||
|
///
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "lld/Core/DefinedAtom.h"
|
||||||
|
#include "lld/Core/File.h"
|
||||||
|
#include "lld/Core/LLVM.h"
|
||||||
|
#include "lld/Core/Pass.h"
|
||||||
|
#include "lld/Core/Reference.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
|
||||||
|
namespace lld {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool shouldReplaceTargetWithGOTAtom(const Atom *target, bool canBypassGOT) {
|
||||||
|
// Accesses to shared library symbols must go through GOT.
|
||||||
|
if (target->definition() == Atom::definitionSharedLibrary)
|
||||||
|
return true;
|
||||||
|
// Accesses to interposable symbols in same linkage unit must also go
|
||||||
|
// through GOT.
|
||||||
|
const DefinedAtom *defTarget = dyn_cast<DefinedAtom>(target);
|
||||||
|
if (defTarget != nullptr &&
|
||||||
|
defTarget->interposable() != DefinedAtom::interposeNo) {
|
||||||
|
assert(defTarget->scope() != DefinedAtom::scopeTranslationUnit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Target does not require indirection. So, if instruction allows GOT to be
|
||||||
|
// by-passed, do that optimization and don't create GOT entry.
|
||||||
|
return !canBypassGOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DefinedAtom *
|
||||||
|
findGOTAtom(const Atom *target,
|
||||||
|
llvm::DenseMap<const Atom *, const DefinedAtom *> &targetToGOT) {
|
||||||
|
auto pos = targetToGOT.find(target);
|
||||||
|
return (pos == targetToGOT.end()) ? nullptr : pos->second;
|
||||||
|
}
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
void GOTPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
|
||||||
|
// Use map so all pointers to same symbol use same GOT entry.
|
||||||
|
llvm::DenseMap<const Atom*, const DefinedAtom*> targetToGOT;
|
||||||
|
|
||||||
|
// Scan all references in all atoms.
|
||||||
|
for (const DefinedAtom *atom : mergedFile->defined()) {
|
||||||
|
for (const Reference *ref : *atom) {
|
||||||
|
// Look at instructions accessing the GOT.
|
||||||
|
bool canBypassGOT;
|
||||||
|
if (!isGOTAccess(ref->kind(), canBypassGOT))
|
||||||
|
continue;
|
||||||
|
const Atom *target = ref->target();
|
||||||
|
assert(target != nullptr);
|
||||||
|
|
||||||
|
if (!shouldReplaceTargetWithGOTAtom(target, canBypassGOT)) {
|
||||||
|
// Update reference kind to reflect that target is a direct accesss.
|
||||||
|
updateReferenceToGOT(ref, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Replace the target with a reference to a GOT entry.
|
||||||
|
const DefinedAtom *gotEntry = findGOTAtom(target, targetToGOT);
|
||||||
|
if (!gotEntry) {
|
||||||
|
gotEntry = makeGOTEntry(*target);
|
||||||
|
assert(gotEntry != nullptr);
|
||||||
|
assert(gotEntry->contentType() == DefinedAtom::typeGOT);
|
||||||
|
targetToGOT[target] = gotEntry;
|
||||||
|
}
|
||||||
|
const_cast<Reference *>(ref)->setTarget(gotEntry);
|
||||||
|
// Update reference kind to reflect that target is now a GOT entry.
|
||||||
|
updateReferenceToGOT(ref, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add all created GOT Atoms to master file
|
||||||
|
for (auto &it : targetToGOT) {
|
||||||
|
mergedFile->addAtom(*it.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
569
external/bsd/llvm/dist/lld/lib/Passes/LayoutPass.cpp
vendored
Normal file
569
external/bsd/llvm/dist/lld/lib/Passes/LayoutPass.cpp
vendored
Normal file
@@ -0,0 +1,569 @@
|
|||||||
|
//===--Passes/LayoutPass.cpp - Layout atoms -------------------------------===//
|
||||||
|
//
|
||||||
|
// The LLVM Linker
|
||||||
|
//
|
||||||
|
// This file is distributed under the University of Illinois Open Source
|
||||||
|
// License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "LayoutPass"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "lld/Passes/LayoutPass.h"
|
||||||
|
#include "lld/Core/Instrumentation.h"
|
||||||
|
|
||||||
|
#include "llvm/ADT/Twine.h"
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
|
|
||||||
|
using namespace lld;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
namespace {
|
||||||
|
// Return "reason (leftval, rightval)"
|
||||||
|
std::string formatReason(StringRef reason, int leftVal, int rightVal) {
|
||||||
|
Twine msg =
|
||||||
|
Twine(reason) + " (" + Twine(leftVal) + ", " + Twine(rightVal) + ")";
|
||||||
|
return msg.str();
|
||||||
|
}
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
// Less-than relationship of two atoms must be transitive, which is, if a < b
|
||||||
|
// and b < c, a < c must be true. This function checks the transitivity by
|
||||||
|
// checking the sort results.
|
||||||
|
void LayoutPass::checkTransitivity(DefinedAtomIter begin,
|
||||||
|
DefinedAtomIter end) const {
|
||||||
|
for (DefinedAtomIter i = begin; (i + 1) != end; ++i) {
|
||||||
|
for (DefinedAtomIter j = i + 1; j != end; ++j) {
|
||||||
|
assert(_compareAtoms(*i, *j));
|
||||||
|
assert(!_compareAtoms(*j, *i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
/// The function compares atoms by sorting atoms in the following order
|
||||||
|
/// a) Sorts atoms by Section position preference
|
||||||
|
/// b) Sorts atoms by their ordinal overrides
|
||||||
|
/// (layout-after/layout-before/ingroup)
|
||||||
|
/// c) Sorts atoms by their permissions
|
||||||
|
/// d) Sorts atoms by their content
|
||||||
|
/// e) Sorts atoms on how they appear using File Ordinality
|
||||||
|
/// f) Sorts atoms on how they appear within the File
|
||||||
|
bool LayoutPass::CompareAtoms::compare(const DefinedAtom *left,
|
||||||
|
const DefinedAtom *right,
|
||||||
|
std::string &reason) const {
|
||||||
|
if (left == right) {
|
||||||
|
reason = "same";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by section position preference.
|
||||||
|
DefinedAtom::SectionPosition leftPos = left->sectionPosition();
|
||||||
|
DefinedAtom::SectionPosition rightPos = right->sectionPosition();
|
||||||
|
|
||||||
|
bool leftSpecialPos = (leftPos != DefinedAtom::sectionPositionAny);
|
||||||
|
bool rightSpecialPos = (rightPos != DefinedAtom::sectionPositionAny);
|
||||||
|
if (leftSpecialPos || rightSpecialPos) {
|
||||||
|
if (leftPos != rightPos) {
|
||||||
|
DEBUG(reason = formatReason("sectionPos", (int)leftPos, (int)rightPos));
|
||||||
|
return leftPos < rightPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the root of the chain if it is a part of a follow-on chain.
|
||||||
|
auto leftFind = _layout._followOnRoots.find(left);
|
||||||
|
auto rightFind = _layout._followOnRoots.find(right);
|
||||||
|
const DefinedAtom *leftRoot =
|
||||||
|
(leftFind == _layout._followOnRoots.end()) ? left : leftFind->second;
|
||||||
|
const DefinedAtom *rightRoot =
|
||||||
|
(rightFind == _layout._followOnRoots.end()) ? right : rightFind->second;
|
||||||
|
|
||||||
|
// Sort atoms by their ordinal overrides only if they fall in the same
|
||||||
|
// chain.
|
||||||
|
AtomToOrdinalT::const_iterator lPos = _layout._ordinalOverrideMap.find(left);
|
||||||
|
AtomToOrdinalT::const_iterator rPos = _layout._ordinalOverrideMap.find(right);
|
||||||
|
AtomToOrdinalT::const_iterator end = _layout._ordinalOverrideMap.end();
|
||||||
|
if (leftRoot == rightRoot && lPos != end && rPos != end) {
|
||||||
|
DEBUG(reason = formatReason("override", lPos->second, rPos->second));
|
||||||
|
return lPos->second < rPos->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort same permissions together.
|
||||||
|
DefinedAtom::ContentPermissions leftPerms = leftRoot->permissions();
|
||||||
|
DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions();
|
||||||
|
|
||||||
|
if (leftPerms != rightPerms) {
|
||||||
|
DEBUG(reason =
|
||||||
|
formatReason("contentPerms", (int)leftPerms, (int)rightPerms));
|
||||||
|
return leftPerms < rightPerms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort same content types together.
|
||||||
|
DefinedAtom::ContentType leftType = leftRoot->contentType();
|
||||||
|
DefinedAtom::ContentType rightType = rightRoot->contentType();
|
||||||
|
|
||||||
|
if (leftType != rightType) {
|
||||||
|
DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType));
|
||||||
|
return leftType < rightType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by .o order.
|
||||||
|
const File *leftFile = &leftRoot->file();
|
||||||
|
const File *rightFile = &rightRoot->file();
|
||||||
|
|
||||||
|
if (leftFile != rightFile) {
|
||||||
|
DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(),
|
||||||
|
(int)rightFile->ordinal()));
|
||||||
|
return leftFile->ordinal() < rightFile->ordinal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by atom order with .o file.
|
||||||
|
uint64_t leftOrdinal = leftRoot->ordinal();
|
||||||
|
uint64_t rightOrdinal = rightRoot->ordinal();
|
||||||
|
|
||||||
|
if (leftOrdinal != rightOrdinal) {
|
||||||
|
DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(),
|
||||||
|
(int)rightRoot->ordinal()));
|
||||||
|
return leftOrdinal < rightOrdinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(llvm::dbgs() << "Unordered\n");
|
||||||
|
llvm_unreachable("Atoms with Same Ordinal!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayoutPass::CompareAtoms::operator()(const DefinedAtom *left,
|
||||||
|
const DefinedAtom *right) const {
|
||||||
|
std::string reason;
|
||||||
|
bool result = compare(left, right, reason);
|
||||||
|
DEBUG({
|
||||||
|
StringRef comp = result ? "<" : ">=";
|
||||||
|
llvm::dbgs() << "Layout: '" << left->name() << "' " << comp << " '"
|
||||||
|
<< right->name() << "' (" << reason << ")\n";
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the atom immediately followed by the given atom in the followon
|
||||||
|
// chain.
|
||||||
|
const DefinedAtom *LayoutPass::findAtomFollowedBy(
|
||||||
|
const DefinedAtom *targetAtom) {
|
||||||
|
// Start from the beginning of the chain and follow the chain until
|
||||||
|
// we find the targetChain.
|
||||||
|
const DefinedAtom *atom = _followOnRoots[targetAtom];
|
||||||
|
while (true) {
|
||||||
|
const DefinedAtom *prevAtom = atom;
|
||||||
|
AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
|
||||||
|
// The target atom must be in the chain of its root.
|
||||||
|
assert(targetFollowOnAtomsIter != _followOnNexts.end());
|
||||||
|
atom = targetFollowOnAtomsIter->second;
|
||||||
|
if (atom == targetAtom)
|
||||||
|
return prevAtom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if all the atoms followed by the given target atom are of size zero.
|
||||||
|
// When this method is called, an atom being added is not of size zero and
|
||||||
|
// will be added to the head of the followon chain. All the atoms between the
|
||||||
|
// atom and the targetAtom (specified by layout-after) need to be of size zero
|
||||||
|
// in this case. Otherwise the desired layout is impossible.
|
||||||
|
bool LayoutPass::checkAllPrevAtomsZeroSize(const DefinedAtom *targetAtom) {
|
||||||
|
const DefinedAtom *atom = _followOnRoots[targetAtom];
|
||||||
|
while (true) {
|
||||||
|
if (atom == targetAtom)
|
||||||
|
return true;
|
||||||
|
if (atom->size() != 0)
|
||||||
|
// TODO: print warning that an impossible layout is being desired by the
|
||||||
|
// user.
|
||||||
|
return false;
|
||||||
|
AtomToAtomT::iterator targetFollowOnAtomsIter = _followOnNexts.find(atom);
|
||||||
|
// The target atom must be in the chain of its root.
|
||||||
|
assert(targetFollowOnAtomsIter != _followOnNexts.end());
|
||||||
|
atom = targetFollowOnAtomsIter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the root of all atoms in targetAtom's chain to the given root.
|
||||||
|
void LayoutPass::setChainRoot(const DefinedAtom *targetAtom,
|
||||||
|
const DefinedAtom *root) {
|
||||||
|
// Walk through the followon chain and override each node's root.
|
||||||
|
while (true) {
|
||||||
|
_followOnRoots[targetAtom] = root;
|
||||||
|
AtomToAtomT::iterator targetFollowOnAtomsIter =
|
||||||
|
_followOnNexts.find(targetAtom);
|
||||||
|
if (targetFollowOnAtomsIter == _followOnNexts.end())
|
||||||
|
return;
|
||||||
|
targetAtom = targetFollowOnAtomsIter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This pass builds the followon tables described by two DenseMaps
|
||||||
|
/// followOnRoots and followonNexts.
|
||||||
|
/// The followOnRoots map contains a mapping of a DefinedAtom to its root
|
||||||
|
/// The followOnNexts map contains a mapping of what DefinedAtom follows the
|
||||||
|
/// current Atom
|
||||||
|
/// The algorithm follows a very simple approach
|
||||||
|
/// a) If the atom is first seen, then make that as the root atom
|
||||||
|
/// b) The targetAtom which this Atom contains, has the root thats set to the
|
||||||
|
/// root of the current atom
|
||||||
|
/// c) If the targetAtom is part of a different tree and the root of the
|
||||||
|
/// targetAtom is itself, Chain all the atoms that are contained in the tree
|
||||||
|
/// to the current Tree
|
||||||
|
/// d) If the targetAtom is part of a different chain and the root of the
|
||||||
|
/// targetAtom until the targetAtom has all atoms of size 0, then chain the
|
||||||
|
/// targetAtoms and its tree to the current chain
|
||||||
|
void LayoutPass::buildFollowOnTable(MutableFile::DefinedAtomRange &range) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "LayoutPass::buildFollowOnTable");
|
||||||
|
// Set the initial size of the followon and the followonNext hash to the
|
||||||
|
// number of atoms that we have.
|
||||||
|
_followOnRoots.resize(range.size());
|
||||||
|
_followOnNexts.resize(range.size());
|
||||||
|
for (const DefinedAtom *ai : range) {
|
||||||
|
for (const Reference *r : *ai) {
|
||||||
|
if (r->kind() != lld::Reference::kindLayoutAfter)
|
||||||
|
continue;
|
||||||
|
const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
|
||||||
|
_followOnNexts[ai] = targetAtom;
|
||||||
|
|
||||||
|
// If we find a followon for the first time, lets make that atom as the
|
||||||
|
// root atom.
|
||||||
|
if (_followOnRoots.count(ai) == 0)
|
||||||
|
_followOnRoots[ai] = ai;
|
||||||
|
|
||||||
|
auto iter = _followOnRoots.find(targetAtom);
|
||||||
|
if (iter == _followOnRoots.end()) {
|
||||||
|
// If the targetAtom is not a root of any chain, lets make the root of
|
||||||
|
// the targetAtom to the root of the current chain.
|
||||||
|
_followOnRoots[targetAtom] = _followOnRoots[ai];
|
||||||
|
} else if (iter->second == targetAtom) {
|
||||||
|
// If the targetAtom is the root of a chain, the chain becomes part of
|
||||||
|
// the current chain. Rewrite the subchain's root to the current
|
||||||
|
// chain's root.
|
||||||
|
setChainRoot(targetAtom, _followOnRoots[ai]);
|
||||||
|
} else {
|
||||||
|
// The targetAtom is already a part of a chain. If the current atom is
|
||||||
|
// of size zero, we can insert it in the middle of the chain just
|
||||||
|
// before the target atom, while not breaking other atom's followon
|
||||||
|
// relationships. If it's not, we can only insert the current atom at
|
||||||
|
// the beginning of the chain. All the atoms followed by the target
|
||||||
|
// atom must be of size zero in that case to satisfy the followon
|
||||||
|
// relationships.
|
||||||
|
size_t currentAtomSize = ai->size();
|
||||||
|
if (currentAtomSize == 0) {
|
||||||
|
const DefinedAtom *targetPrevAtom = findAtomFollowedBy(targetAtom);
|
||||||
|
_followOnNexts[targetPrevAtom] = ai;
|
||||||
|
_followOnRoots[ai] = _followOnRoots[targetPrevAtom];
|
||||||
|
} else {
|
||||||
|
if (!checkAllPrevAtomsZeroSize(targetAtom))
|
||||||
|
break;
|
||||||
|
_followOnNexts[ai] = _followOnRoots[targetAtom];
|
||||||
|
setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This pass builds the followon tables using InGroup relationships
|
||||||
|
/// The algorithm follows a very simple approach
|
||||||
|
/// a) If the rootAtom is not part of any root, create a new root with the
|
||||||
|
/// as the head
|
||||||
|
/// b) If the current Atom root is not found, then make the current atoms root
|
||||||
|
/// point to the rootAtom
|
||||||
|
/// c) If the root of the current Atom is itself a root of some other tree
|
||||||
|
/// make all the atoms in the chain point to the ingroup reference
|
||||||
|
/// d) Check to see if the current atom is part of the chain from the rootAtom
|
||||||
|
/// if not add the atom to the chain, so that the current atom is part of the
|
||||||
|
/// the chain where the rootAtom is in
|
||||||
|
void LayoutPass::buildInGroupTable(MutableFile::DefinedAtomRange &range) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "LayoutPass::buildInGroupTable");
|
||||||
|
// This table would convert precededby references to follow on
|
||||||
|
// references so that we have only one table
|
||||||
|
for (const DefinedAtom *ai : range) {
|
||||||
|
for (const Reference *r : *ai) {
|
||||||
|
if (r->kind() == lld::Reference::kindInGroup) {
|
||||||
|
const DefinedAtom *rootAtom = dyn_cast<DefinedAtom>(r->target());
|
||||||
|
// If the root atom is not part of any root
|
||||||
|
// create a new root
|
||||||
|
if (_followOnRoots.count(rootAtom) == 0) {
|
||||||
|
_followOnRoots[rootAtom] = rootAtom;
|
||||||
|
}
|
||||||
|
// If the current Atom has not been seen yet and there is no root
|
||||||
|
// that has been set, set the root of the atom to the targetAtom
|
||||||
|
// as the targetAtom points to the ingroup root
|
||||||
|
auto iter = _followOnRoots.find(ai);
|
||||||
|
if (iter == _followOnRoots.end()) {
|
||||||
|
_followOnRoots[ai] = rootAtom;
|
||||||
|
} else if (iter->second == ai) {
|
||||||
|
if (iter->second != rootAtom)
|
||||||
|
setChainRoot(iter->second, rootAtom);
|
||||||
|
} else {
|
||||||
|
// TODO : Flag an error that the root of the tree
|
||||||
|
// is different, Here is an example
|
||||||
|
// Say there are atoms
|
||||||
|
// chain 1 : a->b->c
|
||||||
|
// chain 2 : d->e->f
|
||||||
|
// and e,f have their ingroup reference as a
|
||||||
|
// this could happen only if the root of e,f that is d
|
||||||
|
// has root as 'a'
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the current atom is part of the chain
|
||||||
|
bool isAtomInChain = false;
|
||||||
|
const DefinedAtom *lastAtom = rootAtom;
|
||||||
|
while (true) {
|
||||||
|
AtomToAtomT::iterator followOnAtomsIter =
|
||||||
|
_followOnNexts.find(lastAtom);
|
||||||
|
if (followOnAtomsIter != _followOnNexts.end()) {
|
||||||
|
lastAtom = followOnAtomsIter->second;
|
||||||
|
if (lastAtom == ai) {
|
||||||
|
isAtomInChain = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
} // findAtomInChain
|
||||||
|
|
||||||
|
if (!isAtomInChain)
|
||||||
|
_followOnNexts[lastAtom] = ai;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This pass builds the followon tables using Preceded By relationships
|
||||||
|
/// The algorithm follows a very simple approach
|
||||||
|
/// a) If the targetAtom is not part of any root and the current atom is not
|
||||||
|
/// part of any root, create a chain with the current atom as root and
|
||||||
|
/// the targetAtom as following the current atom
|
||||||
|
/// b) Chain the targetAtom to the current Atom if the targetAtom is not part
|
||||||
|
/// of any chain and the currentAtom has no followOn's
|
||||||
|
/// c) If the targetAtom is part of a different tree and the root of the
|
||||||
|
/// targetAtom is itself, and if the current atom is not part of any root
|
||||||
|
/// chain all the atoms together
|
||||||
|
/// d) If the current atom has no followon and the root of the targetAtom is
|
||||||
|
/// not equal to the root of the current atom(the targetAtom is not in the
|
||||||
|
/// same chain), chain all the atoms that are lead by the targetAtom into
|
||||||
|
/// the current chain
|
||||||
|
void LayoutPass::buildPrecededByTable(MutableFile::DefinedAtomRange &range) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "LayoutPass::buildPrecededByTable");
|
||||||
|
// This table would convert precededby references to follow on
|
||||||
|
// references so that we have only one table
|
||||||
|
for (const DefinedAtom *ai : range) {
|
||||||
|
for (const Reference *r : *ai) {
|
||||||
|
if (r->kind() == lld::Reference::kindLayoutBefore) {
|
||||||
|
const DefinedAtom *targetAtom = dyn_cast<DefinedAtom>(r->target());
|
||||||
|
// Is the targetAtom not chained
|
||||||
|
if (_followOnRoots.count(targetAtom) == 0) {
|
||||||
|
// Is the current atom not part of any root ?
|
||||||
|
if (_followOnRoots.count(ai) == 0) {
|
||||||
|
_followOnRoots[ai] = ai;
|
||||||
|
_followOnNexts[ai] = targetAtom;
|
||||||
|
_followOnRoots[targetAtom] = _followOnRoots[ai];
|
||||||
|
} else if (_followOnNexts.count(ai) == 0) {
|
||||||
|
// Chain the targetAtom to the current Atom
|
||||||
|
// if the currentAtom has no followon references
|
||||||
|
_followOnNexts[ai] = targetAtom;
|
||||||
|
_followOnRoots[targetAtom] = _followOnRoots[ai];
|
||||||
|
}
|
||||||
|
} else if (_followOnRoots.find(targetAtom)->second == targetAtom) {
|
||||||
|
// Is the targetAtom in chain with the targetAtom as the root ?
|
||||||
|
bool changeRoots = false;
|
||||||
|
if (_followOnRoots.count(ai) == 0) {
|
||||||
|
_followOnRoots[ai] = ai;
|
||||||
|
_followOnNexts[ai] = targetAtom;
|
||||||
|
_followOnRoots[targetAtom] = _followOnRoots[ai];
|
||||||
|
changeRoots = true;
|
||||||
|
} else if (_followOnNexts.count(ai) == 0) {
|
||||||
|
// Chain the targetAtom to the current Atom
|
||||||
|
// if the currentAtom has no followon references
|
||||||
|
if (_followOnRoots[ai] != _followOnRoots[targetAtom]) {
|
||||||
|
_followOnNexts[ai] = targetAtom;
|
||||||
|
_followOnRoots[targetAtom] = _followOnRoots[ai];
|
||||||
|
changeRoots = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Change the roots of the targetAtom and its chain to
|
||||||
|
// the current atoms root
|
||||||
|
if (changeRoots) {
|
||||||
|
setChainRoot(_followOnRoots[targetAtom], _followOnRoots[ai]);
|
||||||
|
}
|
||||||
|
} // Is targetAtom root
|
||||||
|
} // kindLayoutBefore
|
||||||
|
} // Reference
|
||||||
|
} // atom iteration
|
||||||
|
} // end function
|
||||||
|
|
||||||
|
|
||||||
|
/// Build an ordinal override map by traversing the followon chain, and
|
||||||
|
/// assigning ordinals to each atom, if the atoms have their ordinals
|
||||||
|
/// already assigned skip the atom and move to the next. This is the
|
||||||
|
/// main map thats used to sort the atoms while comparing two atoms together
|
||||||
|
void LayoutPass::buildOrdinalOverrideMap(MutableFile::DefinedAtomRange &range) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "LayoutPass::buildOrdinalOverrideMap");
|
||||||
|
uint64_t index = 0;
|
||||||
|
for (const DefinedAtom *ai : range) {
|
||||||
|
const DefinedAtom *atom = ai;
|
||||||
|
if (_ordinalOverrideMap.find(atom) != _ordinalOverrideMap.end())
|
||||||
|
continue;
|
||||||
|
AtomToAtomT::iterator start = _followOnRoots.find(atom);
|
||||||
|
if (start != _followOnRoots.end()) {
|
||||||
|
for (const DefinedAtom *nextAtom = start->second; nextAtom != NULL;
|
||||||
|
nextAtom = _followOnNexts[nextAtom]) {
|
||||||
|
AtomToOrdinalT::iterator pos = _ordinalOverrideMap.find(nextAtom);
|
||||||
|
if (pos == _ordinalOverrideMap.end()) {
|
||||||
|
_ordinalOverrideMap[nextAtom] = index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions to check follow-on graph.
|
||||||
|
#ifndef NDEBUG
|
||||||
|
namespace {
|
||||||
|
typedef llvm::DenseMap<const DefinedAtom *, const DefinedAtom *> AtomToAtomT;
|
||||||
|
|
||||||
|
std::string atomToDebugString(const Atom *atom) {
|
||||||
|
const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom);
|
||||||
|
std::string str;
|
||||||
|
llvm::raw_string_ostream s(str);
|
||||||
|
if (definedAtom->name().empty())
|
||||||
|
s << "<anonymous " << definedAtom << ">";
|
||||||
|
else
|
||||||
|
s << definedAtom->name();
|
||||||
|
s << " in ";
|
||||||
|
if (definedAtom->customSectionName().empty())
|
||||||
|
s << "<anonymous>";
|
||||||
|
else
|
||||||
|
s << definedAtom->customSectionName();
|
||||||
|
s.flush();
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void showCycleDetectedError(AtomToAtomT &followOnNexts,
|
||||||
|
const DefinedAtom *atom) {
|
||||||
|
const DefinedAtom *start = atom;
|
||||||
|
llvm::dbgs() << "There's a cycle in a follow-on chain!\n";
|
||||||
|
do {
|
||||||
|
llvm::dbgs() << " " << atomToDebugString(atom) << "\n";
|
||||||
|
for (const Reference *ref : *atom) {
|
||||||
|
llvm::dbgs() << " " << ref->kindToString()
|
||||||
|
<< ": " << atomToDebugString(ref->target()) << "\n";
|
||||||
|
}
|
||||||
|
atom = followOnNexts[atom];
|
||||||
|
} while (atom != start);
|
||||||
|
llvm::report_fatal_error("Cycle detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Exit if there's a cycle in a followon chain reachable from the
|
||||||
|
/// given root atom. Uses the tortoise and hare algorithm to detect a
|
||||||
|
/// cycle.
|
||||||
|
void checkNoCycleInFollowonChain(AtomToAtomT &followOnNexts,
|
||||||
|
const DefinedAtom *root) {
|
||||||
|
const DefinedAtom *tortoise = root;
|
||||||
|
const DefinedAtom *hare = followOnNexts[root];
|
||||||
|
while (true) {
|
||||||
|
if (!tortoise || !hare)
|
||||||
|
return;
|
||||||
|
if (tortoise == hare)
|
||||||
|
showCycleDetectedError(followOnNexts, tortoise);
|
||||||
|
tortoise = followOnNexts[tortoise];
|
||||||
|
hare = followOnNexts[followOnNexts[hare]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkReachabilityFromRoot(AtomToAtomT &followOnRoots,
|
||||||
|
const DefinedAtom *atom) {
|
||||||
|
if (!atom) return;
|
||||||
|
auto i = followOnRoots.find(atom);
|
||||||
|
if (i == followOnRoots.end()) {
|
||||||
|
Twine msg(Twine("Atom <") + atomToDebugString(atom)
|
||||||
|
+ "> has no follow-on root!");
|
||||||
|
llvm_unreachable(msg.str().c_str());
|
||||||
|
}
|
||||||
|
const DefinedAtom *ap = i->second;
|
||||||
|
while (true) {
|
||||||
|
const DefinedAtom *next = followOnRoots[ap];
|
||||||
|
if (!next) {
|
||||||
|
Twine msg(Twine("Atom <" + atomToDebugString(atom)
|
||||||
|
+ "> is not reachable from its root!"));
|
||||||
|
llvm_unreachable(msg.str().c_str());
|
||||||
|
}
|
||||||
|
if (next == ap)
|
||||||
|
return;
|
||||||
|
ap = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printDefinedAtoms(const MutableFile::DefinedAtomRange &atomRange) {
|
||||||
|
for (const DefinedAtom *atom : atomRange) {
|
||||||
|
llvm::dbgs() << " file=" << atom->file().path()
|
||||||
|
<< ", name=" << atom->name()
|
||||||
|
<< ", size=" << atom->size()
|
||||||
|
<< ", type=" << atom->contentType()
|
||||||
|
<< ", ordinal=" << atom->ordinal()
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
/// Verify that the followon chain is sane. Should not be called in
|
||||||
|
/// release binary.
|
||||||
|
void LayoutPass::checkFollowonChain(MutableFile::DefinedAtomRange &range) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "LayoutPass::checkFollowonChain");
|
||||||
|
|
||||||
|
// Verify that there's no cycle in follow-on chain.
|
||||||
|
std::set<const DefinedAtom *> roots;
|
||||||
|
for (const auto &ai : _followOnRoots)
|
||||||
|
roots.insert(ai.second);
|
||||||
|
for (const DefinedAtom *root : roots)
|
||||||
|
checkNoCycleInFollowonChain(_followOnNexts, root);
|
||||||
|
|
||||||
|
// Verify that all the atoms in followOnNexts have references to
|
||||||
|
// their roots.
|
||||||
|
for (const auto &ai : _followOnNexts) {
|
||||||
|
checkReachabilityFromRoot(_followOnRoots, ai.first);
|
||||||
|
checkReachabilityFromRoot(_followOnRoots, ai.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // #ifndef NDEBUG
|
||||||
|
|
||||||
|
/// Perform the actual pass
|
||||||
|
void LayoutPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "LayoutPass");
|
||||||
|
MutableFile::DefinedAtomRange atomRange = mergedFile->definedAtoms();
|
||||||
|
|
||||||
|
// Build follow on tables
|
||||||
|
buildFollowOnTable(atomRange);
|
||||||
|
|
||||||
|
// Build Ingroup reference table
|
||||||
|
buildInGroupTable(atomRange);
|
||||||
|
|
||||||
|
// Build preceded by tables
|
||||||
|
buildPrecededByTable(atomRange);
|
||||||
|
|
||||||
|
// Check the structure of followon graph if running in debug mode.
|
||||||
|
DEBUG(checkFollowonChain(atomRange));
|
||||||
|
|
||||||
|
// Build override maps
|
||||||
|
buildOrdinalOverrideMap(atomRange);
|
||||||
|
|
||||||
|
DEBUG({
|
||||||
|
llvm::dbgs() << "unsorted atoms:\n";
|
||||||
|
printDefinedAtoms(atomRange);
|
||||||
|
});
|
||||||
|
|
||||||
|
// sort the atoms
|
||||||
|
std::sort(atomRange.begin(), atomRange.end(), _compareAtoms);
|
||||||
|
|
||||||
|
DEBUG(checkTransitivity(atomRange.begin(), atomRange.end()));
|
||||||
|
|
||||||
|
DEBUG({
|
||||||
|
llvm::dbgs() << "sorted atoms:\n";
|
||||||
|
printDefinedAtoms(atomRange);
|
||||||
|
});
|
||||||
|
}
|
||||||
48
external/bsd/llvm/dist/lld/lib/Passes/RoundTripNativePass.cpp
vendored
Normal file
48
external/bsd/llvm/dist/lld/lib/Passes/RoundTripNativePass.cpp
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
//===--Passes/RoundTripNativePass.cpp - 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.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "RoundTripNativePass"
|
||||||
|
|
||||||
|
#include "lld/Core/Instrumentation.h"
|
||||||
|
#include "lld/Passes/RoundTripNativePass.h"
|
||||||
|
#include "lld/ReaderWriter/Simple.h"
|
||||||
|
#include "lld/ReaderWriter/Writer.h"
|
||||||
|
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
|
#include "llvm/Support/Path.h"
|
||||||
|
|
||||||
|
using namespace lld;
|
||||||
|
|
||||||
|
/// Perform the actual pass
|
||||||
|
void RoundTripNativePass::perform(std::unique_ptr<MutableFile> &mergedFile) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "RoundTripNativePass");
|
||||||
|
std::unique_ptr<Writer> nativeWriter = createWriterNative(_context);
|
||||||
|
SmallString<128> tmpNativeFile;
|
||||||
|
// Separate the directory from the filename
|
||||||
|
StringRef outFile = llvm::sys::path::filename(_context.outputPath());
|
||||||
|
if (llvm::sys::fs::createTemporaryFile(outFile, "native", tmpNativeFile))
|
||||||
|
return;
|
||||||
|
DEBUG_WITH_TYPE("RoundTripNativePass", {
|
||||||
|
llvm::dbgs() << "RoundTripNativePass: " << tmpNativeFile << "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
// The file that is written would be kept around if there is a problem
|
||||||
|
// writing to the file or when reading atoms back from the file.
|
||||||
|
nativeWriter->writeFile(*mergedFile, tmpNativeFile.str());
|
||||||
|
OwningPtr<MemoryBuffer> buff;
|
||||||
|
if (MemoryBuffer::getFile(tmpNativeFile.str(), buff))
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::unique_ptr<MemoryBuffer> mb(buff.take());
|
||||||
|
_context.getNativeReader().parseFile(mb, _nativeFile);
|
||||||
|
|
||||||
|
mergedFile.reset(new FileToMutable(_context, *_nativeFile[0].get()));
|
||||||
|
|
||||||
|
llvm::sys::fs::remove(tmpNativeFile.str());
|
||||||
|
}
|
||||||
53
external/bsd/llvm/dist/lld/lib/Passes/RoundTripYAMLPass.cpp
vendored
Normal file
53
external/bsd/llvm/dist/lld/lib/Passes/RoundTripYAMLPass.cpp
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
//===--Passes/RoundTripYAMLPass.cpp - 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.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
#define DEBUG_TYPE "RoundTripYAMLPass"
|
||||||
|
|
||||||
|
#include "lld/Core/Instrumentation.h"
|
||||||
|
#include "lld/Passes/RoundTripYAMLPass.h"
|
||||||
|
#include "lld/ReaderWriter/Simple.h"
|
||||||
|
#include "lld/ReaderWriter/Writer.h"
|
||||||
|
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
|
#include "llvm/Support/Path.h"
|
||||||
|
|
||||||
|
// Skip YAML files larger than this to avoid OOM error. The YAML reader consumes
|
||||||
|
// excessively large amount of memory when parsing a large file.
|
||||||
|
// TODO: Fix the YAML reader to reduce memory footprint.
|
||||||
|
static const size_t MAX_YAML_FILE_SIZE = 50 * 1024 * 1024;
|
||||||
|
|
||||||
|
using namespace lld;
|
||||||
|
|
||||||
|
/// Perform the actual pass
|
||||||
|
void RoundTripYAMLPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
|
||||||
|
ScopedTask task(getDefaultDomain(), "RoundTripYAMLPass");
|
||||||
|
std::unique_ptr<Writer> yamlWriter = createWriterYAML(_context);
|
||||||
|
SmallString<128> tmpYAMLFile;
|
||||||
|
// Separate the directory from the filename
|
||||||
|
StringRef outFile = llvm::sys::path::filename(_context.outputPath());
|
||||||
|
if (llvm::sys::fs::createTemporaryFile(outFile, "yaml", tmpYAMLFile))
|
||||||
|
return;
|
||||||
|
DEBUG_WITH_TYPE("RoundTripYAMLPass", {
|
||||||
|
llvm::dbgs() << "RoundTripYAMLPass: " << tmpYAMLFile << "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
// The file that is written would be kept around if there is a problem
|
||||||
|
// writing to the file or when reading atoms back from the file.
|
||||||
|
yamlWriter->writeFile(*mergedFile, tmpYAMLFile.str());
|
||||||
|
OwningPtr<MemoryBuffer> buff;
|
||||||
|
if (MemoryBuffer::getFile(tmpYAMLFile.str(), buff))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (buff->getBufferSize() < MAX_YAML_FILE_SIZE) {
|
||||||
|
std::unique_ptr<MemoryBuffer> mb(buff.take());
|
||||||
|
_context.getYAMLReader().parseFile(mb, _yamlFile);
|
||||||
|
mergedFile.reset(new FileToMutable(_context, *_yamlFile[0].get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::sys::fs::remove(tmpYAMLFile.str());
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user