From f71d9880d2cb035ac2383e6d8d28014e9a4b2919 Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Fri, 16 Sep 2016 12:11:51 +0100 Subject: [PATCH 1/2] [stdlib] Refactor binary section data loading into separate file - Move OS specific libdl calls from ProtocolConformance.cpp into SectionData.cpp - Remove duplicate defintions also contained in MetadataLookup.cpp --- stdlib/public/runtime/CMakeLists.txt | 1 + stdlib/public/runtime/MetadataLookup.cpp | 73 ++----- stdlib/public/runtime/ProtocolConformance.cpp | 180 ++---------------- stdlib/public/runtime/SectionData.cpp | 132 +++++++++++++ stdlib/public/runtime/SectionData.h | 61 ++++++ 5 files changed, 222 insertions(+), 225 deletions(-) create mode 100644 stdlib/public/runtime/SectionData.cpp create mode 100644 stdlib/public/runtime/SectionData.h diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 732013ad1c701..3b2ae1777c6ca 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -55,6 +55,7 @@ set(swift_runtime_sources ProtocolConformance.cpp ReflectionNative.cpp RuntimeEntrySymbols.cpp + SectionData.cpp SwiftObjectNative.cpp) # Acknowledge that the following sources are known. diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 5822a930520c0..3f0e080255674 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -25,14 +25,8 @@ #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringExtras.h" #include "Private.h" +#include "SectionData.h" -#if defined(__APPLE__) && defined(__MACH__) -#include -#include -#elif defined(__ELF__) || defined(__ANDROID__) -#include -#include -#endif using namespace swift; using namespace Demangle; @@ -43,14 +37,6 @@ using namespace Demangle; #include #endif -#if defined(__APPLE__) && defined(__MACH__) -#define SWIFT_TYPE_METADATA_SECTION "__swift2_types" -#elif defined(__ELF__) -#define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start" -#elif defined(__CYGWIN__) || defined(_MSC_VER) -#define SWIFT_TYPE_METADATA_SECTION ".sw2tymd" -#endif - // Type Metadata Cache. namespace { @@ -89,17 +75,19 @@ namespace { }; } -#if defined(__APPLE__) && defined(__MACH__) -static void _initializeCallbacksToInspectDylib(); -#else -namespace swift { - void _swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName); -} - static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, size_t recordsSize); + +static InspectArgs metadataSectionArgs = { + _addImageTypeMetadataRecordsBlock, + SWIFT_TYPE_METADATA_SECTION +}; + +#if defined(__APPLE__) && defined(__MACH__) +static void +_addImageTypeMetadataRecords(const mach_header *mh, intptr_t vmaddr_slide) { + _swift_readSectionData(mh, &metadataSectionArgs); +} #endif struct TypeMetadataState { @@ -110,14 +98,11 @@ struct TypeMetadataState { TypeMetadataState() { SectionsToScan.reserve(16); #if defined(__APPLE__) && defined(__MACH__) - _initializeCallbacksToInspectDylib(); + _swift_initializeCallbacksForSectionData(_addImageTypeMetadataRecords); #else - _swift_initializeCallbacksToInspectDylib( - _addImageTypeMetadataRecordsBlock, - SWIFT_TYPE_METADATA_SECTION); + _swift_initializeCallbacksForSectionData(&metadataSectionArgs); #endif } - }; static Lazy TypeMetadataRecords; @@ -147,36 +132,6 @@ static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, recordsBegin, recordsEnd); } -#if defined(__APPLE__) && defined(__MACH__) -static void _addImageTypeMetadataRecords(const mach_header *mh, - intptr_t vmaddr_slide) { -#ifdef __LP64__ - using mach_header_platform = mach_header_64; - assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); -#else - using mach_header_platform = mach_header; -#endif - - // Look for a __swift2_types section. - unsigned long recordsSize; - const uint8_t *records = - getsectiondata(reinterpret_cast(mh), - SEG_TEXT, SWIFT_TYPE_METADATA_SECTION, - &recordsSize); - - if (!records) - return; - - _addImageTypeMetadataRecordsBlock(records, recordsSize); -} - -static void _initializeCallbacksToInspectDylib() { - // Install our dyld callback. - // Dyld will invoke this on our behalf for all images that have already - // been loaded. - _dyld_register_func_for_add_image(_addImageTypeMetadataRecords); -} -#endif void swift::swift_registerTypeMetadataRecords(const TypeMetadataRecord *begin, diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index 4ac9ad976c339..d4564ac056aab 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -20,22 +20,8 @@ #include "swift/Runtime/Metadata.h" #include "swift/Runtime/Mutex.h" #include "Private.h" +#include "SectionData.h" -#if defined(__APPLE__) && defined(__MACH__) -#include -#include -#elif defined(__ELF__) || defined(__ANDROID__) -#include -#include -#endif - -#if defined(_MSC_VER) -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#else -#include -#endif using namespace swift; @@ -146,13 +132,6 @@ const { } } -#if defined(__APPLE__) && defined(__MACH__) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto" -#elif defined(__ELF__) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" -#elif defined(__CYGWIN__) || defined(_MSC_VER) -#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".sw2prtc" -#endif namespace { struct ConformanceSection { @@ -232,17 +211,20 @@ namespace { } // Conformance Cache. -#if defined(__APPLE__) && defined(__MACH__) -static void _initializeCallbacksToInspectDylib(); -#else -namespace swift { - void _swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName); -} static void _addImageProtocolConformancesBlock(const uint8_t *conformances, size_t conformancesSize); + +static InspectArgs conformanceSectionArgs = { + _addImageProtocolConformancesBlock, + SWIFT_PROTOCOL_CONFORMANCES_SECTION +}; + +#if defined(__APPLE__) && defined(__MACH__) +static void +_addImageProtocolConformances(const mach_header *mh, intptr_t vmaddr_slide) { + _swift_readSectionData(mh, &conformanceSectionArgs); +} #endif struct ConformanceState { @@ -253,11 +235,9 @@ struct ConformanceState { ConformanceState() { SectionsToScan.reserve(16); #if defined(__APPLE__) && defined(__MACH__) - _initializeCallbacksToInspectDylib(); + _swift_initializeCallbacksForSectionData(_addImageProtocolConformances); #else - _swift_initializeCallbacksToInspectDylib( - _addImageProtocolConformancesBlock, - SWIFT_PROTOCOL_CONFORMANCES_SECTION); + _swift_initializeCallbacksForSectionData(&conformanceSectionArgs); #endif } @@ -317,138 +297,6 @@ static void _addImageProtocolConformancesBlock(const uint8_t *conformances, recordsBegin, recordsEnd); } -#if !defined(__APPLE__) || !defined(__MACH__) -// Common Structure -struct InspectArgs { - void (*fnAddImageBlock)(const uint8_t *, size_t); - const char *sectionName; -}; -#endif - -#if defined(__APPLE__) && defined(__MACH__) -static void _addImageProtocolConformances(const mach_header *mh, - intptr_t vmaddr_slide) { -#ifdef __LP64__ - using mach_header_platform = mach_header_64; - assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); -#else - using mach_header_platform = mach_header; -#endif - - // Look for a __swift2_proto section. - unsigned long conformancesSize; - const uint8_t *conformances = - getsectiondata(reinterpret_cast(mh), - SEG_TEXT, SWIFT_PROTOCOL_CONFORMANCES_SECTION, - &conformancesSize); - - if (!conformances) - return; - - _addImageProtocolConformancesBlock(conformances, conformancesSize); -} - -static void _initializeCallbacksToInspectDylib() { - // Install our dyld callback. - // Dyld will invoke this on our behalf for all images that have already - // been loaded. - _dyld_register_func_for_add_image(_addImageProtocolConformances); -} - -#elif defined(__ELF__) || defined(__ANDROID__) -static int _addImageProtocolConformances(struct dl_phdr_info *info, - size_t size, void *data) { - // inspectArgs contains addImage*Block function and the section name - InspectArgs *inspectArgs = reinterpret_cast(data); - - void *handle; - if (!info->dlpi_name || info->dlpi_name[0] == '\0') { - handle = dlopen(nullptr, RTLD_LAZY); - } else - handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); - - if (!handle) { - // Not a shared library. - return 0; - } - - auto conformances = reinterpret_cast( - dlsym(handle, inspectArgs->sectionName)); - - if (!conformances) { - // if there are no conformances, don't hold this handle open. - dlclose(handle); - return 0; - } - - // Extract the size of the conformances block from the head of the section - auto conformancesSize = *reinterpret_cast(conformances); - conformances += sizeof(conformancesSize); - - inspectArgs->fnAddImageBlock(conformances, conformancesSize); - - dlclose(handle); - return 0; -} - -void swift::_swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName) { - InspectArgs inspectArgs = {fnAddImageBlock, sectionName}; - - // Search the loaded dls. Unlike the above, this only searches the already - // loaded ones. - // FIXME: Find a way to have this continue to happen after. - // rdar://problem/19045112 - dl_iterate_phdr(_addImageProtocolConformances, &inspectArgs); -} -#elif defined(__CYGWIN__) || defined(_MSC_VER) -static int _addImageProtocolConformances(struct dl_phdr_info *info, - size_t size, void *data) { - InspectArgs *inspectArgs = (InspectArgs *)data; - // inspectArgs contains addImage*Block function and the section name -#if defined(_MSC_VER) - HMODULE handle; - - if (!info->dlpi_name || info->dlpi_name[0] == '\0') - handle = GetModuleHandle(nullptr); - else - handle = GetModuleHandle(info->dlpi_name); -#else - void *handle; - if (!info->dlpi_name || info->dlpi_name[0] == '\0') - handle = dlopen(nullptr, RTLD_LAZY); - else - handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); -#endif - - unsigned long conformancesSize; - const uint8_t *conformances = - _swift_getSectionDataPE(handle, inspectArgs->sectionName, - &conformancesSize); - - if (conformances) - inspectArgs->fnAddImageBlock(conformances, conformancesSize); - -#if defined(_MSC_VER) - FreeLibrary(handle); -#else - dlclose(handle); -#endif - return 0; -} - -void swift::_swift_initializeCallbacksToInspectDylib( - void (*fnAddImageBlock)(const uint8_t *, size_t), - const char *sectionName) { - InspectArgs inspectArgs = {fnAddImageBlock, sectionName}; - - _swift_dl_iterate_phdr(_addImageProtocolConformances, &inspectArgs); -} -#else -# error No known mechanism to inspect dynamic libraries on this platform. -#endif - // This variable is used to signal when a cache was generated and // it is correct to avoid a new scan. static unsigned ConformanceCacheGeneration = 0; diff --git a/stdlib/public/runtime/SectionData.cpp b/stdlib/public/runtime/SectionData.cpp new file mode 100644 index 0000000000000..5e3eea7c878b6 --- /dev/null +++ b/stdlib/public/runtime/SectionData.cpp @@ -0,0 +1,132 @@ +//===-- SectionData.cpp -----------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include +#include "SectionData.h" + + +using namespace swift; + +#if defined(__APPLE__) && defined(__MACH__) +void +swift::_swift_readSectionData(const mach_header *mh, + InspectArgs *inspectArgs) { +#ifdef __LP64__ + using mach_header_platform = mach_header_64; + assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); +#else + using mach_header_platform = mach_header; +#endif + + // Look for a named section. + unsigned long dataSize = 0; + const uint8_t *data = + getsectiondata(reinterpret_cast(mh), + SEG_TEXT, inspectArgs->sectionName, + &dataSize); + + if (data) { + inspectArgs->fnAddImageBlock(data, dataSize); + } +} + +void +swift::_swift_initializeCallbacksForSectionData( + void (*func)(const mach_header*, intptr_t)) { + // Install our dyld callback. + // Dyld will invoke this on our behalf for all images that have already + // been loaded. + _dyld_register_func_for_add_image(func); +} +#elif defined(__ELF__) || defined(__ANDROID__) + +static int +_addImageSectionData(struct dl_phdr_info *info, size_t size, void *data) { + // inspectArgs contains addImage*Block function and the section name + InspectArgs *inspectArgs = reinterpret_cast(data); + void *handle; + if (!info->dlpi_name || info->dlpi_name[0] == '\0') { + handle = dlopen(nullptr, RTLD_LAZY); + } else + handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); + + if (!handle) { + // Not a shared library. + return 0; + } + + auto imageBlock = reinterpret_cast( + dlsym(handle, inspectArgs->sectionName)); + + if (imageBlock) { + // Extract the size of the image data from the head of the section + auto imageBlockSize = *reinterpret_cast(imageBlock); + imageBlock += sizeof(imageBlockSize); + inspectArgs->fnAddImageBlock(imageBlock, imageBlockSize); + } + dlclose(handle); + return 0; +} + +void +swift::_swift_initializeCallbacksForSectionData(InspectArgs *inspectArgs) { + // Search the loaded dls. Unlike the above, this only searches the already + // loaded ones. + // FIXME: Find a way to have this continue to happen after. + // rdar://problem/19045112 + dl_iterate_phdr(_addImageSectionData, inspectArgs); +} + +#elif defined(__CYGWIN__) || defined(_MSC_VER) + +static int +_addImageSectionData(struct dl_phdr_info *info, size_t size, void *data) { + InspectArgs *inspectArgs = (InspectArgs *)data; + // inspectArgs contains addImage*Block function and the section name +#if defined(_MSC_VER) + HMODULE handle; + + if (!info->dlpi_name || info->dlpi_name[0] == '\0') + handle = GetModuleHandle(nullptr); + else + handle = GetModuleHandle(info->dlpi_name); +#else + void *handle; + if (!info->dlpi_name || info->dlpi_name[0] == '\0') + handle = dlopen(nullptr, RTLD_LAZY); + else + handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); +#endif + + unsigned long imageBlockSize; + const uint8_t *imageBlock = + _swift_getSectionDataPE(handle, inspectArgs->sectionName, + imageBlockSize); + + if (imageBlock) + inspectArgs->fnAddImageBlock(imageBlock, imageBlockSize); + +#if defined(_MSC_VER) + FreeLibrary(handle); +#else + dlclose(handle); +#endif + return 0; +} + +void +swift::_swift_initializeCallbacksForSectionData(InspectArgs *inspectArgs) { + _swift_dl_iterate_phdr(_addImageSectionData, inspectArgs); +} +#else +# error No known mechanism to inspect dynamic libraries on this platform. +#endif diff --git a/stdlib/public/runtime/SectionData.h b/stdlib/public/runtime/SectionData.h new file mode 100644 index 0000000000000..98dd6bf1c54a7 --- /dev/null +++ b/stdlib/public/runtime/SectionData.h @@ -0,0 +1,61 @@ +//===-- SectionData.h ------------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2016 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See http://swift.org/LICENSE.txt for license information +// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_RUNTIME_SECTIONDATA_H +#define SWIFT_RUNTIME_SECTIONDATA_H + +#if defined(__APPLE__) && defined(__MACH__) +#include +#include +#elif defined(__ELF__) || defined(__ANDROID__) +#include +#include +#endif + +#if defined(_MSC_VER) +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#else +#include +#endif + + +#if defined(__APPLE__) && defined(__MACH__) +#define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto" +#define SWIFT_TYPE_METADATA_SECTION "__swift2_types" +#elif defined(__ELF__) +#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" +#define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start" +#elif defined(__CYGWIN__) || defined(_MSC_VER) +#define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".sw2prtc" +#define SWIFT_TYPE_METADATA_SECTION ".sw2tymd" +#endif + + +namespace swift { + // Common Structure + struct InspectArgs { + void (*fnAddImageBlock)(const uint8_t *, size_t); + const char *sectionName; + }; + +#if defined(__APPLE__) && defined(__MACH__) + void _swift_initializeCallbacksForSectionData(void (*func)(const mach_header*, + intptr_t)); + void _swift_readSectionData(const mach_header *mh, InspectArgs *inspectArgs); +#else + void _swift_initializeCallbacksForSectionData(InspectArgs *inspectArgs); +#endif +} + +#endif /* SWIFT_RUNTIME_SECTIONDATA_H */ From 27a46bf72052af50d5d0aaf04150b36648d37894 Mon Sep 17 00:00:00 2001 From: Simon Evans Date: Mon, 19 Sep 2016 18:13:09 +0100 Subject: [PATCH 2/2] [SR-648] Add option to create statically linked binaries - Adds -static-executable option to swiftc to use along with -emit-executable - Only works on Linux for now, adds a stub to replace select libdl functions with a fatal error message to catch other libs that use dlopen() etc (eg libicu) to aid in debugging since they wont work on static binaries anyway and could just silently fail otherwise - Darwin doesnt support static binaries, see https://developer.apple.com/library/content/qa/qa1118/_index.html --- include/swift/Option/Options.td | 6 +++ lib/Driver/ToolChains.cpp | 41 +++++++++++++++++-- stdlib/public/runtime/CMakeLists.txt | 13 ++++++ stdlib/public/runtime/MetadataLookup.cpp | 5 ++- stdlib/public/runtime/ProtocolConformance.cpp | 5 ++- stdlib/public/runtime/SectionData.cpp | 19 +++++++++ stdlib/public/runtime/SectionData.h | 11 +++++ stdlib/public/runtime/static_stub.c | 33 +++++++++++++++ 8 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 stdlib/public/runtime/static_stub.c diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 2eba9fcd8ae6e..ab964e25ceed8 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -278,6 +278,12 @@ def no_static_stdlib: Flag<["-"], "no-static-stdlib">, Flags<[HelpHidden]>, HelpText<"Don't statically link the Swift standard library">; +def static_executable : Flag<["-"], "static-executable">, + HelpText<"Statically link the executable">; +def no_static_executable : Flag<["-"], "no-static-executable">, + Flags<[HelpHidden]>, + HelpText<"Don't statically link the executable">; + def use_ld : Joined<["-"], "use-ld=">, Flags<[DoesNotAffectIncrementalBuild]>, HelpText<"Specifies the linker to be used">; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 285de54a2a067..6003e0908b967 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -948,6 +948,12 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, assert(context.Output.getPrimaryOutputType() == types::TY_Image && "Invalid linker output type."); + if (context.Args.hasFlag(options::OPT_static_executable, + options::OPT_no_static_executable, + false)) { + llvm::report_fatal_error("-static-executable is not supported on Darwin"); + } + const Driver &D = getDriver(); const llvm::Triple &Triple = getTriple(); @@ -1353,9 +1359,38 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, // Link the standard library. Arguments.push_back("-L"); - if (context.Args.hasFlag(options::OPT_static_stdlib, - options::OPT_no_static_stdlib, - false)) { + if (context.Args.hasFlag(options::OPT_static_executable, + options::OPT_no_static_executable, + false)) { + SmallString<128> StaticRuntimeLibPath; + getRuntimeStaticLibraryPath(StaticRuntimeLibPath, context.Args, *this); + Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); + + SmallString<128> StaticStubObjectPath = StaticRuntimeLibPath; + llvm::sys::path::append(StaticStubObjectPath, "static_stub.o"); + auto ObjectPath = StaticStubObjectPath.str(); + + if (llvm::sys::fs::is_regular_file(ObjectPath)) { + // FIXME: It would be better if these were extracted from static_stub.o + // using `swift-autolink-extract' + Arguments.push_back(context.Args.MakeArgString(ObjectPath)); + Arguments.push_back("-static"); + Arguments.push_back("-Xlinker"); + Arguments.push_back("--defsym=__swift2_protocol_conformances_start=.swift2_protocol_conformances_start"); + Arguments.push_back("-Xlinker"); + Arguments.push_back("--defsym=__swift2_type_metadata_start=.swift2_type_metadata_start"); + Arguments.push_back("-lswiftCore"); + Arguments.push_back("-licui18n"); + Arguments.push_back("-licuuc"); + Arguments.push_back("-licudata"); + Arguments.push_back("-lpthread"); + } else { + llvm::report_fatal_error("-static-executable not supported on this platform"); + } + } + else if (context.Args.hasFlag(options::OPT_static_stdlib, + options::OPT_no_static_stdlib, + false)) { SmallString<128> StaticRuntimeLibPath; getRuntimeStaticLibraryPath(StaticRuntimeLibPath, context.Args, *this); Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 3b2ae1777c6ca..6f5f076969137 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -65,6 +65,7 @@ set(LLVM_OPTIONAL_SOURCES MutexPThread.cpp MutexWin32.cpp CygwinPort.cpp + static_stub.c ${swift_runtime_sources} ${swift_runtime_objc_sources} ${swift_runtime_leaks_sources}) @@ -131,3 +132,15 @@ foreach(sdk ${ELFISH_SDKS}) endforeach() add_custom_target(section_magic ALL DEPENDS ${object_target_list}) + +if(SWIFT_BUILD_STATIC_STDLIB) + foreach(sdk ${SWIFT_SDKS}) + if("${sdk}" STREQUAL "LINUX") + add_library(static_stub OBJECT static_stub.c) + swift_install_in_component(stdlib + FILES "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/static_stub.dir/static_stub.c${CMAKE_C_OUTPUT_EXTENSION}" + RENAME "static_stub.o" + DESTINATION "lib/swift_static/linux") + endif() + endforeach() +endif() diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 3f0e080255674..0256ae89659e8 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -80,7 +80,10 @@ static void _addImageTypeMetadataRecordsBlock(const uint8_t *records, static InspectArgs metadataSectionArgs = { _addImageTypeMetadataRecordsBlock, - SWIFT_TYPE_METADATA_SECTION + SWIFT_TYPE_METADATA_SECTION, +#if defined(SUPPORTS_STATIC_BINARIES) + &__swift2_type_metadata_start +#endif }; #if defined(__APPLE__) && defined(__MACH__) diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index d4564ac056aab..f2ba73d75d9a2 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -217,7 +217,10 @@ static void _addImageProtocolConformancesBlock(const uint8_t *conformances, static InspectArgs conformanceSectionArgs = { _addImageProtocolConformancesBlock, - SWIFT_PROTOCOL_CONFORMANCES_SECTION + SWIFT_PROTOCOL_CONFORMANCES_SECTION, +#if defined(SUPPORTS_STATIC_BINARIES) + &__swift2_protocol_conformances_start +#endif }; #if defined(__APPLE__) && defined(__MACH__) diff --git a/stdlib/public/runtime/SectionData.cpp b/stdlib/public/runtime/SectionData.cpp index 5e3eea7c878b6..6e3f298d69cdd 100644 --- a/stdlib/public/runtime/SectionData.cpp +++ b/stdlib/public/runtime/SectionData.cpp @@ -49,6 +49,13 @@ swift::_swift_initializeCallbacksForSectionData( } #elif defined(__ELF__) || defined(__ANDROID__) +#if defined(SUPPORTS_STATIC_BINARIES) +// If creating a static binary using --static-executable, +// gold will set these to the data sections via --defsym +const void *__swift2_protocol_conformances_start = nullptr; +const void *__swift2_type_metadata_start = nullptr; +#endif // SUPPORTS_STATIC_BINARIES + static int _addImageSectionData(struct dl_phdr_info *info, size_t size, void *data) { // inspectArgs contains addImage*Block function and the section name @@ -79,6 +86,18 @@ _addImageSectionData(struct dl_phdr_info *info, size_t size, void *data) { void swift::_swift_initializeCallbacksForSectionData(InspectArgs *inspectArgs) { +#if defined(SUPPORTS_STATIC_BINARIES) + const void **sectionDataAddr = inspectArgs->sectionDataAddr; + assert(sectionDataAddr != nullptr ); + if (*sectionDataAddr) { + auto blockAddr = reinterpret_cast(sectionDataAddr); + auto blockSize = *reinterpret_cast(blockAddr); + blockAddr += sizeof(blockSize); + inspectArgs->fnAddImageBlock(blockAddr, blockSize); + return; + } +#endif // SUPPORTS_STATIC_BINARIES + // Search the loaded dls. Unlike the above, this only searches the already // loaded ones. // FIXME: Find a way to have this continue to happen after. diff --git a/stdlib/public/runtime/SectionData.h b/stdlib/public/runtime/SectionData.h index 98dd6bf1c54a7..63fdd5a8302bc 100644 --- a/stdlib/public/runtime/SectionData.h +++ b/stdlib/public/runtime/SectionData.h @@ -36,6 +36,14 @@ #elif defined(__ELF__) #define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" #define SWIFT_TYPE_METADATA_SECTION ".swift2_type_metadata_start" + +#if defined(__linux__) +#define SUPPORTS_STATIC_BINARIES +// Add a declaration for each section +extern const void *__swift2_protocol_conformances_start; +extern const void *__swift2_type_metadata_start; +#endif // __linux__ + #elif defined(__CYGWIN__) || defined(_MSC_VER) #define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".sw2prtc" #define SWIFT_TYPE_METADATA_SECTION ".sw2tymd" @@ -47,6 +55,9 @@ namespace swift { struct InspectArgs { void (*fnAddImageBlock)(const uint8_t *, size_t); const char *sectionName; +#if defined(SUPPORTS_STATIC_BINARIES) + const void **sectionDataAddr; +#endif }; #if defined(__APPLE__) && defined(__MACH__) diff --git a/stdlib/public/runtime/static_stub.c b/stdlib/public/runtime/static_stub.c new file mode 100644 index 0000000000000..366415c61345d --- /dev/null +++ b/stdlib/public/runtime/static_stub.c @@ -0,0 +1,33 @@ +#if defined(__LINUX__) && defined(__ELF__) +#error "This only works on Linux/ELF" // Needs testing on other ELF platforms +#else +#include +#include +#include + + +// This forces resolving of these weak symbols but keeps them hidden +// externally +const void *unused1 __attribute__ ((unused, visibility("internal"))) = pthread_self; +const void *unused2 __attribute__ ((unused, visibility("internal"))) = pthread_key_create; +const void *unused3 __attribute__ ((unused, visibility("internal"))) = pthread_once; + + +// linking libdl into static binaries produces this message: +// "warning: Using 'dlopen' in statically linked applications requires at +// runtime the shared libraries from the glibc version used for linking" +// +// Instead of letting the calls silently fail, show an error and quit. +// This is not actually needed, it is just to aid debugging + +#define UNSUPPORTED_FUNC(x) void x() { \ + fprintf(stderr, "Unsupported dynamic linker call: %s\n", __func__); \ + abort(); \ +} + +UNSUPPORTED_FUNC(dlopen) +UNSUPPORTED_FUNC(dlsym) +UNSUPPORTED_FUNC(dladdr) +UNSUPPORTED_FUNC(dlclose) + +#endif // linux && ELF