Skip to content

Export DotNetRuntimeInfo symbol from singlefile host#47299

Merged
6 commits merged intodotnet:masterfrom
VSadov:debSF
Jan 22, 2021
Merged

Export DotNetRuntimeInfo symbol from singlefile host#47299
6 commits merged intodotnet:masterfrom
VSadov:debSF

Conversation

@VSadov
Copy link
Member

@VSadov VSadov commented Jan 21, 2021

@ghost ghost added the area-Host label Jan 21, 2021
@VSadov
Copy link
Member Author

VSadov commented Jan 21, 2021

Windows:

Dump of file C:\Hosting01\runtime\artifacts\obj\win-x64.Debug\corehost\cli\apphost\static\Debug\singlefilehost.exe

File Type: EXECUTABLE IMAGE

  Section contains the following exports for singlefilehost.exe

    00000000 characteristics
    FFFFFFFF time date stamp
        0.00 version
           1 ordinal base
           1 number of functions
           1 number of names

    ordinal hint RVA      name

          1    0 02DABF30 DotNetRuntimeInfo = ?DotNetRuntimeInfo@@3U_RuntimeInfo@@A (struct _RuntimeInfo DotNetRuntimeInfo)

@VSadov
Copy link
Member Author

VSadov commented Jan 21, 2021

Linux:

 nm -D --defined-only /SSD/vsadov/hosting01/runtime/artifacts/bin/linux-x64.Release/corehost/singlefilehost
0000000000bdce98 D DotNetRuntimeInfo
0000000000000000 A V1.0

@VSadov
Copy link
Member Author

VSadov commented Jan 21, 2021

OSX:

 nm -gU  ./artifacts/bin/osx-x64.Release/corehost/singlefilehost
000000010081b200 D _DotNetRuntimeInfo

@dotnet dotnet deleted a comment Jan 21, 2021
@VSadov VSadov marked this pull request as ready for review January 21, 2021 23:24
@VSadov VSadov requested review from janvorli and mikem8361 January 21, 2021 23:24
@VSadov
Copy link
Member Author

VSadov commented Jan 21, 2021

/cc: @tommcdon


// Runtime information public export
#ifdef HOST_UNIX
DLLEXPORT
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure I understand this change. Unless I am missing something, the DLLEXPORT is defined as __attribute__((visibility("default"))).

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm. I think it did not work or was not defined in the context of this file. I will try reverting this line change.

Copy link
Member Author

Choose a reason for hiding this comment

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

Works now with DLLEXPORT. I am not sure where it is defined, since this file seems to include only windows.h, but somehow it works now.

Copy link
Member

Choose a reason for hiding this comment

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

this file seems to include only windows.h

This windows.h is actually the one in runtime sources, which includes this chain of headers: palrt.h->pal.h->palinternal.h->mbusafecrt_internal.h to obtain the definition from:

Copy link
Member

@janvorli janvorli left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

@VSadov
Copy link
Member Author

VSadov commented Jan 22, 2021

Thanks!!!

@ghost
Copy link

ghost commented Jan 22, 2021

Hello @VSadov!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

${NATIVE_LIBS}

${START_WHOLE_ARCHIVE}
${RUNTIMEINFO_LIB}
Copy link
Member

Choose a reason for hiding this comment

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

From the latest installer build, it seems like we have dynamic linkage on linux in statically linked sinlgefilehost (although overrider counterparts are present and should be used instead?):

$ ldd -r ~/.dotnet6/packs/Microsoft.NETCore.App.Host.linux-x64/6.0.0-preview.2.21105.12/runtimes/linux-x64/native/singlefilehost 
	linux-vdso.so.1 (0x00007fffd091a000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa96ea21000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa96e81d000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fa96e600000)
	libgssapi_krb5.so.2 => /usr/lib/x86_64-linux-gnu/libgssapi_krb5.so.2 (0x00007fa96e3b5000)
	librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa96e1ad000)
	libanl.so.1 => /lib/x86_64-linux-gnu/libanl.so.1 (0x00007fa96dfa9000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fa96dc20000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa96d882000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa96d66a000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa96d279000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fa96f66f000)
	libkrb5.so.3 => /usr/lib/x86_64-linux-gnu/libkrb5.so.3 (0x00007fa96cfa3000)
	libk5crypto.so.3 => /usr/lib/x86_64-linux-gnu/libk5crypto.so.3 (0x00007fa96cd71000)
	libcom_err.so.2 => /lib/x86_64-linux-gnu/libcom_err.so.2 (0x00007fa96cb6d000)
	libkrb5support.so.0 => /usr/lib/x86_64-linux-gnu/libkrb5support.so.0 (0x00007fa96c962000)
	libkeyutils.so.1 => /lib/x86_64-linux-gnu/libkeyutils.so.1 (0x00007fa96c75e000)
	libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007fa96c544000)

is this correct that dynamic linkages are not stripped?

Copy link
Member

Choose a reason for hiding this comment

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

@am11 do you mean all the libraries listed above? If it is the case, we don't want to statically link 3rd party libraries. The reason is that this way, we get potential fixes to those libraries through the repo and we don't need to release updated host every time one of those get some important fix. In some of them, I think it would be even a licensing problem.

Copy link
Member

@am11 am11 Feb 9, 2021

Choose a reason for hiding this comment

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

@janvorli, yup, it looks like libunwind and libsssl are statically linked in the binary. When I read about "super host" in the design doc: https://github.com/dotnet/designs/blob/5a6bf8fef1b072a7ed578a23dbd3d2ee7dd89d11/accepted/2020/single-file/design.md#host-builds, I was under the impression that:

$ file singlefilehost | fold -72
singlefilehost: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Lin
ux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildI
D[sha1]=27997343859af70e0bfc5e50a4d1059b3513a1c4, for GNU/Linux 2.6.32, 
stripped, too many notes (256)

will just become

$ file singlefilehost | fold -72
singlefilehost ELF 64-bit LSB executable, x86-64, version 1 (SYSV), stat
ically linked, with debug_info, not stripped

Maybe objects file could be provided so folks can statically link their apps?

Copy link
Member

Choose a reason for hiding this comment

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

libssl is not statically linked, but we load it dynamically, so it is not on the direct dependencies list. As for providing object files, that sounds like an interesting idea. However, linking e.g. standard c library statically is almost never a good idea. The problem is that a 3d party shared library used in some user code DllImport would most likely be dynamically linked to libc and mixing two libcs in one process is a recipe for problems.

Copy link
Member

Choose a reason for hiding this comment

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

For reference, in node.js this is possible:

$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
$ nvm install 12.9.1
$ npm install nexe
$ echo 'console.log("Hello World!");' > hi.js

# static
$ nexe -t static hi.js
$ file hi | fold -72
hi: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically link
ed, with debug_info, not stripped

# dynamic
$ nexe hi.js
$ file hi | fold -72
hi: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), dynamicall
y linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,
 BuildID[sha1]=3cb1a5d531f2b89baef69d5bbb4f0688959a572e, with debug_info
, not stripped

Copy link
Member

Choose a reason for hiding this comment

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

I know, I have noticed this a long time ago when I was enabling portable runtime builds. Their repo contains copies of source all of their dependencies except of standard c/c++ libraries (about 16 libraries). I guess that they took the risk of possibility of having multiple standard C libraries in the same process.
This is an interesting write-up I've used as a source of details on creating portable binaries for Linux at that time:
https://insanecoding.blogspot.com/2012/07/creating-portable-linux-binaries.html

Copy link
Member

@am11 am11 Feb 10, 2021

Choose a reason for hiding this comment

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

Thank you for sharing the link! :)

Ultimately I am trying to build a bootable image out of singlefilehost linked to a new cloud-oriented unikernel nanos (utsname->sysname: 'pugnix'): https://github.com/nanovms/nanos/blob/9b43cfcb6dedad4c896c4efc2173336c4f83f71a/src/unix/syscall.c#L1527-L1529. It is basically a light-weight implementation of Linux kernel interface, with stubbed out syscalls and libc (klib). The produced .img file out of user app has a slim bootloader, that can be burned to a bootable device as well as deployed to cloud: HyperV in Azure, run with qemu etc. Basically the concept is: "your one (and only one) app is the OS" (almost) so there is very limited surface area for vulnerabilities (and other positive/negative virtues of a general-purpose OS kernel). There was an attempt for .NET5 (and also .NET6) singlefile app: nanovms/ops-examples#47 but scenario is not fully functional yet (that bootable myapp1.img is 109M; OS+silefileapp+deps).

The ideal situation for app for unikernel environment is: it is statically linked and has embedded (native) debug symbols (.debug_info and other .debug_* ELF sections instead of .gnu_debuglink pointing to .dbg file, which we currently have). I think that can be achieved if a separate runtime pack provides the object files and a recipie to embed debug symbols (for app built with Debug configuration). However, dynamic binaries work but with --debug switch in their tooling, fails these two validations. Therefore, I opted for --trace option to track down coreclr_initialize failures.

@ghost ghost locked as resolved and limited conversation to collaborators Mar 12, 2021
This pull request was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants