bflattened / bflat

C# as you know it but with Go-inspired tooling (small, selfcontained, and native executables)
GNU Affero General Public License v3.0
3.56k stars 102 forks source link

Building MOOS a native OS written in C# with BFLAT throws `'Expected type System.Runtime.InteropServices.Marshal' not found` in module 'MOOS' #95

Open xiaoyuvax opened 1 year ago

xiaoyuvax commented 1 year ago

Building MOOS - a native OS written in C# with BFLAT throws following error:

 bflat build @build.rsp...
Error: AggregateException_ctor_DefaultMessage (Code generation failed for method '[MOOS]Internal.Runtime.CompilerHelpers.ThrowHelpers.Error(string,bool)')
System.AggregateException: AggregateException_ctor_DefaultMessage (Code generation failed for method '[MOOS]Internal.Runtime.CompilerHelpers.ThrowHelpers.Error(string,bool)')
 ---> ILCompiler.CodeGenerationFailedException: Code generation failed for method '[MOOS]Internal.Runtime.CompilerHelpers.ThrowHelpers.Error(string,bool)'
 ---> System.InvalidOperationException: Expected type 'System.Runtime.InteropServices.Marshal' not found in module 'MOOS'
   at Internal.IL.HelperExtensions.GetKnownType(ModuleDesc, String, String) + 0xaa
   at Internal.TypeSystem.Interop.AnsiStringMarshaller.EmitCleanupManaged(ILCodeStream) + 0x5e
   at Internal.IL.Stubs.PInvokeILEmitter.EmitIL() + 0x112
   at Internal.IL.Stubs.PInvokeILEmitter.EmitIL(MethodDesc, PInvokeILEmitterConfiguration, InteropStateManager) + 0x81

Obviously, this is because Marshal.cs is absent from the trimmed custom Corlib framework in MOOS project (as u can see from the RSP file below), specified by <IlcSystemModule>MOOS</IlcSystemModule> in the csproj file. However, MOOS can be successfully compiled with MSBuild and then be compiled to native binary through ILCompiler and run on bare metal. I am trying to compile MOOS directly from source to native binary by BFLAT, but here comes the Marshal.cs problem, any hint to solve it?

RSP file contents (generated by BFlatA ):

-o MOOS.exe 
--target Exe 
--stdlib None 
-d Kernel 
-d UseAPIC 
-d HasGUI
d:\repos\moos\Corlib\Internal\Runtime\CompilerHelpers\ArrayHelpers.cs
d:\repos\moos\Corlib\Internal\Runtime\CompilerHelpers\InteropHelpers.cs
d:\repos\moos\Corlib\Internal\Runtime\CompilerHelpers\StartupCodeHelpers.cs
d:\repos\moos\Corlib\Internal\Runtime\CompilerHelpers\SynchronizedMethodHelpers.cs
d:\repos\moos\Corlib\Internal\Runtime\CompilerHelpers\ThrowHelpers.cs
d:\repos\moos\Corlib\Internal\Runtime\CompilerServices\Unsafe.cs
d:\repos\moos\Corlib\Internal\Runtime\EEType.cs
d:\repos\moos\Corlib\Internal\Runtime\ModuleHeaders.cs
d:\repos\moos\Corlib\Internal\Runtime\RuntimeConstants.cs
d:\repos\moos\Corlib\Internal\TypeSystem\ExceptionStringID.cs
d:\repos\moos\Corlib\System\Action.cs
d:\repos\moos\Corlib\System\AppContext.cs
d:\repos\moos\Corlib\System\Array.cs
d:\repos\moos\Corlib\System\Attribute.cs
d:\repos\moos\Corlib\System\AttributeUsageAttribute.cs
d:\repos\moos\Corlib\System\BitConverter.cs
d:\repos\moos\Corlib\System\BitHelpers.cs
d:\repos\moos\Corlib\System\Boolean.cs
d:\repos\moos\Corlib\System\Byte.cs
d:\repos\moos\Corlib\System\Char.cs
d:\repos\moos\Corlib\System\Collections\Generic\Dictionary.cs
d:\repos\moos\Corlib\System\Collections\Generic\List.cs
d:\repos\moos\Corlib\System\Collections\Generic\Queue.cs
d:\repos\moos\Corlib\System\ConsoleColor.cs
d:\repos\moos\Corlib\System\ConsoleKey.cs
d:\repos\moos\Corlib\System\ConsoleKeyInfo.cs
d:\repos\moos\Corlib\System\ConsoleKeyState.cs
d:\repos\moos\Corlib\System\ConsoleModifiers.cs
d:\repos\moos\Corlib\System\Convert.cs
d:\repos\moos\Corlib\System\DateTime.cs
d:\repos\moos\Corlib\System\Delegate.cs
d:\repos\moos\Corlib\System\Diagnostics\Debug.cs
d:\repos\moos\Corlib\System\Diagnostics\Process.cs
d:\repos\moos\Corlib\System\Diagnostics\Stopwatch.cs
d:\repos\moos\Corlib\System\Double.cs
d:\repos\moos\Corlib\System\Drawing\Color.cs
d:\repos\moos\Corlib\System\Drawing\Image.cs
d:\repos\moos\Corlib\System\Drawing\Point.cs
d:\repos\moos\Corlib\System\Drawing\Rectangle.cs
d:\repos\moos\Corlib\System\Drawing\Size.cs
d:\repos\moos\Corlib\System\EETypePtr.cs
d:\repos\moos\Corlib\System\Enum.cs
d:\repos\moos\Corlib\System\Environment.cs
d:\repos\moos\Corlib\System\EventArgs.cs
d:\repos\moos\Corlib\System\EventHandler.cs
d:\repos\moos\Corlib\System\FlagsAttribute.cs
d:\repos\moos\Corlib\System\Func.cs
d:\repos\moos\Corlib\System\Globalization\CharUnicodeInfo.cs
d:\repos\moos\Corlib\System\Globalization\CultureInfo.cs
d:\repos\moos\Corlib\System\Int16.cs
d:\repos\moos\Corlib\System\Int32.cs
d:\repos\moos\Corlib\System\Int64.cs
d:\repos\moos\Corlib\System\IntPtr.cs
d:\repos\moos\Corlib\System\Math.cs
d:\repos\moos\Corlib\System\MathF.cs
d:\repos\moos\Corlib\System\MulticastDelegate.cs
d:\repos\moos\Corlib\System\Net\IPAddress.cs
d:\repos\moos\Corlib\System\Nullable.cs
d:\repos\moos\Corlib\System\Object.cs
d:\repos\moos\Corlib\System\ObsoleteAttribute.cs
d:\repos\moos\Corlib\System\ParamArrayAttribute.cs
d:\repos\moos\Corlib\System\Random.cs
d:\repos\moos\Corlib\System\Reflection\DefaultMemberAttribute.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\DataDirectory.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\DllCharacteristicsType.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\DOSHeader.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\FileHeader.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\NtHeaders64.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\OptionalHeaders64.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\SectionHeader.cs
d:\repos\moos\Corlib\System\Reflection\PortableExecutable\SubSystemType.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\ClassConstructorRunner.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\ExtensionAttribute.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\IntrinsicAttribute.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\IsVolatile.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\MethodImplAttribute.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\RawCalliHelper.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\RuntimeHelpers.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\StaticClassConstructionContext.cs
d:\repos\moos\Corlib\System\Runtime\CompilerServices\TupleElementNamesAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\CallingConvention.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\DllImportAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\FieldOffsetAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\McgIntrinsicsAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\StructLayoutAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\SuppressGCTransition.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\UnmanagedCallersOnlyAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\UnmanagedFunctionPointerAttribute.cs
d:\repos\moos\Corlib\System\Runtime\InteropServices\UnmanagedType.cs
d:\repos\moos\Corlib\System\Runtime\RuntimeExportAttribute.cs
d:\repos\moos\Corlib\System\Runtime\TypeCast.cs
d:\repos\moos\Corlib\System\RuntimeFieldHandle.cs
d:\repos\moos\Corlib\System\RuntimeMethodHandle.cs
d:\repos\moos\Corlib\System\RuntimeType.cs
d:\repos\moos\Corlib\System\RuntimeTypeHandle.cs
d:\repos\moos\Corlib\System\SByte.cs
d:\repos\moos\Corlib\System\Single.cs
d:\repos\moos\Corlib\System\String.cs
d:\repos\moos\Corlib\System\System.SR.cs
d:\repos\moos\Corlib\System\Threading\Monitor.cs
d:\repos\moos\Corlib\System\TimeSpan.cs
d:\repos\moos\Corlib\System\Tuple.cs
d:\repos\moos\Corlib\System\UInt16.cs
d:\repos\moos\Corlib\System\UInt32.cs
d:\repos\moos\Corlib\System\UInt64.cs
d:\repos\moos\Corlib\System\UIntPtr.cs
d:\repos\moos\Corlib\System\ValueTuple.cs
d:\repos\moos\Corlib\System\ValueType.cs
d:\repos\moos\Corlib\System\Void.cs
d:\repos\moos\Corlib\System\Windows\Forms\Control.cs
d:\repos\moos\Corlib\System\Windows\Forms\MouseButtons.cs
d:\repos\moos\Kernel\Animation.cs
d:\repos\moos\Kernel\API.cs
d:\repos\moos\Kernel\AVX.cs
d:\repos\moos\Kernel\Driver\AC97.cs
d:\repos\moos\Kernel\Driver\ACPI.cs
d:\repos\moos\Kernel\Driver\ACPITimer.cs
d:\repos\moos\Kernel\Driver\EHCI.cs
d:\repos\moos\Kernel\Driver\ES1371.cs
d:\repos\moos\Kernel\Driver\Framebuffer.cs
d:\repos\moos\Kernel\Driver\HID.cs
d:\repos\moos\Kernel\Driver\HPET.cs
d:\repos\moos\Kernel\Driver\Hub.cs
d:\repos\moos\Kernel\Driver\IDE.cs
d:\repos\moos\Kernel\Driver\Intel8254X.cs
d:\repos\moos\Kernel\Driver\IOAPIC.cs
d:\repos\moos\Kernel\Driver\Keyboard.cs
d:\repos\moos\Kernel\Driver\LocalAPIC.cs
d:\repos\moos\Kernel\Driver\LocalAPICTimer.cs
d:\repos\moos\Kernel\Driver\PCI.cs
d:\repos\moos\Kernel\Driver\PCIExpress.cs
d:\repos\moos\Kernel\Driver\PIC.cs
d:\repos\moos\Kernel\Driver\PIT.cs
d:\repos\moos\Kernel\Driver\Power.cs
d:\repos\moos\Kernel\Driver\PS2Controller.cs
d:\repos\moos\Kernel\Driver\PS2Keyboard.cs
d:\repos\moos\Kernel\Driver\PS2Mouse.cs
d:\repos\moos\Kernel\Driver\Ramdisk.cs
d:\repos\moos\Kernel\Driver\RTC.cs
d:\repos\moos\Kernel\Driver\RTL8139.cs
d:\repos\moos\Kernel\Driver\SATA.cs
d:\repos\moos\Kernel\Driver\Serial.cs
d:\repos\moos\Kernel\Driver\SMBIOS.cs
d:\repos\moos\Kernel\Driver\Timer.cs
d:\repos\moos\Kernel\Driver\VMWareSVGAII.cs
d:\repos\moos\Kernel\Driver\VMwareTools.cs
d:\repos\moos\Kernel\FS\Disk.cs
d:\repos\moos\Kernel\FS\FAT32.cs
d:\repos\moos\Kernel\FS\FATFS.cs
d:\repos\moos\Kernel\FS\FileSystem.cs
d:\repos\moos\Kernel\FS\TarFS.cs
d:\repos\moos\Kernel\Graph\Graphics.cs
d:\repos\moos\Kernel\Graph\VMWareSVGAIIGraphics.cs
d:\repos\moos\Kernel\Misc\Allocator.cs
d:\repos\moos\Kernel\Misc\ASC16.cs
d:\repos\moos\Kernel\Misc\Audio.cs
d:\repos\moos\Kernel\Misc\BitFont.cs
d:\repos\moos\Kernel\Misc\Bitmap.cs
d:\repos\moos\Kernel\Misc\ClassID.cs
d:\repos\moos\Kernel\Misc\Console.cs
d:\repos\moos\Kernel\Misc\CPUID.cs
d:\repos\moos\Kernel\Misc\EntryPoint.cs
d:\repos\moos\Kernel\Misc\FPSMeter.cs
d:\repos\moos\Kernel\Misc\GDT.cs
d:\repos\moos\Kernel\Misc\IDT.cs
d:\repos\moos\Kernel\Misc\IFont.cs
d:\repos\moos\Kernel\Misc\Interrupts.cs
d:\repos\moos\Kernel\Misc\MMIO.cs
d:\repos\moos\Kernel\Misc\Multiboot.cs
d:\repos\moos\Kernel\Misc\Native.cs
d:\repos\moos\Kernel\Misc\NativeCS.cs
d:\repos\moos\Kernel\Misc\PageTable.cs
d:\repos\moos\Kernel\Misc\Panic.cs
d:\repos\moos\Kernel\Misc\PNG.cs
d:\repos\moos\Kernel\Misc\Threading.cs
d:\repos\moos\Kernel\Misc\USB.cs
d:\repos\moos\Kernel\Misc\VendorID.cs
d:\repos\moos\Kernel\Misc\WAV.cs
d:\repos\moos\Kernel\NET\ARP.cs
d:\repos\moos\Kernel\NET\Ethernet.cs
d:\repos\moos\Kernel\NET\IPv4.cs
d:\repos\moos\Kernel\NET\MACAddress.cs
d:\repos\moos\Kernel\NET\Network.cs
d:\repos\moos\Kernel\NET\NIC.cs
d:\repos\moos\Kernel\NET\UDP.cs
d:\repos\moos\Kernel\SMP.cs
d:\repos\moos\Kernel\SSE.cs
d:\repos\moos\Kernel\stdio.cs
d:\repos\moos\Kernel\stdlib.cs
d:\repos\moos\Kernel\strings.cs
d:\repos\moos\Kernel\VHD.cs
d:\repos\moos\MOOS\GUI\Calculator.cs
d:\repos\moos\MOOS\GUI\Clock.cs
d:\repos\moos\MOOS\GUI\Desktop.cs
d:\repos\moos\MOOS\GUI\FConsole.cs
d:\repos\moos\MOOS\GUI\ImageViewer.cs
d:\repos\moos\MOOS\GUI\Lockscreen.cs
d:\repos\moos\MOOS\GUI\MessageBox.cs
d:\repos\moos\MOOS\GUI\Monitor.cs
d:\repos\moos\MOOS\GUI\NotificationManager.cs
d:\repos\moos\MOOS\GUI\Paint.cs
d:\repos\moos\MOOS\GUI\PortableApp.cs
d:\repos\moos\MOOS\GUI\RightMenu.cs
d:\repos\moos\MOOS\GUI\Snake.cs
d:\repos\moos\MOOS\GUI\WAVPlayer.cs
d:\repos\moos\MOOS\GUI\Welcome.cs
d:\repos\moos\MOOS\GUI\Widgets\Button.cs
d:\repos\moos\MOOS\GUI\Widgets\Widget.cs
d:\repos\moos\MOOS\GUI\Window.cs
d:\repos\moos\MOOS\GUI\WindowManager.cs
d:\repos\moos\MOOS\Program.cs
--ldflags d:\repos\moos\x64\Debug\Doom.lib
--ldflags d:\repos\moos\x64\Debug\LibC.lib
--ldflags d:\repos\moos\x64\Debug\NativeLib.lib
MichalStrehovsky commented 1 year ago

That sounds like missing -i parameters. Moos probably sets it as directpinvoke.

xiaoyuvax commented 1 year ago

Can u be more specific? by explaining the -i <library|library!function> option or at least in my case, what should i do?

do u mean like for each:

       [DllImport("WriteLine")]
        public static extern void WriteLine();

        [DllImport("Allocate")]
        public static extern nint Allocate(ulong size);

        [DllImport("Free")]
        public static extern ulong Free(nint ptr);

add -i options like below?

-i MOOS!WriteLine
-i MOOS!Allocate
-i MOOS!Free

Can't these be universally set?

I tried -i MOOS, seems still not working.

MichalStrehovsky commented 1 year ago

No, this would be -i WriteLine -i Allocate, etc. The way DllImports are set up in MOOS is super weird. Normally the thing in the DllImport string is the name of the DLL. Since you have a fork, you migth as well change the DllImport declarations to be DllImport("*") (some are already like that). Those work out of the box.

xiaoyuvax commented 1 year ago

change the DllImport declarations to be DllImport("*") doesn't work, the compiler throws weird error.

I checked with the code, such [DllImport("SayHello")] is used as a symbol for the interrrupt handlers written in masm to identify the name of the function for handling system api call, as shown below: image

image

as for the -i option, one by one?!! it's really heartwarming ~~~ ps. i'd really expect an one off switch-on for the entire module in the next version of bflat.

MichalStrehovsky commented 1 year ago

Ah, I see. Now I understand why the DllImports are so weird. Adding -i is not the solution. MOOS expects that these will be lazy resolved.

This is failing because the support for ansi string marshalling is not present in MOOS corelib. MOOS is compiled using an ancient version of NativeAOT. You can find the current version of AnsiStringMarshaller class (that is in the failing callstack) here:

https://github.com/dotnet/runtime/blob/99aa25fee09a3a66fb698720a234eb3d7770ca1a/src/coreclr/tools/Common/TypeSystem/Interop/IL/Marshaller.cs#L1583

You need to apply https://github.com/dotnet/runtime/commit/e22c63e2fa78931c6a4802e555370324c34475bd to MOOS corelib. You'll see that MOOS has the "InteropHelpers.CoTaskMemFree" in corelib, but doesn't have "Marshal.FreeCoTaskMem". The fix is to create it.

xiaoyuvax commented 1 year ago

See if i understood correctly: CoTaskMemFree() has been removed in the new version of compiler, so i have to amend its implementation for bflat to compile, right? but in the source of nativeAot, this method is actually implemented through ole32.dll (for windows), what can i do in MOOS then?

so, i just added a Marshal class with a sole FreeCoTaskMem() method and the compiling seems done. image

but the linker throws some errors:

- Executing building script: bflat build @build.rsp...
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.As<__Canon,native int>(__Canon&)' will always throw because: Invalid IL or CLR metadata in 'IntPtr ByRef Internal.Runtime.CompilerServices.Unsafe.As(System.__Canon ByRef)'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.As<native int,__Canon>(native int&)' will always throw because: Invalid IL or CLR metadata in 'System.__Canon ByRef Internal.Runtime.CompilerServices.Unsafe.As(IntPtr ByRef)'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.SizeOf<GDTEntry>()' will always throw because: Invalid IL or CLR metadata in 'Int32 Internal.Runtime.CompilerServices.Unsafe.SizeOf()'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.SizeOf<TSS>()' will always throw because: Invalid IL or CLR metadata in 'Int32 Internal.Runtime.CompilerServices.Unsafe.SizeOf()'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.AsPointer<IDTEntry>(IDTEntry&)' will always throw because: Invalid IL or CLR metadata in 'Void* Internal.Runtime.CompilerServices.Unsafe.AsPointer(IDTEntry ByRef)'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.Add<char>(char&,int32)' will always throw because: Invalid IL or CLR metadata in 'Char ByRef Internal.Runtime.CompilerServices.Unsafe.Add(Char ByRef, Int32)'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.As<bool,uint64>(bool&)' will always throw because: Invalid IL or CLR metadata in 'UInt64 ByRef Internal.Runtime.CompilerServices.Unsafe.As(Boolean ByRef)'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.As<__Canon>(object)' will always throw because: Invalid IL or CLR metadata in 'System.__Canon Internal.Runtime.CompilerServices.Unsafe.As(System.Object)'
ILC: Method '[MOOS]Internal.Runtime.CompilerServices.Unsafe.As<__Canon,__Canon>(__Canon&)' will always throw because: Invalid IL or CLR metadata in 'System.__Canon ByRef Internal.Runtime.CompilerServices.Unsafe.As(System.__Canon ByRef)'
lld: error: could not open 'MSVCRTD.lib': No such file or directory
lld: error: could not open 'OLDNAMES.lib': No such file or directory
lld: error: duplicate symbol: free in MOOS.obj and in api-ms-win-crt-heap-l1-1-0.dll
lld: error: duplicate symbol: malloc in MOOS.obj and in api-ms-win-crt-heap-l1-1-0.dll
lld: error: duplicate symbol: realloc in MOOS.obj and in api-ms-win-crt-heap-l1-1-0.dll
lld: error: duplicate symbol: memcpy in MOOS.obj and in shcrt.lib(nocrt.cpp.obj)
lld: error: duplicate symbol: memset in MOOS.obj and in shcrt.lib(nocrt.cpp.obj)
Compiler exit code:1
MichalStrehovsky commented 1 year ago

CoTaskMemFree is an empty method in MOOS, so I would implement FreeCoTaskMem as an empty method too.

The Unsafe class moved from Internal.Runtime.CompilerServices to System.Runtime.CompilerServices, so you should also update MOOS to get rid of the warnings.

Adding --libc none to bflat build might get rid of the lld errors.

xiaoyuvax commented 1 year ago

the duplicated symbols are eliminated by adding --libc none, only the last two errors left:

lld: error: could not open 'MSVCRTD.lib': No such file or directory
lld: error: could not open 'OLDNAMES.lib': No such file or directory
xiaoyuvax commented 1 year ago

I solve it by copying these two files from vc15 to building path. now it's done! ;))) don't know if the binary would run... go on building the system image.

xiaoyuvax commented 1 year ago

Final outcome report: The MOOS.exe built by bflat is much smaller than that compiled by ILCompiler and is not runnable after being packed to system image. without the kernel.map file due to lld.exe not supporting /map: option, i can't compare the compiling result to see if it's right.

MichalStrehovsky commented 1 year ago

If you compile with -c, you can use link.exe on the generated obj file and get a map file that way

xiaoyuvax commented 1 year ago

ah, yes, i did have thought of using MSVC Linker, after i found out that lld.exe in bflat path looks actually like MSVC linker.

I checked the map, and found the most important init methods such as Entry() , KMain() were all missing in the exe built by bflat. No idea why.

 [RuntimeExport("Entry")]
        public static void Entry(MultibootInfo* Info, IntPtr Modules, IntPtr Trampoline)
        { ...

  [RuntimeExport("KMain")]
    static void KMain()
    { ...

Instead, i used ObjectDump to have extracted the map for MOOS.obj, where i can see the symbols for Entry() and KMain(), don't know why they disappear after linking.

MichalStrehovsky commented 1 year ago

Does moos pass a /def parameter to link.exe to make it exported?

xiaoyuvax commented 1 year ago

linker args do not include /def in moos.csproj and i don't see any .def files in the project path

i am not sure if linker should know any of these settings in .csproj file: especially the EntryPointSymbol must be specified somehow? Would IlcSystemModule and RuntimeAssembly mean something to linker? and there is also a CustomizeReferences section, it is also suspected to do something with the output? ...

<IlcSystemModule>MOOS</IlcSystemModule>
<EntryPointSymbol>Entry</EntryPointSymbol>
<LinkerSubsystem>NATIVE</LinkerSubsystem>
<IlcOptimizationPreference>Size</IlcOptimizationPreference>
...

<!--CustomizeReferences-->
    <Target Name="CustomizeReferences" BeforeTargets="BeforeCompile" AfterTargets="FindReferenceAssembliesForReferences">
        <ItemGroup>
            <ReferencePathWithRefAssemblies Remove="@(ReferencePathWithRefAssemblies)" Condition="%(Filename) != 'Corlib'" />
            <ReferencePath Remove="@(ReferencePath)" />
        </ItemGroup>
    </Target>

...
    <RuntimeAssembly Include="MOOS"></RuntimeAssembly>
xiaoyuvax commented 1 year ago

update: Yes, after adding /Entry:Entry to the linker args, now the exe file's size grows larger, and the Entry symbol appears. the exe size is 376kb while moos original compiled is 426kb, still some significant difference.

xiaoyuvax commented 1 year ago

update FINALLY!: i used -x option upon MSBuild to have got and applied the exact args of the linker, now the exe image generated from bflat + linker.exe is exact the same size with that generated by MSBuild+ILCompiler, now the OS is running.

the args that finally work:

"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64\link.exe" MOOS.obj /out:"MOOS.exe" ^
d:\repos\moos\x64\Debug\Doom.lib ^
d:\repos\moos\x64\Debug\LibC.lib ^
d:\repos\moos\x64\Debug\NativeLib.lib ^
/LIBPATH:"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.35.32215\lib\x64" ^
/LIBPATH:"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64" ^
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" ^
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" ^
D:\Repos\MOOS\MOOS\obj\Debug\net7.0\win-x64\native\MOOS.res ^
/fixed /base:0x10000000 /map:Kernel.map /NOLOGO /MANIFEST:NO /DEBUG /INCREMENTAL:NO /SUBSYSTEM:NATIVE /ENTRY:Entry

i also tested lld.exe comes with bflat with following args:

d:\bflat\bin\lld.exe -flavor link MOOS.obj /out:"MOOS.exe" ^
d:\repos\moos\x64\Debug\Doom.lib ^
d:\repos\moos\x64\Debug\LibC.lib ^
d:\repos\moos\x64\Debug\NativeLib.lib ^
/LIBPATH:"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.35.32215\lib\x64" ^
/LIBPATH:"C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64" ^
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\lib\10.0.22621.0\ucrt\x64" ^
/LIBPATH:"C:\Program Files (x86)\Windows Kits\10\\lib\10.0.22621.0\\um\x64" ^
D:\Repos\MOOS\MOOS\obj\Debug\net7.0\win-x64\native\MOOS.res ^
/fixed /base:0x10000000 /NOLOGO /MANIFEST:NO /DEBUG /INCREMENTAL:NO /SUBSYSTEM:NATIVE /ENTRY:Entry 

it still throws the following errors relatied to lib path:"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.35.32215\lib\x64" but is not seen with linker.exe

lld: error: undefined symbol: __guard_eh_cont_table
>>> referenced by MSVCRTD.lib(loadcfg.obj):(_load_config_used)

lld: error: undefined symbol: __guard_eh_cont_count
>>> referenced by MSVCRTD.lib(loadcfg.obj):(_load_config_used)

Summary: now i'd expect bflat solve following issues as to make the toolchain from BFlatA -> BFlat -> lld to work fluently on building such a project like MOOS: 1) correctly pass paths strings with spaces to lld, where quotes being correctly passed to the linker, now the chain is stuck here! 2) solve the "undefined symbol" errors lld throws, which is not seen with linker.exe. 3) lld.exe should support /map: option as linker.exe do. 4) Allow fully controlling args passing to the linker, bflat seemingly adds certain assumed default args which is not necessary in some case.

xiaoyuvax commented 1 year ago

Why can't i find this res file with BFlat after compiling? seems a must for MOOS, seen in both moos.ilc.rsp and linker.rsp, even no much content inside. @MichalStrehovsky D:\Repos\MOOS\MOOS\obj\Debug\net7.0\win-x64\native\MOOS.res

MichalStrehovsky commented 1 year ago

The rest file contains the Win32 resources of the module. It will probably be Win32 version resource. Bflat doesn't currently generate it.

xiaoyuvax commented 1 year ago

So sad and weird, can't reproduce runnable image of MOOS any more after last success, even the image is successfully built. No idea of what's wrong.

xiaoyuvax commented 1 year ago

Seems related to the customized Internal.Runtime.CompilerHelpers.StartupCodeHelpers.InitializeModules() of MOOS (if compiled with bflat, no problem with MSBuild + ILCompiler) , which calls its method: private static unsafe void InitializeStatics(IntPtr rgnStart, IntPtr rgnEnd) as shown below and error occurs at the marked line. It seems that *pBlock cannot be accessed at that address (or may be out of memory range).

image

Corresponding COM output: image

MichalStrehovsky commented 1 year ago

The format of the table changed like this: https://github.com/dotnet/runtime/commit/1771d63827387b49dcd8c33b95f1512f4f11e368

Bflat 0.0.8 would probably still work. Anything newer had that change.

xiaoyuvax commented 1 year ago

Bingo! thanks for your link! I simply copied the ReadRelPtr32() method and applied it on the problematic pointers, everything come back to normal. Now MOOS runs smoothly. Bflat is proved to be an alternative and even prefered compiler for building such a project like MOOS.

xiaoyuvax commented 1 year ago

Finally, I wrote a text to introduce how to build MOOS with BFlat as a summary: https://github.com/xiaoyuvax/MOOS/blob/master/MOOS.bflat.md

MichalStrehovsky commented 1 year ago

Finally, I wrote a text to introduce how to build MOOS with BFlat as a summary: https://github.com/xiaoyuvax/MOOS/blob/master/MOOS.bflat.md

Very cool! Thanks for sharing!