ltrzesniewski / InlineIL.Fody

Inject arbitrary IL code at compile time.
MIT License
240 stars 17 forks source link

Invalid assembly after weaving #4

Closed jp2masa closed 5 years ago

jp2masa commented 5 years ago

Not sure if this is an InlineIL.Fody, Fody or Mono.Cecil bug.

Repro: https://github.com/CosmosOS/Cosmos/tree/inline-il

The verification fails, and if I try to load the assembly at runtime it fails with BadImageFormatException. ILSpy loads it correctly.

I tried adding ExcludeAssets="All" here: Cosmos.Core_Asm.csproj#L13, and then used ildasm on both assemblies, and the main difference (ignoring the parts which were not weaved) is the .imagebase, which is 0x00400000 when weaved, and 0x10000000 when not.

Any help would be appreciated.

ltrzesniewski commented 5 years ago

I isolated your method in an empty project, and it seems to work correctly.

Verification fails because your code is unverifiable. See if your code works when you remove VerifyAssembly="True". A failed verification causes the build to fail anyway.

If this doesn't solve your issue, please send me an isolated repro - something I can just compile and test by myself. The IDE.sln from your branch doesn't compile because of missing projects, and I don't know anything about CosmOS.

FYI .imagebase is hardcoded by Cecil. This shouldn't be an issue unless CosmOS messes with relocations.


As an aside:

Your code is unverifiable because you're taking a pointer to a (non-pinned) managed object, which will not be tracked by the GC, and could lose track of the underlying object if a compacting GC pass happens while your code is executing. In your case that is unlikely to happen, given that the disassembly of the method is:

00007ff8`fab90500 488bc1          mov     rax,rcx
00007ff8`fab90503 8b4008          mov     eax,dword ptr [rax+8]
00007ff8`fab90506 c3              ret

But here's how I'd write the same method, using managed references instead of pointers, which are tracked by the GC:

public static int get_Length(Array aThis)
{
    IL.DeclareLocals(
        false,
        typeof(int).MakeByRefType()
    );

    Ldarg_0();
    Stloc_0();
    Ldloc_0();
    Ldc_I4(8);
    Add();
    Ldind_I4();

    return IL.Return<int>();
}

Don't worry about the local, this generates the same assembly code while being "safer" should the JIT not compile the method to a single assembly instruction.

jp2masa commented 5 years ago

I tried it in an isolated project (the same code and some unsafe C# code that I added to another method just to make sure) and the verification is successful (it shouldn't I guess, because the code is unverifiable). But in that project (I tried on other project, without the underscore) it fails, and the only unexpected change on the diff was the .imagebase (which may be unrelated), but I have no idea why it's failing. I also thought that the problem could be assembly signing, but I tried it in the isolated project and it worked fine (and the IL diff doesn't show any problem with that). I'll try diffing the isolated project assemblies and will report the results here today or tomorrow.

Also, sorry for a somewhat bad repro. Cosmos doesn't "mess" with relocations, simply using Assembly.Load fails with a BadImageFormatException, so the runtime doesn't "like" the assembly.

I understand about pinning, I honestly forgot about that, but I don't believe that's related to this problem.

This project would be really helpful for Cosmos, as we have some assembly code, and replacing most of it with IL, which is really easy with this project, would be really good for us. Unfortunately, I'm hitting this error which is totally unexpected.

Thanks for the help.

jp2masa commented 5 years ago

It looks like, in the isolated project, the diff is really minimal (only expected parts). On the other project, there are differences in the order of assembly attributes (no idea why that's happening), and .imagebase, so the problem is likely the .imagebase.

ltrzesniewski commented 5 years ago

Nope, pinning is not related - I just wanted to bring it to your attention as an aside.

BadImageFormatException is a weird exception to get... I suppose you already checked that your assembly targets a platform that is compatible with the process that calls Assembly.Load. The order of assembly attributes shouldn't matter. I guess they're reordered because Cecil doesn't care about the order, but I didn't check.

Did you build in debug or release mode? Try release mode just in case, there may be a bug in the way InlineIL generates sequence points in debug mode.

ltrzesniewski commented 5 years ago

BTW in an isolated project, verification fails for me as expected when I target net472, but succeeds when I target netcoreapp2.1:

1>  Fody: Fody (version 3.2.9.0) Executing
1>  Fody: Searched for 'InlineIL'. Found: C:\Users\Lucas\.nuget\packages\inlineil.fody\1.0.0\build\..\netclassicweaver\InlineIL.Fody.dll
1>  Fody: Fody (version 3.2.9.0) Executing
1>  Fody: Searched for 'InlineIL'. Found: C:\Users\Lucas\.nuget\packages\inlineil.fody\1.0.0\build\..\netclassicweaver\InlineIL.Fody.dll
1>  Fody:   Finished Fody 56ms.
1>Temp -> C:\Dev\Temp\Temp\bin\Debug\netcoreapp2.1\Temp.dll
1>  Fody:   Verifying assembly
1>  Fody:   Finished verification in 50ms.
1>  Fody:   Finished Fody 357ms.
1>Temp -> C:\Dev\Temp\Temp\bin\Debug\net472\Temp.exe
1>  Fody:   Verifying assembly
1>MSBUILD : error : Fody: PEVerify of the assembly failed.
1>MSBUILD : error : [IL]: Error: [C:\Dev\Temp\Temp\bin\Debug\net472\Temp.exe : Temp.Program::GetLength][offset 0x00000003][found ref 'System.Array'] Expected numeric type on the stack.(Error: 0x8013185D)
1>MSBUILD : error : 1 Error(s) Verifying C:\Dev\Temp\Temp\bin\Debug\net472\Temp.exe
1>  Fody:   Finished verification in 41ms.
1>Done building project "Temp.csproj" -- FAILED.

I tested with netstandard2.0, as in your real project, but the verification still fails.

If you don't manage to isolate the issue in a simpler project, could you please post a zip containing the full build output of your project that exposes the issue, and a full build which doesn't have the issue (eg without weaving), preferably in release mode? I'll take a look, maybe I'll be able to spot something.

jp2masa commented 5 years ago

For both Debug and Release:

4>  Fody: Fody (version 3.2.9.0) Executing
4>  Fody: Searched for 'InlineIL'. Found: (...)\.nuget\packages\inlineil.fody\1.0.0\build\..\netclassicweaver\InlineIL.Fody.dll
4>  Fody:   Finished Fody 1388ms.
4>Cosmos.Core_Asm -> (...)\Cosmos\source\Cosmos.Core_Asm\bin\Debug\netstandard2.0\Cosmos.Core_Asm.dll
4>  Fody:   Verifying assembly
4>MSBUILD : error : Fody: PEVerify of the assembly failed.
4>MSBUILD : error : File not found or has bad headers.
4>MSBUILD : error : 1 Error(s) Verifying (...)\Cosmos\source\Cosmos.Core_Asm\bin\Debug\netstandard2.0\Cosmos.Core_Asm.dll
4>  Fody:   Finished verification in 89ms.
4>Done building project "Cosmos.Core_Asm.csproj" -- FAILED.
jp2masa commented 5 years ago

Here are the logs: Logs.zip.

ltrzesniewski commented 5 years ago

Ok, so this PEVerify error is really strange:

File not found or has bad headers.

Looks like PEVerify simply refuses to open the dll, just like the CLR does with its BadImageFormatException.

But, sorry, I wasn't clear enough when I said "build output". I need to take a look at the binaries (all of the content in Cosmos.Core_Asm\bin\Release\netstandard2.0) rather than the logs. The logs aren't saying much.

Please also turn off verification by removing VerifyAssembly="True". It only gets in the way when you know you have unverifiable code.

jp2masa commented 5 years ago

Here are the binaries: Cosmos.Core_Asm.zip.

I only enabled verification because I was curious to see the output for unverifiable code, but then I got this weird error...

ltrzesniewski commented 5 years ago

Ok, so here's a first quick analysis.

Here's a dnSpy dump of both files' headers, if you want to diff them:

Not weaved
// PE
// All tree nodes below use the hex editor to modify the PE file
// 
// 00000000 - 0000003F DOS Header
// 
// IMAGE_DOS_HEADER:
// 00000000 - 00000001 5A4D = e_magic
// 00000002 - 00000003 0090 = e_cblp
// 00000004 - 00000005 0003 = e_cp
// 00000006 - 00000007 0000 = e_crlc
// 00000008 - 00000009 0004 = e_cparhdr
// 0000000A - 0000000B 0000 = e_minalloc
// 0000000C - 0000000D FFFF = e_maxalloc
// 0000000E - 0000000F 0000 = e_ss
// 00000010 - 00000011 00B8 = e_sp
// 00000012 - 00000013 0000 = e_csum
// 00000014 - 00000015 0000 = e_ip
// 00000016 - 00000017 0000 = e_cs
// 00000018 - 00000019 0040 = e_lfarlc
// 0000001A - 0000001B 0000 = e_ovno
// 0000001C - 0000001D 0000 = e_res[0]
// 0000001E - 0000001F 0000 = e_res[1]
// 00000020 - 00000021 0000 = e_res[2]
// 00000022 - 00000023 0000 = e_res[3]
// 00000024 - 00000025 0000 = e_oemid
// 00000026 - 00000027 0000 = e_oeminfo
// 00000028 - 00000029 0000 = e_res2[0]
// 0000002A - 0000002B 0000 = e_res2[1]
// 0000002C - 0000002D 0000 = e_res2[2]
// 0000002E - 0000002F 0000 = e_res2[3]
// 00000030 - 00000031 0000 = e_res2[4]
// 00000032 - 00000033 0000 = e_res2[5]
// 00000034 - 00000035 0000 = e_res2[6]
// 00000036 - 00000037 0000 = e_res2[7]
// 00000038 - 00000039 0000 = e_res2[8]
// 0000003A - 0000003B 0000 = e_res2[9]
// 0000003C - 0000003F 00000080 = e_lfanew
// 
// 00000084 - 00000097 File Header
// 
// IMAGE_FILE_HEADER:
// 00000084 - 00000085 014C = Machine
// 00000086 - 00000087 0003 = NumberOfSections
// 00000088 - 0000008B 806A3147 = TimeDateStamp
// 0000008C - 0000008F 00000000 = PointerToSymbolTable
// 00000090 - 00000093 00000000 = NumberOfSymbols
// 00000094 - 00000095 00E0 = SizeOfOptionalHeader
// 00000096 - 00000097 2022 = Characteristics
// 
// 00000098 - 00000177 Optional Header (32-bit)
// 
// IMAGE_OPTIONAL_HEADER32:
// 00000098 - 00000099 010B = Magic
// 0000009A - 0000009A 30 = MajorLinkerVersion
// 0000009B - 0000009B 00 = MinorLinkerVersion
// 0000009C - 0000009F 00006600 = SizeOfCode
// 000000A0 - 000000A3 00000600 = SizeOfInitializedData
// 000000A4 - 000000A7 00000000 = SizeOfUninitializedData
// 000000A8 - 000000AB 00008586 = AddressOfEntryPoint
// 000000AC - 000000AF 00002000 = BaseOfCode
// 000000B0 - 000000B3 0000A000 = BaseOfData
// 000000B4 - 000000B7 10000000 = ImageBase
// 000000B8 - 000000BB 00002000 = SectionAlignment
// 000000BC - 000000BF 00000200 = FileAlignment
// 000000C0 - 000000C1 0004 = MajorOperatingSystemVersion
// 000000C2 - 000000C3 0000 = MinorOperatingSystemVersion
// 000000C4 - 000000C5 0000 = MajorImageVersion
// 000000C6 - 000000C7 0000 = MinorImageVersion
// 000000C8 - 000000C9 0004 = MajorSubsystemVersion
// 000000CA - 000000CB 0000 = MinorSubsystemVersion
// 000000CC - 000000CF 00000000 = Win32VersionValue
// 000000D0 - 000000D3 0000E000 = SizeOfImage
// 000000D4 - 000000D7 00000200 = SizeOfHeaders
// 000000D8 - 000000DB 00015FEF = CheckSum
// 000000DC - 000000DD 0003 = Subsystem
// 000000DE - 000000DF 8540 = DllCharacteristics
// 000000E0 - 000000E3 00100000 = SizeOfStackReserve
// 000000E4 - 000000E7 00001000 = SizeOfStackCommit
// 000000E8 - 000000EB 00100000 = SizeOfHeapReserve
// 000000EC - 000000EF 00001000 = SizeOfHeapCommit
// 000000F0 - 000000F3 00000000 = LoaderFlags
// 000000F4 - 000000F7 00000010 = NumberOfRvaAndSizes
// 000000F8 - 000000FB 00000000 = Export.VirtualAddress
// 000000FC - 000000FF 00000000 = Export.Size
// 00000100 - 00000103 00008531 = Import.VirtualAddress
// 00000104 - 00000107 0000004F = Import.Size
// 00000108 - 0000010B 0000A000 = Resource.VirtualAddress
// 0000010C - 0000010F 00000390 = Resource.Size
// 00000110 - 00000113 00000000 = Exception.VirtualAddress
// 00000114 - 00000117 00000000 = Exception.Size
// 00000118 - 0000011B 00000000 = Security.VirtualAddress
// 0000011C - 0000011F 00000000 = Security.Size
// 00000120 - 00000123 0000C000 = Base Reloc.VirtualAddress
// 00000124 - 00000127 0000000C = Base Reloc.Size
// 00000128 - 0000012B 00008428 = Debug.VirtualAddress
// 0000012C - 0000012F 00000054 = Debug.Size
// 00000130 - 00000133 00000000 = Architecture.VirtualAddress
// 00000134 - 00000137 00000000 = Architecture.Size
// 00000138 - 0000013B 00000000 = Global Ptr.VirtualAddress
// 0000013C - 0000013F 00000000 = Global Ptr.Size
// 00000140 - 00000143 00000000 = TLS.VirtualAddress
// 00000144 - 00000147 00000000 = TLS.Size
// 00000148 - 0000014B 00000000 = Load Config.VirtualAddress
// 0000014C - 0000014F 00000000 = Load Config.Size
// 00000150 - 00000153 00000000 = Bound Import.VirtualAddress
// 00000154 - 00000157 00000000 = Bound Import.Size
// 00000158 - 0000015B 00002000 = IAT.VirtualAddress
// 0000015C - 0000015F 00000008 = IAT.Size
// 00000160 - 00000163 00000000 = Delay Import.VirtualAddress
// 00000164 - 00000167 00000000 = Delay Import.Size
// 00000168 - 0000016B 00002008 = .NET.VirtualAddress
// 0000016C - 0000016F 00000048 = .NET.Size
// 00000170 - 00000173 00000000 = Reserved15.VirtualAddress
// 00000174 - 00000177 00000000 = Reserved15.Size
// 
// 00000178 - 0000019F Section #0: .text
// 
// IMAGE_SECTION_HEADER:
// 00000178 - 0000017F .text = Name
// 00000180 - 00000183 000065A4 = VirtualSize
// 00000184 - 00000187 00002000 = VirtualAddress
// 00000188 - 0000018B 00006600 = SizeOfRawData
// 0000018C - 0000018F 00000200 = PointerToRawData
// 00000190 - 00000193 00000000 = PointerToRelocations
// 00000194 - 00000197 00000000 = PointerToLinenumbers
// 00000198 - 00000199 0000 = NumberOfRelocations
// 0000019A - 0000019B 0000 = NumberOfLinenumbers
// 0000019C - 0000019F 60000020 = Characteristics
// 
// 000001A0 - 000001C7 Section #1: .rsrc
// 
// IMAGE_SECTION_HEADER:
// 000001A0 - 000001A7 .rsrc = Name
// 000001A8 - 000001AB 00000390 = VirtualSize
// 000001AC - 000001AF 0000A000 = VirtualAddress
// 000001B0 - 000001B3 00000400 = SizeOfRawData
// 000001B4 - 000001B7 00006800 = PointerToRawData
// 000001B8 - 000001BB 00000000 = PointerToRelocations
// 000001BC - 000001BF 00000000 = PointerToLinenumbers
// 000001C0 - 000001C1 0000 = NumberOfRelocations
// 000001C2 - 000001C3 0000 = NumberOfLinenumbers
// 000001C4 - 000001C7 40000040 = Characteristics
// 
// 000001C8 - 000001EF Section #2: .reloc
// 
// IMAGE_SECTION_HEADER:
// 000001C8 - 000001CF .reloc = Name
// 000001D0 - 000001D3 0000000C = VirtualSize
// 000001D4 - 000001D7 0000C000 = VirtualAddress
// 000001D8 - 000001DB 00000200 = SizeOfRawData
// 000001DC - 000001DF 00006C00 = PointerToRawData
// 000001E0 - 000001E3 00000000 = PointerToRelocations
// 000001E4 - 000001E7 00000000 = PointerToLinenumbers
// 000001E8 - 000001E9 0000 = NumberOfRelocations
// 000001EA - 000001EB 0000 = NumberOfLinenumbers
// 000001EC - 000001EF 42000040 = Characteristics
// 
// 00000208 - 0000024F Cor20 Header
// 
// IMAGE_COR20_HEADER:
// 00000208 - 0000020B 00000048 = cb
// 0000020C - 0000020D 0002 = MajorRuntimeVersion
// 0000020E - 0000020F 0005 = MinorRuntimeVersion
// 00000210 - 00000213 000049FC = MetaData.VirtualAddress
// 00000214 - 00000217 000039AC = MetaData.Size
// 00000218 - 0000021B 00000009 = Flags
// 0000021C - 0000021F 00000000 = EntryPointTokenOrRVA
// 00000220 - 00000223 00000000 = Resources.VirtualAddress
// 00000224 - 00000227 00000000 = Resources.Size
// 00000228 - 0000022B 000083A8 = StrongNameSignature.VirtualAddress
// 0000022C - 0000022F 00000080 = StrongNameSignature.Size
// 00000230 - 00000233 00000000 = CodeManagerTable.VirtualAddress
// 00000234 - 00000237 00000000 = CodeManagerTable.Size
// 00000238 - 0000023B 00000000 = VTableFixups.VirtualAddress
// 0000023C - 0000023F 00000000 = VTableFixups.Size
// 00000240 - 00000243 00000000 = ExportAddressTableJumps.VirtualAddress
// 00000244 - 00000247 00000000 = ExportAddressTableJumps.Size
// 00000248 - 0000024B 00000000 = ManagedNativeHeader.VirtualAddress
// 0000024C - 0000024F 00000000 = ManagedNativeHeader.Size
// 
// 00002BFC - 00002C17 Storage Signature
// 
// STORAGESIGNATURE:
// 00002BFC - 00002BFF 424A5342 = lSignature
// 00002C00 - 00002C01 0001 = iMajorVer
// 00002C02 - 00002C03 0001 = iMinorVer
// 00002C04 - 00002C07 00000000 = iExtraData
// 00002C08 - 00002C0B 0000000C = iVersionString
// 00002C0C - 00002C17 v4.0.30319 = VersionString
// 
// 00002C18 - 00002C1B Storage Header
// 
// STORAGEHEADER:
// 00002C18 - 00002C18 00 = fFlags
// 00002C19 - 00002C19 00 = pad
// 00002C1A - 00002C1B 0005 = iStreams
// 
// 00002C1C - 00002C27 Storage Stream #0: #~
// 
// STORAGESTREAM:
// 00002C1C - 00002C1F 0000006C = iOffset
// 00002C20 - 00002C23 00001208 = iSize
// 00002C24 - 00002C27 #~ = rcName
// 
// 00002C28 - 00002C3B Storage Stream #1: #Strings
// 
// STORAGESTREAM:
// 00002C28 - 00002C2B 00001274 = iOffset
// 00002C2C - 00002C2F 00000F18 = iSize
// 00002C30 - 00002C3B #Strings = rcName
// 
// 00002C3C - 00002C47 Storage Stream #2: #US
// 
// STORAGESTREAM:
// 00002C3C - 00002C3F 0000218C = iOffset
// 00002C40 - 00002C43 00000998 = iSize
// 00002C44 - 00002C47 #US = rcName
// 
// 00002C48 - 00002C57 Storage Stream #3: #GUID
// 
// STORAGESTREAM:
// 00002C48 - 00002C4B 00002B24 = iOffset
// 00002C4C - 00002C4F 00000010 = iSize
// 00002C50 - 00002C57 #GUID = rcName
// 
// 00002C58 - 00002C67 Storage Stream #4: #Blob
// 
// STORAGESTREAM:
// 00002C58 - 00002C5B 00002B34 = iOffset
// 00002C5C - 00002C5F 00000E78 = iSize
// 00002C60 - 00002C67 #Blob = rcName
Weaved
// PE
// All tree nodes below use the hex editor to modify the PE file
// 
// 00000000 - 0000003F DOS Header
// 
// IMAGE_DOS_HEADER:
// 00000000 - 00000001 5A4D = e_magic
// 00000002 - 00000003 0090 = e_cblp
// 00000004 - 00000005 0003 = e_cp
// 00000006 - 00000007 0000 = e_crlc
// 00000008 - 00000009 0004 = e_cparhdr
// 0000000A - 0000000B 0000 = e_minalloc
// 0000000C - 0000000D FFFF = e_maxalloc
// 0000000E - 0000000F 0000 = e_ss
// 00000010 - 00000011 00B8 = e_sp
// 00000012 - 00000013 0000 = e_csum
// 00000014 - 00000015 0000 = e_ip
// 00000016 - 00000017 0000 = e_cs
// 00000018 - 00000019 0040 = e_lfarlc
// 0000001A - 0000001B 0000 = e_ovno
// 0000001C - 0000001D 0000 = e_res[0]
// 0000001E - 0000001F 0000 = e_res[1]
// 00000020 - 00000021 0000 = e_res[2]
// 00000022 - 00000023 0000 = e_res[3]
// 00000024 - 00000025 0000 = e_oemid
// 00000026 - 00000027 0000 = e_oeminfo
// 00000028 - 00000029 0000 = e_res2[0]
// 0000002A - 0000002B 0000 = e_res2[1]
// 0000002C - 0000002D 0000 = e_res2[2]
// 0000002E - 0000002F 0000 = e_res2[3]
// 00000030 - 00000031 0000 = e_res2[4]
// 00000032 - 00000033 0000 = e_res2[5]
// 00000034 - 00000035 0000 = e_res2[6]
// 00000036 - 00000037 0000 = e_res2[7]
// 00000038 - 00000039 0000 = e_res2[8]
// 0000003A - 0000003B 0000 = e_res2[9]
// 0000003C - 0000003F 00000080 = e_lfanew
// 
// 00000084 - 00000097 File Header
// 
// IMAGE_FILE_HEADER:
// 00000084 - 00000085 014C = Machine
// 00000086 - 00000087 0003 = NumberOfSections
// 00000088 - 0000008B 806A3147 = TimeDateStamp
// 0000008C - 0000008F 00000000 = PointerToSymbolTable
// 00000090 - 00000093 00000000 = NumberOfSymbols
// 00000094 - 00000095 00E0 = SizeOfOptionalHeader
// 00000096 - 00000097 2102 = Characteristics
// 
// 00000098 - 00000177 Optional Header (32-bit)
// 
// IMAGE_OPTIONAL_HEADER32:
// 00000098 - 00000099 010B = Magic
// 0000009A - 0000009A 30 = MajorLinkerVersion
// 0000009B - 0000009B 00 = MinorLinkerVersion
// 0000009C - 0000009F 00006200 = SizeOfCode
// 000000A0 - 000000A3 00000600 = SizeOfInitializedData
// 000000A4 - 000000A7 00000000 = SizeOfUninitializedData
// 000000A8 - 000000AB 000081BE = AddressOfEntryPoint
// 000000AC - 000000AF 00002000 = BaseOfCode
// 000000B0 - 000000B3 00000000 = BaseOfData
// 000000B4 - 000000B7 00400000 = ImageBase
// 000000B8 - 000000BB 00002000 = SectionAlignment
// 000000BC - 000000BF 00000200 = FileAlignment
// 000000C0 - 000000C1 0004 = MajorOperatingSystemVersion
// 000000C2 - 000000C3 0000 = MinorOperatingSystemVersion
// 000000C4 - 000000C5 0000 = MajorImageVersion
// 000000C6 - 000000C7 0000 = MinorImageVersion
// 000000C8 - 000000C9 0004 = MajorSubsystemVersion
// 000000CA - 000000CB 0000 = MinorSubsystemVersion
// 000000CC - 000000CF 00000000 = Win32VersionValue
// 000000D0 - 000000D3 0000E000 = SizeOfImage
// 000000D4 - 000000D7 00000200 = SizeOfHeaders
// 000000D8 - 000000DB 00000000 = CheckSum
// 000000DC - 000000DD 0003 = Subsystem
// 000000DE - 000000DF 8540 = DllCharacteristics
// 000000E0 - 000000E3 00100000 = SizeOfStackReserve
// 000000E4 - 000000E7 00001000 = SizeOfStackCommit
// 000000E8 - 000000EB 00100000 = SizeOfHeapReserve
// 000000EC - 000000EF 00001000 = SizeOfHeapCommit
// 000000F0 - 000000F3 00000000 = LoaderFlags
// 000000F4 - 000000F7 00000010 = NumberOfRvaAndSizes
// 000000F8 - 000000FB 00000000 = Export.VirtualAddress
// 000000FC - 000000FF 00000000 = Export.Size
// 00000100 - 00000103 0000816C = Import.VirtualAddress
// 00000104 - 00000107 0000004F = Import.Size
// 00000108 - 0000010B 0000A000 = Resource.VirtualAddress
// 0000010C - 0000010F 00000390 = Resource.Size
// 00000110 - 00000113 00000000 = Exception.VirtualAddress
// 00000114 - 00000117 00000000 = Exception.Size
// 00000118 - 0000011B 00000000 = Security.VirtualAddress
// 0000011C - 0000011F 00000000 = Security.Size
// 00000120 - 00000123 0000C000 = Base Reloc.VirtualAddress
// 00000124 - 00000127 0000000C = Base Reloc.Size
// 00000128 - 0000012B 00008108 = Debug.VirtualAddress
// 0000012C - 0000012F 00000038 = Debug.Size
// 00000130 - 00000133 00000000 = Architecture.VirtualAddress
// 00000134 - 00000137 00000000 = Architecture.Size
// 00000138 - 0000013B 00000000 = Global Ptr.VirtualAddress
// 0000013C - 0000013F 00000000 = Global Ptr.Size
// 00000140 - 00000143 00000000 = TLS.VirtualAddress
// 00000144 - 00000147 00000000 = TLS.Size
// 00000148 - 0000014B 00000000 = Load Config.VirtualAddress
// 0000014C - 0000014F 00000000 = Load Config.Size
// 00000150 - 00000153 00000000 = Bound Import.VirtualAddress
// 00000154 - 00000157 00000000 = Bound Import.Size
// 00000158 - 0000015B 00002000 = IAT.VirtualAddress
// 0000015C - 0000015F 00000008 = IAT.Size
// 00000160 - 00000163 00000000 = Delay Import.VirtualAddress
// 00000164 - 00000167 00000000 = Delay Import.Size
// 00000168 - 0000016B 00002008 = .NET.VirtualAddress
// 0000016C - 0000016F 00000048 = .NET.Size
// 00000170 - 00000173 00000000 = Reserved15.VirtualAddress
// 00000174 - 00000177 00000000 = Reserved15.Size
// 
// 00000178 - 0000019F Section #0: .text
// 
// IMAGE_SECTION_HEADER:
// 00000178 - 0000017F .text = Name
// 00000180 - 00000183 000061C4 = VirtualSize
// 00000184 - 00000187 00002000 = VirtualAddress
// 00000188 - 0000018B 00006200 = SizeOfRawData
// 0000018C - 0000018F 00000200 = PointerToRawData
// 00000190 - 00000193 00000000 = PointerToRelocations
// 00000194 - 00000197 00000000 = PointerToLinenumbers
// 00000198 - 00000199 0000 = NumberOfRelocations
// 0000019A - 0000019B 0000 = NumberOfLinenumbers
// 0000019C - 0000019F 60000020 = Characteristics
// 
// 000001A0 - 000001C7 Section #1: .rsrc
// 
// IMAGE_SECTION_HEADER:
// 000001A0 - 000001A7 .rsrc = Name
// 000001A8 - 000001AB 00000390 = VirtualSize
// 000001AC - 000001AF 0000A000 = VirtualAddress
// 000001B0 - 000001B3 00000400 = SizeOfRawData
// 000001B4 - 000001B7 00006400 = PointerToRawData
// 000001B8 - 000001BB 00000000 = PointerToRelocations
// 000001BC - 000001BF 00000000 = PointerToLinenumbers
// 000001C0 - 000001C1 0000 = NumberOfRelocations
// 000001C2 - 000001C3 0000 = NumberOfLinenumbers
// 000001C4 - 000001C7 40000040 = Characteristics
// 
// 000001C8 - 000001EF Section #2: .reloc
// 
// IMAGE_SECTION_HEADER:
// 000001C8 - 000001CF .reloc = Name
// 000001D0 - 000001D3 0000000C = VirtualSize
// 000001D4 - 000001D7 0000C000 = VirtualAddress
// 000001D8 - 000001DB 00000200 = SizeOfRawData
// 000001DC - 000001DF 00006800 = PointerToRawData
// 000001E0 - 000001E3 00000000 = PointerToRelocations
// 000001E4 - 000001E7 00000000 = PointerToLinenumbers
// 000001E8 - 000001E9 0000 = NumberOfRelocations
// 000001EA - 000001EB 0000 = NumberOfLinenumbers
// 000001EC - 000001EF 42000040 = Characteristics
// 
// 00000208 - 0000024F Cor20 Header
// 
// IMAGE_COR20_HEADER:
// 00000208 - 0000020B 00000048 = cb
// 0000020C - 0000020D 0002 = MajorRuntimeVersion
// 0000020E - 0000020F 0005 = MinorRuntimeVersion
// 00000210 - 00000213 000048E8 = MetaData.VirtualAddress
// 00000214 - 00000217 00003820 = MetaData.Size
// 00000218 - 0000021B 00000009 = Flags
// 0000021C - 0000021F 00000000 = EntryPointTokenOrRVA
// 00000220 - 00000223 00000000 = Resources.VirtualAddress
// 00000224 - 00000227 00000000 = Resources.Size
// 00000228 - 0000022B 00000000 = StrongNameSignature.VirtualAddress
// 0000022C - 0000022F 00000000 = StrongNameSignature.Size
// 00000230 - 00000233 00000000 = CodeManagerTable.VirtualAddress
// 00000234 - 00000237 00000000 = CodeManagerTable.Size
// 00000238 - 0000023B 00000000 = VTableFixups.VirtualAddress
// 0000023C - 0000023F 00000000 = VTableFixups.Size
// 00000240 - 00000243 00000000 = ExportAddressTableJumps.VirtualAddress
// 00000244 - 00000247 00000000 = ExportAddressTableJumps.Size
// 00000248 - 0000024B 00000000 = ManagedNativeHeader.VirtualAddress
// 0000024C - 0000024F 00000000 = ManagedNativeHeader.Size
// 
// 00002AE8 - 00002B03 Storage Signature
// 
// STORAGESIGNATURE:
// 00002AE8 - 00002AEB 424A5342 = lSignature
// 00002AEC - 00002AED 0001 = iMajorVer
// 00002AEE - 00002AEF 0001 = iMinorVer
// 00002AF0 - 00002AF3 00000000 = iExtraData
// 00002AF4 - 00002AF7 0000000C = iVersionString
// 00002AF8 - 00002B03 v4.0.30319 = VersionString
// 
// 00002B04 - 00002B07 Storage Header
// 
// STORAGEHEADER:
// 00002B04 - 00002B04 00 = fFlags
// 00002B05 - 00002B05 00 = pad
// 00002B06 - 00002B07 0005 = iStreams
// 
// 00002B08 - 00002B13 Storage Stream #0: #~
// 
// STORAGESTREAM:
// 00002B08 - 00002B0B 0000006C = iOffset
// 00002B0C - 00002B0F 000011B8 = iSize
// 00002B10 - 00002B13 #~ = rcName
// 
// 00002B14 - 00002B27 Storage Stream #1: #Strings
// 
// STORAGESTREAM:
// 00002B14 - 00002B17 00001224 = iOffset
// 00002B18 - 00002B1B 00000E94 = iSize
// 00002B1C - 00002B27 #Strings = rcName
// 
// 00002B28 - 00002B33 Storage Stream #2: #US
// 
// STORAGESTREAM:
// 00002B28 - 00002B2B 000020B8 = iOffset
// 00002B2C - 00002B2F 00000998 = iSize
// 00002B30 - 00002B33 #US = rcName
// 
// 00002B34 - 00002B43 Storage Stream #3: #GUID
// 
// STORAGESTREAM:
// 00002B34 - 00002B37 00002A50 = iOffset
// 00002B38 - 00002B3B 00000010 = iSize
// 00002B3C - 00002B43 #GUID = rcName
// 
// 00002B44 - 00002B53 Storage Stream #4: #Blob
// 
// STORAGESTREAM:
// 00002B44 - 00002B47 00002A60 = iOffset
// 00002B48 - 00002B4B 00000DC0 = iSize
// 00002B4C - 00002B53 #Blob = rcName

Major differences: non weaved -> weaved

I thought the first one was the issue, but then I compared that to a known good netstandard2.0 assembly that uses InlineIL, and the values match. Actually, it's Cecil that encodes this header like so.

I'l keep looking at this.

ltrzesniewski commented 5 years ago

Some other stuff: in IMAGE_COR20_HEADER, StrongNameSignature.VirtualAddress and StrongNameSignature.Size are both zero in the weaved assembly. That doesn't look right either, but when I round-trip the dll through dnSpy, PEVerify happily loads it. After round-tripping, these headers are nonzero. So that looks like a decent clue.

I added a strong name to my isolated project, and these fields are nonzero in the build output. Everything works fine there.

This definitely starts to look like a strong naming issue. Maybe Fody can't find the key file for some reason.

Could you please do the following? This could help me pinpoint the issue.

I'll take a look at it tomorrow.

jp2masa commented 5 years ago

I found the problem: SignAssembly is being set to True after Fody "captures" its value on FodySignAssembly, so the assembly was being signed by the compiler, but not by Fody.

Thanks for the help!

ltrzesniewski commented 5 years ago

Yay \o/

Indeed, I can see that Cosmos sets SignAssembly in the "targets" file. Glad you got it figured out.

@SimonCropp why does Fody copy SignAssembly to FodySignAssembly in Fody.targets? The commit that introduces this change only says "perf hacks"...

SimonCropp commented 5 years ago

That was a hack to support a niche edge case I once had. To do with mixing signed and unsigned dlls when using ilmerge. That use case is no longer valid and that property copy could be removed

ltrzesniewski commented 5 years ago

@SimonCropp, ok thanks for the explanation.

When these properties went out of sync, this generated very unusual build results which were not straightforward to figure out as you can see from this issue, so since it's no longer necessary I'll submit a small PR to avoid such cases in the future.

ltrzesniewski commented 5 years ago

@jp2masa FYI this should be fixed in Fody v3.2.10