<div dir="ltr">Solved! Just for the records: everything is done right here, and the BinUtils dlltool as of today is interoperable with Visual Studio 2019. The only missing bit was that in the absence of MSVC-orchestrated delayed-load, linker.exe defaults to read-only ".idata", which has to be altered by e.g.<div><br></div><div>set_target_properties(${PROJECT_NAME}_test_executable PROPERTIES LINK_FLAGS "/SECTION:.idata,RW")<br></div><div><br></div><div>Note also the delayimp code for DloadObtainSection() must also be changed slightly, as we don't have (and don't really need) the IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:</div><div><br></div><div>_Success_(return != nullptr)<br>DLOAD_INLINE<br>PVOID<br>DloadObtainSection (<br> _Out_ PULONG SectionSize,<br> _Out_ PULONG SectionCharacteristics<br> )<br>{<br><br> PIMAGE_DATA_DIRECTORY DataDir;<br> ULONG Entries;<br> PUCHAR ImageBase;<br> ULONG Index;<br> PIMAGE_NT_HEADERS NtHeaders;<br> PIMAGE_SECTION_HEADER SectionHeader;<br><br> ImageBase = (PUCHAR)&__ImageBase;<br> NtHeaders = (PIMAGE_NT_HEADERS)(ImageBase + __ImageBase.e_lfanew);<br><br> SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);<br> for (Index = 0;<br> Index < NtHeaders->FileHeader.NumberOfSections;<br> Index += 1, SectionHeader += 1) {<br><br> if (!__memcmp(SectionHeader->Name, ".idata", __strlen(".idata"))) {<br> *SectionSize = SectionHeader->Misc.VirtualSize;<br> *SectionCharacteristics = SectionHeader->Characteristics;<br> return ImageBase + SectionHeader->VirtualAddress;<br> }<br> }<br><br> return NULL;<br>}<br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">пн, 24 авг. 2020 г. в 12:34, Dmitry Mikushin <<a href="mailto:dmitry@kernelgen.org">dmitry@kernelgen.org</a>>:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Dear All,</div><div><br></div>I've been studying the delayed-load (delayimp) pipeline as a possible backend for the missing RPATH functionality on Windows, by the following example:<br><br>#include <stdio.h><br><br>int __declspec(dllimport) foo(int arg);<br><br>int main(int argc, char* argv[])<br>{<br> printf("foo() = %d\n", foo(foo(argc)));<br> return 0;<br><div>}</div><div><br></div><div>Both GNU and LLVM implement delayed loading similarly with the dlltool (yet, LLVM's dlltool seems to have merged into ld-link). Essentially, the task performed in LLVM's lld/COFF/DLL.cpp or BinUtil's dlltool.c is two-fold:<br></div><div><br></div><div>1) Generate jump table stub for a delayed-load function (see example below)</div><div>2) Generate a trampoline that shall deploy the __delayLoadHelper2 code (see example below)</div><div><br></div><div>Upon the successful binding, the __delayLoadHelper2 seems to write a resolved function address right into the executable code section:</div><div><br></div><div>extern "C"<br>FARPROC WINAPI<br>__delayLoadHelper2(<br> PCImgDelayDescr pidd,<br> FARPROC * ppfnIATEntry<br> ) {<br></div><div><br></div><div>SetEntryHookBypass:<br> *ppfnIATEntry = pfnRet; // access violation<br></div><div><br></div><div>}</div><div><br></div><div>In order for executable image modification, Microsoft has developed some fancy functions that temporarily add write permissions to the corresponding memory region.</div><div><br></div><div>Now the question is: the code to be modified is within the jump table stub that goes into ".idata" section, and it fails to get write permissions:</div><div><br></div><div> if ((Characteristics & IMAGE_SCN_MEM_WRITE) == 0) {<br><br> //<br> // This delay load helper module does not support merging the delay<br> // load section to a read only section because memory management<br> // would not guarantee that there is commit available - and thus a<br> // low memory failure path where the delay load failure hook could<br> // not be safely invoked (the delay load section would still be<br> // read only) might be encountered.<br> //<br> // It is a build time configuration problem to produce such a<br> // binary so abort here and now so that the problem can be<br> // identified & fixed.<br> //<br><br>/* Exception thrown at 0x000000013F3B3F3F in dlltool_test_executable.exe: 0xC0000005: Access violation reading */<br> __fastfail(FAST_FAIL_DLOAD_PROTECTION_FAILURE);<br> }</div><div><br></div><div>So, currently the hard-binding does not work, and gives "write access violation". I'm wondering what kind of "build-time configuration" am I missing here?</div><div><br></div><div>My test config: LLVM upstream from github, BinUtils upstream from git, MSVC2019, Windows 7.</div><div><br></div><div>I'm posting this also to StackOverflow: <a href="https://stackoverflow.com/questions/63559263/" target="_blank">https://stackoverflow.com/questions/63559263/</a></div><div><br></div><div>Kind regards,</div><div>- Dmitry.</div><div><br></div><div>$ cat trampoline.s<br># Import trampoline<br> .section .text<br> .global __tailMerge_C__Users_marcusmae_dlltool_build_import_test_lib<br>__tailMerge_C__Users_marcusmae_dlltool_build_import_test_lib:<br> pushq %rcx<br> pushq %rdx<br> pushq %r8<br> pushq %r9<br> subq $40, %rsp<br> movq %rax, %rdx<br> leaq __DELAY_IMPORT_DESCRIPTOR_C__Users_marcusmae_dlltool_build_import_test_lib(%rip), %rcx<br> call __delayLoadHelper2<br> addq $40, %rsp<br> popq %r9<br> popq %r8<br> popq %rdx<br> popq %rcx<br> jmp *%rax<br><br># DELAY_IMPORT_DESCRIPTOR<br>.section .text$2<br>.global __DELAY_IMPORT_DESCRIPTOR_C__Users_marcusmae_dlltool_build_import_test_lib<br>__DELAY_IMPORT_DESCRIPTOR_C__Users_marcusmae_dlltool_build_import_test_lib:<br> .long 1 # grAttrs<br> .rva __C__Users_marcusmae_dlltool_build_import_test_lib_iname # rvaDLLName<br> .rva __DLL_HANDLE_C__Users_marcusmae_dlltool_build_import_test_lib # rvaHmod<br> .rva __IAT_C__Users_marcusmae_dlltool_build_import_test_lib # rvaIAT<br> .rva __INT_C__Users_marcusmae_dlltool_build_import_test_lib # rvaINT<br> .long 0 # rvaBoundIAT<br> .long 0 # rvaUnloadIAT<br> .long 0 # dwTimeStamp<br><br>.section .data<br>__DLL_HANDLE_C__Users_marcusmae_dlltool_build_import_test_lib:<br> .long 0 # Handle<br> .long 0<br><br>#Stuff for compatibility<br> .section .idata$5<br> .long 0<br> .long 0<br>__IAT_C__Users_marcusmae_dlltool_build_import_test_lib:<br> .section .idata$4<br> .long 0<br> .long 0<br> .section .idata$4<br>__INT_C__Users_marcusmae_dlltool_build_import_test_lib:<br> .section .idata$2<br></div><div><br></div><div>$ objdump -d dorks00000.o<br><br>dorks00000.o: file format pe-x86-64<br><br><br>Disassembly of section .text:<br><br>0000000000000000 <foo>:<br> 0: ff 25 00 00 00 00 jmpq *0x0(%rip) # 6 <foo+0x6><br> 6: 48 8d 05 00 00 00 00 lea 0x0(%rip),%rax # d <foo+0xd><br> d: e9 00 00 00 00 jmpq 12 <foo+0x12><br> ...<br><br></div></div>
</blockquote></div>