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