<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>