Biohazrd icon indicating copy to clipboard operation
Biohazrd copied to clipboard

Combine `LinkImportsTransformationElfTests` into `LinkImportsTransformationTests`

Open PathogenDavid opened this issue 2 years ago • 0 comments

(This issue is blocked because it'd be best implemented with features that will be added in xUnit v3. We might be able to figure out a more complex or less ideal way to go without though.)

As a part of https://github.com/InfectedLibraries/Biohazrd/issues/108 we introduced LinkImportsTransformationElfTests.

The vast majority of these tests are nearly identical between ELF .so shared library imports and library .lib archive imports.

I decided to keep them separate for now because the tests are not totally cross-platform and xUnit v2 does not support conditional skips. Right now the situation is:

  • LinkImportsTransformationTests are Windows-only due to dependence on the MSVC Librarian (which has no equivalent in the LLVM toolchain.)
  • LinkImportsTransformationElfTests is more complex:
    • Always required on Linux
    • Always required on CI
    • On Windows only runs if clang is installed on the system PATH or a Visual Studio install is found with the LLVM toolchain component.

If we merge our multiple xUnit facts into theories, we'd probably need to conditionally skip them based on the logic above. xUnit v3 is adding support for conditional skips (via Assert.Skip), but xUnit v3 is still in development.


Another major difference between the tests is how the symbols get exported. For the ELF tests we generate C/C++ code which is piped to clang and used to generate a shared library. For the LIB tests we pass one or more /EXPORT switches to the MSVC librarian.

The C/C++ code for ELF tests is generated based on a tiny DSL. The LIB tests use the format of the MSVC librarian directly.

We'd need to eliminate these differences. I think the easiest thing would be to use the DSL used for the ELF tests and extend it to cover the additional capabilities we need for the LIB tests (like ordinal exports.)


Another thing we could do while we're at it is to add support for running the LIB tests on Linux. We can use a strategy similar to how we the shared library for ELF tests on Windows by generating code and piping it to Clang.

I've confirmed that clang -fuse-ld=lld-link --no-standard-libraries --target=x86_64-pc-windows Library.cpp --shared --output=Library.dll on WSL can be used for this. One other difference is that we need to declare _DllMainCRTStartup since the CRT isn't providing it. void _DllMainCRTStartup() { } is sufficient for this. (It's not super clear what the actual signature of this is since you're not actually supposed to implement it yourself, but all we really need is a LIB file out of lld-link, we don't care about the DLL being usable for anything.)

Ordinals and other advanced exports can be accomplished with custom export arguments:

clang -fuse-ld=lld-link --no-standard-libraries --target=x86_64-pc-windows Library.cpp --shared --output=Library.dll --for-linker="-export:TestFunction,@3226,NONAME"

So in short, this is probably the overall strategy for accomplishing this:

  • [ ] Modify CreateImportLib to parse the DSL used for CreateSharedLibrary
    • Alternatively we could just require tests specify two definitions for complex exports. 99% of them are just a name.
  • [ ] Add support to CreateSharedLibrary to generate a Windows LIB+DLL instead
  • [ ] Add a shim between the tests and CreateImportLib/CreateSharedLibrary to select the appropriate implementation
  • [ ] Conditionally skip ELF tests when Clang is not present on non-CI Windows

PathogenDavid avatar Jul 31 '21 13:07 PathogenDavid