Skip to content
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

Restore -static-executable on Linux. #29039

Closed
wants to merge 2 commits into from

Conversation

spevans
Copy link
Contributor

@spevans spevans commented Jan 7, 2020

  • Add back StaticBinaryELF.cpp which provides swift::lookupSymbol()
    for statically linked ELF binaries.

  • Build libswiftImageInspectionStatic.a from StaticBinaryELF.cpp

  • Update static-executable-args.lnk and replace
    libswiftImageInspectionShared with libswiftImageInspectionStatic.

  • Add driver tests for '-static-executable' on Linux to validate
    that output binary is statically linked.

  • Fix linkage to pthreads to avoid weak linkage issues in a static
    executable.

This is a rebase of a previous PR but that didnt work with Ubutnu18.04 only 16.04. This version has been tested with 16.04, 18.04 and 19.10.

Note, as with -static-stdlib, only Dispatch can be used with -static-executable, Foundation cannot at this time.

Integration tests have also been added to catch any future breakage of this change.

@spevans
Copy link
Contributor Author

spevans commented Jan 7, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test

@spevans
Copy link
Contributor Author

spevans commented Jan 7, 2020

cc @jckarter @weissi

stdlib/public/runtime/StaticBinaryELF.cpp Outdated Show resolved Hide resolved
stdlib/public/runtime/StaticBinaryELF.cpp Outdated Show resolved Hide resolved
stdlib/public/runtime/StaticBinaryELF.cpp Outdated Show resolved Hide resolved
stdlib/public/runtime/StaticBinaryELF.cpp Outdated Show resolved Hide resolved
stdlib/public/runtime/StaticBinaryELF.cpp Show resolved Hide resolved
@@ -144,6 +152,8 @@ int swift::lookupSymbol(const void *address, SymbolInfo *info) {
return 1;
}

#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just use the alternate version always? The cost is nearly negligible - the cost is largely associated with the fact that the information from the ELF header parsing may be cached by the loader, which is not guaranteed.

@spevans spevans force-pushed the pr_static_executable_fix branch from 340fd22 to 15ac30f Compare January 10, 2020 00:55
@spevans
Copy link
Contributor Author

spevans commented Jan 10, 2020

@swift-ci test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 340fd224916675e06cacc6d144f1054bb0b8b7eb

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 340fd224916675e06cacc6d144f1054bb0b8b7eb

@spevans
Copy link
Contributor Author

spevans commented Jan 10, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 15ac30fbc2be2fe15d8c53a9ac0a3ed9deedbf69

@spevans
Copy link
Contributor Author

spevans commented Jan 10, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test linux

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 15ac30fbc2be2fe15d8c53a9ac0a3ed9deedbf69

@spevans
Copy link
Contributor Author

spevans commented Jan 10, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test linux

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 15ac30fbc2be2fe15d8c53a9ac0a3ed9deedbf69

@spevans
Copy link
Contributor Author

spevans commented Jan 10, 2020

@swift-ci smoke test linux

1 similar comment
@spevans
Copy link
Contributor Author

spevans commented Jan 10, 2020

@swift-ci smoke test linux

@spevans
Copy link
Contributor Author

spevans commented Jan 11, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test linux

Copy link
Member

@compnerd compnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I missed it or something ... why not use the parsing logic even for the shared linking?

lib/Driver/UnixToolChains.cpp Show resolved Hide resolved
stdlib/public/runtime/CMakeLists.txt Outdated Show resolved Hide resolved
stdlib/public/runtime/CMakeLists.txt Outdated Show resolved Hide resolved
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really wish we had linker options ... -u pthread_self -u pthread_once -u pthead_key_create is so much better than this. sigh

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had used ---defsym=__import_pthread_self=pthread_self options to the linker before but it looks like that doesnt create strong linkage anymore.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--defsym creating a strong reference sounds like a bug. If you want to create a strong reference, you should use --require-defined or -u at the very least.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didnt know about this option! I had to use -undefined (-u) since ld.gold is being used, --require-defined seems to only work on ld

- Add back StaticBinaryELF.cpp which provides swift::lookupSymbol()
  for statically linked ELF binaries.

- Build libswiftImageInspectionStatic.a from StaticBinaryELF.cpp

- Update static-executable-args.lnk and replace
  libswiftImageInspectionShared with libswiftImageInspectionStatic.

- Fix linkage to pthreads to avoid weak linkage issues in a static
  executable.

- Add driver test for '-static-executable' on Linux to validate
  that output binary is statically linked.
@spevans spevans force-pushed the pr_static_executable_fix branch from 15ac30f to 3b25795 Compare January 11, 2020 09:00
@spevans
Copy link
Contributor Author

spevans commented Jan 11, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 15ac30fbc2be2fe15d8c53a9ac0a3ed9deedbf69

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 15ac30fbc2be2fe15d8c53a9ac0a3ed9deedbf69

@spevans
Copy link
Contributor Author

spevans commented Jan 11, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please smoketest macos

@spevans
Copy link
Contributor Author

spevans commented Jan 11, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please smoke test macos

@spevans
Copy link
Contributor Author

spevans commented Jan 11, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test macos

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 3b25795

@spevans
Copy link
Contributor Author

spevans commented Jan 11, 2020

I think I missed it or something ... why not use the parsing logic even for the shared linking?

This will only parse 1 ELF file and wont handle the extra shared libraries that are dynamically linked in or their relocations. There would also be no benefit to replacing a platform's dladdr() even if a full implementation was written.

@spevans
Copy link
Contributor Author

spevans commented Jan 12, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test macos

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 3b25795

Copy link
Member

@compnerd compnerd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will only parse 1 ELF file and wont handle the extra shared libraries that are dynamically linked in or their relocations. There would also be no benefit to replacing a platform's dladdr() even if a full implementation was written.

The registration is per module, and is not shared across dynamically shared libraries. I think that you are focusing too much about the fact that there is a wrapper for the dladdr in this file. That doesn't really belong in there, it was just convenient for it to get placed there I think.

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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--defsym creating a strong reference sounds like a bug. If you want to create a strong reference, you should use --require-defined or -u at the very least.

@spevans
Copy link
Contributor Author

spevans commented Jan 13, 2020

Please test with following pull request:
swiftlang/swift-integration-tests#69

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - 3b25795

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - 3b25795

@jckarter
Copy link
Contributor

lookupSymbol should only be used for attempting to symbolicate stack traces, so if it's slow or doesn't work 100% of the time that shouldn't be a showstopper. @drexin had been looking into more robust symbolication using addr2line style DWARF line table decoding which might be able to supersede our use of dladdr as well.

@spevans
Copy link
Contributor Author

spevans commented Jan 13, 2020

Thats correct, its only really used for stack traces hence why it doesnt matter too much if the mmap fails etc. How would the alternative work if there was not DWARF data?

@spevans
Copy link
Contributor Author

spevans commented Jan 16, 2020

@compnerd FYI: the reason for the ImageInspectionShared / ImageInspectionStatic split is mostly due to not wanting to export dladdr in the static case. See the discussion in #5394 from when the lookupSymbol was added.

@jckarter
Copy link
Contributor

Thats correct, its only really used for stack traces hence why it doesnt matter too much if the mmap fails etc. How would the alternative work if there was not DWARF data?

For server side work, I think we'd want to encourage building with at least -gline-tables-only as the standard configuration, to enable better quality runtime diagnostics and backtraces. We could still try dladdr as a best effort thing, maybe.

@compnerd FYI: the reason for the ImageInspectionShared / ImageInspectionStatic split is mostly due to not wanting to export dladdr in the static case. See the discussion in #5394 from when the lookupSymbol was added.

IIRC, at some point ImageInspectionStatic also resolved the registration tables completely statically at some point, rather than relying on iterating through images with libdl API that wouldn't be available in a static executable.

@spevans
Copy link
Contributor Author

spevans commented Feb 10, 2020

After checking the man pages and doing a test I found that dladdr only finds symbols in .so libraries and not in the main executable - this probably explains why the stack traces aren't very good on Linux:

$ cat dltest.c
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>


void show(void *addr) {
  Dl_info info = {};

  int ret = dladdr(addr, &info);

  if (ret) {
    printf("fname: %s\n", info.dli_fname);
    printf("fbase: %p\n", info.dli_fbase);
    printf("sname: %s\n", info.dli_sname);
    printf("saddr: %p\n\n", info.dli_saddr);
  } else {
    printf("Cant get dladdr\n\n");
  }
}


int main() {
  show(main);
  show(printf);
  return 0;
}

$ clang -Wall -static -O  -o dltest-static dltest.c -ldl
$ ./dltest-static 
Cant get dladdr

Cant get dladdr

$ clang -Wall -O -o dltest-dynamic dltest.c -ldl
$ ./dltest-dynamic 
fname: ./dltest-dynamic
fbase: 0x400000
sname: (null)
saddr: (nil)

fname: ./dltest-dynamic
fbase: 0x400000
sname: printf
saddr: 0x400490

So dladdr cant be used in a static binary.

@weissi
Copy link
Contributor

weissi commented Feb 11, 2020

@spevans I think more than main bin vs library, IIRC dladdr can only be used on exported symbols. So it’ll work on printf because that’s exported but it won’t on main or other non-exported functions like anything private in Swift or a static function in C. So I don’t think we can it for anything much in either static or dynamic binaries

@shahmishal
Copy link
Member

Please update the base branch to main by Oct 5th otherwise the pull request will be closed automatically.

  • How to change the base branch: (Link)
  • More detail about the branch update: (Link)

@spevans
Copy link
Contributor Author

spevans commented Oct 5, 2020

An updated and more simplified version of this pr is #34180

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants