Skip to content

Restore -static-executable on Linux. #15183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions lib/Driver/UnixToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,17 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job,
#endif
}

bool staticExecutable = false;
bool staticStdlib = false;

if (context.Args.hasFlag(options::OPT_static_executable,
options::OPT_no_static_executable, false)) {
staticExecutable = true;
} else if (context.Args.hasFlag(options::OPT_static_stdlib,
options::OPT_no_static_stdlib, false)) {
staticStdlib = true;
}

// Configure the toolchain.
// By default, use the system clang++ to link.
const char *Clang = "clang++";
Expand All @@ -167,7 +178,7 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job,
}

if (getTriple().getOS() == llvm::Triple::Linux &&
job.getKind() == LinkKind::Executable) {
job.getKind() == LinkKind::Executable && !staticExecutable) {
Arguments.push_back("-pie");
}

Expand All @@ -177,17 +188,6 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job,
Arguments.push_back(context.Args.MakeArgString(Target));
}

bool staticExecutable = false;
bool staticStdlib = false;

if (context.Args.hasFlag(options::OPT_static_executable,
options::OPT_no_static_executable, false)) {
staticExecutable = true;
} else if (context.Args.hasFlag(options::OPT_static_stdlib,
options::OPT_no_static_stdlib, false)) {
staticStdlib = true;
}

SmallString<128> SharedRuntimeLibPath;
getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, /*Shared=*/true);

Expand All @@ -205,11 +205,13 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job,
Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath));
}

SmallString<128> swiftrtPath = SharedRuntimeLibPath;
llvm::sys::path::append(swiftrtPath,
swift::getMajorArchitectureName(getTriple()));
llvm::sys::path::append(swiftrtPath, "swiftrt.o");
Arguments.push_back(context.Args.MakeArgString(swiftrtPath));
if (!staticExecutable) {
SmallString<128> swiftrtPath = SharedRuntimeLibPath;
llvm::sys::path::append(swiftrtPath,
swift::getMajorArchitectureName(getTriple()));
llvm::sys::path::append(swiftrtPath, "swiftrt.o");
Arguments.push_back(context.Args.MakeArgString(swiftrtPath));
}

addPrimaryInputsOfType(Arguments, context.Inputs, context.Args,
file_types::TY_Object);
Expand Down
65 changes: 39 additions & 26 deletions stdlib/public/runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,33 +105,44 @@ if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX")
LINK_FLAGS ${swift_runtime_linker_flags}
INSTALL_IN_COMPONENT stdlib)

foreach(arch IN LISTS SWIFT_SDK_${sdk}_ARCHITECTURES)
set(FragileSupportLibrary swiftImageInspectionShared-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch})
set(LibraryLocation ${SWIFTSTATICLIB_DIR}/${lowercase_sdk}/${arch})
add_custom_command_target(swift_image_inspection_${arch}_static
COMMAND
"${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${FragileSupportLibrary}> ${LibraryLocation}
OUTPUT
"${LibraryLocation}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspectionShared${CMAKE_STATIC_LIBRARY_SUFFIX}"
DEPENDS
${FragileSupportLibrary})
swift_install_in_component(FILES $<TARGET_FILE:${FragileSupportLibrary}>
DESTINATION "lib/swift_static/${lowercase_sdk}/${arch}"
COMPONENT stdlib)
endforeach()
set(swift_elf_static_lib_compile_flags ${swift_runtime_library_compile_flags})
list(APPEND swift_elf_static_lib_compile_flags -DELF_STATIC_LIB)

add_swift_target_library(swiftImageInspectionStatic TARGET_LIBRARY STATIC
StaticBinaryELF.cpp ImageInspectionELF.cpp
C_COMPILE_FLAGS ${swift_elf_static_lib_compile_flags}
LINK_FLAGS ${swift_runtime_linker_flags}
INSTALL_IN_COMPONENT stdlib)

foreach(linktype Shared Static)
foreach(arch IN LISTS SWIFT_SDK_${sdk}_ARCHITECTURES)
set(FragileSupportLibrary swiftImageInspection${linktype}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch})
set(LibraryLocation ${SWIFTSTATICLIB_DIR}/${lowercase_sdk}/${arch})
add_custom_command_target(swift_image_inspection_${linktype}_${arch}_static
COMMAND
"${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${FragileSupportLibrary}> ${LibraryLocation}
OUTPUT
"${LibraryLocation}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspection${linktype}${CMAKE_STATIC_LIBRARY_SUFFIX}"
DEPENDS
${FragileSupportLibrary})
swift_install_in_component(FILES $<TARGET_FILE:${FragileSupportLibrary}>
DESTINATION "lib/swift_static/${lowercase_sdk}/${arch}"
COMPONENT stdlib)
endforeach()

set(FragileSupportLibraryPrimary swiftImageInspectionShared-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${SWIFT_PRIMARY_VARIANT_ARCH})
set(LibraryLocationPrimary ${SWIFTSTATICLIB_DIR}/${lowercase_sdk})
add_custom_command_target(swift_image_inspection_static_primary_arch
COMMAND
"${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${FragileSupportLibraryPrimary}> ${LibraryLocationPrimary}
OUTPUT
"${LibraryLocationPrimary}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspectionShared${CMAKE_STATIC_LIBRARY_SUFFIX}"
DEPENDS
${FragileSupportLibraryPrimary})
set(FragileSupportLibraryPrimary swiftImageInspection${linktype}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${SWIFT_PRIMARY_VARIANT_ARCH})
set(LibraryLocationPrimary ${SWIFTSTATICLIB_DIR}/${lowercase_sdk})
add_custom_command_target(swift_image_inspection_${linktype}_primary_arch
COMMAND
"${CMAKE_COMMAND}" -E copy $<TARGET_FILE:${FragileSupportLibraryPrimary}> ${LibraryLocationPrimary}
OUTPUT
"${LibraryLocationPrimary}/${CMAKE_STATIC_LIBRARY_PREFIX}swiftImageInspection${linktype}${CMAKE_STATIC_LIBRARY_SUFFIX}"
DEPENDS
${FragileSupportLibraryPrimary})
swift_install_in_component(FILES $<TARGET_FILE:${FragileSupportLibraryPrimary}>
DESTINATION "lib/swift_static/${lowercase_sdk}"
COMPONENT stdlib)
endforeach()

# Generate the static-executable-args.lnk file used for ELF systems (eg linux)
set(linkfile "${lowercase_sdk}/static-executable-args.lnk")
Expand All @@ -150,10 +161,12 @@ if(SWIFT_BUILD_STATIC_STDLIB AND "${sdk}" STREQUAL "LINUX")
DESTINATION "lib/swift_static/${lowercase_sdk}"
COMPONENT stdlib)
add_custom_target(static_binary_magic ALL DEPENDS ${static_binary_lnk_file_list})
foreach(arch IN LISTS SWIFT_SDK_LINUX_ARCHITECTURES)
add_dependencies(static_binary_magic ${swift_image_inspection_${arch}_static})
foreach(linktype Shared Static)
foreach(arch IN LISTS SWIFT_SDK_LINUX_ARCHITECTURES)
add_dependencies(static_binary_magic ${swift_image_inspection_${linktype}_${arch}_static})
endforeach()
add_dependencies(static_binary_magic ${swift_image_inspection_${linktype}_primary_arch})
endforeach()
add_dependencies(static_binary_magic ${swift_image_inspection_static_primary_arch})

add_swift_target_library(swiftImageInspectionSharedObject OBJECT_LIBRARY TARGET_LIBRARY
ImageInspectionELF.cpp
Expand Down
18 changes: 14 additions & 4 deletions stdlib/public/runtime/ImageInspectionELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@

#include "ImageInspection.h"
#include "ImageInspectionELF.h"

#ifndef ELF_STATIC_LIB
#include <dlfcn.h>
#endif

using namespace swift;

Expand Down Expand Up @@ -56,6 +59,7 @@ void swift::initializeProtocolLookup() {
sections = sections->next;
}
}

void swift::initializeProtocolConformanceLookup() {
const swift::MetadataSections *sections = registered;
while (true) {
Expand Down Expand Up @@ -89,10 +93,10 @@ void swift::initializeTypeMetadataRecordLookup() {
void swift::initializeDynamicReplacementLookup() {
}

// As ELF images are loaded, ImageInspectionInit:sectionDataInit() will call
// addNewDSOImage() with an address in the image that can later be used via
// dladdr() to dlopen() the image after the appropriate initialize*Lookup()
// function has been called.
// As ELF images are loaded, SwiftRT-ELF:swift_image_constructor() will call
// addNewDSOImage() with a pointer to the MetadataSections in the image. This
// functionality is not required for static executables which are linked with
// swiftImageInspectionStatic.
SWIFT_RUNTIME_EXPORT
void swift_addNewDSOImage(const void *addr) {
const swift::MetadataSections *sections =
Expand Down Expand Up @@ -131,6 +135,10 @@ void swift_addNewDSOImage(const void *addr) {
}
}

#ifndef ELF_STATIC_LIB

// For shared executables only, static executables use the version defined in
// StaticBinaryELF.cpp
int swift::lookupSymbol(const void *address, SymbolInfo *info) {
Dl_info dlinfo;
if (dladdr(address, &dlinfo) == 0) {
Expand All @@ -144,6 +152,8 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) {
return 1;
}

#endif

// This is only used for backward deployment hooks, which we currently only support for
// MachO. Add a stub here to make sure it still compiles.
void *swift::lookupSection(const char *segment, const char *section, size_t *outSize) {
Expand Down
55 changes: 45 additions & 10 deletions stdlib/public/runtime/StaticBinaryELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
#include <sys/stat.h>
#include <sys/types.h>

// The functions in SwiftRT-ELF.cpp are only called via the ELF .init constructor
// and none of the functions are linked directly, so include the code inline as the
// linker wont link to it in a static executable.
#include "SwiftRT-ELF.cpp"

using namespace std;
using namespace llvm;

Expand Down Expand Up @@ -61,6 +66,19 @@ typedef Elf32_Section Elf_Section;

extern const Elf_Ehdr elfHeader asm("__ehdr_start");

// Create strong linkage to pthread_self, pthread_once and pthread_key_create
// as they are normally weak-linked and used to detect the presence of pthreads.
// Without this the calls just jump to 0x0.
__attribute__((__visibility__("hidden")))
pthread_t (*__strong_pthread_self)(void) = pthread_self;

__attribute__((__visibility__("hidden")))
int (*__strong_pthread_once)(pthread_once_t *, void (*)(void)) = pthread_once;

__attribute__((__visibility__("hidden")))
int (*__strong_pthread_key_create)(pthread_key_t *, void (*)(void *)) = pthread_key_create;


class StaticBinaryELF {

private:
Expand Down Expand Up @@ -159,15 +177,28 @@ class StaticBinaryELF {
if (symbolTable.hasValue()) {
auto searchAddr = reinterpret_cast<Elf_Addr>(addr);
auto symbols = symbolTable->data<Elf_Sym>();
const Elf_Sym *bestMatch = nullptr;
unsigned long bestDistance = ULONG_MAX;

for (size_t idx = 0; idx < symbols.size(); idx++) {
auto symbol = &symbols[idx];
if (ELF_ST_TYPE(symbol->st_info) == STT_FUNC
&& searchAddr >= symbol->st_value
&& searchAddr < (symbol->st_value + symbol->st_size)) {
return symbol;
&& searchAddr >= symbol->st_value) {

auto tmpDistance = searchAddr - symbol->st_value;
if (tmpDistance < symbol->st_size) {
return symbol;
}
// The searchAddress is past the end of this symbol's region, keep
// track of which symbol end address the searchAddress is closest to.
tmpDistance -= symbol->st_size;
if (tmpDistance < bestDistance) {
bestMatch = symbol;
tmpDistance = bestDistance;
}
}
}
return bestMatch;
}
return nullptr;
}
Expand Down Expand Up @@ -202,26 +233,30 @@ class StaticBinaryELF {
StringRef deleted = StringRef("(deleted)");

while (getdelim(&line, &size, '\n', fp) != -1) {
StringRef entry = StringRef(line).rsplit('\n').first;
auto addrRange = entry.split(' ').first.split('-');
unsigned long long low = strtoull(addrRange.first.str().c_str(),
StringRef entry = StringRef(line).drop_back();

auto indexOfDash = entry.find('-');
auto indexOfSpace = entry.find(' ');
auto addrLow = entry.substr(0, indexOfDash);
auto addrHigh = entry.substr(indexOfDash + 1, indexOfSpace);
unsigned long long low = strtoull(addrLow.str().c_str(),
nullptr, 16);
if (low == 0 || low > UINTPTR_MAX || address < (uintptr_t)low) {
continue;
}

unsigned long long high = strtoull(addrRange.second.str().c_str(),
unsigned long long high = strtoull(addrHigh.str().c_str(),
nullptr, 16);
if (high == 0 || high > UINTPTR_MAX || address > (uintptr_t)high) {
continue;
}

auto fname = entry.split('/').second;
auto fname = entry.substr(entry.find('/'));
if (fname.empty() || fname.endswith(deleted)) {
continue;
}

fullPathName = "/" + fname.str();
fullPathName = fname.str();
break;
}
if (line) {
Expand Down Expand Up @@ -312,7 +347,7 @@ swift::lookupSymbol(const void *address, SymbolInfo *info) {
auto symbol = binary.findSymbol(address);
if (symbol != nullptr) {
info->symbolAddress = reinterpret_cast<void *>(symbol->st_value);
info->symbolName = binary.symbolName(symbol);
info->symbolName.reset(binary.symbolName(symbol));
} else {
info->symbolAddress = nullptr;
info->symbolName = nullptr;
Expand Down
10 changes: 10 additions & 0 deletions test/Driver/static-executable-linux.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Build a static executable "hello world" program
// REQUIRES: OS=linux-gnu
// REQUIRES: static_stdlib
print("hello world!")
// RUN: %empty-directory(%t)
// RUN: %target-swiftc_driver -static-executable -o %t/static-executable %s
// RUN: %t/static-executable | %FileCheck %s
// RUN: file %t/static-executable | %FileCheck %s --check-prefix=FILE
// CHECK: hello world!
// FILE: , statically linked,
15 changes: 4 additions & 11 deletions utils/static-executable-args.lnk
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
-static
-lswiftCore
-lswiftImageInspectionShared
-Xlinker
--defsym=__import_pthread_self=pthread_self
-Xlinker
--defsym=__import_pthread_once=pthread_once
-Xlinker
--defsym=__import_pthread_key_create=pthread_key_create
-lswiftImageInspectionStatic
-lpthread
-latomic
-licui18n
-licuuc
-licudata
-ldl
-licui18nswift
-licuucswift
-licudataswift