在 2025-02-13 18:17, Jacek Caban 写道:
This isn't entirely true for other linkers. While those linkers do place .idata sections, including the IAT itself, in .rdata, they don’t use .idata sections for delay imports. Instead, they implement delay loading within the linker itself rather than relying on special delay import libraries, placing the delay IAT in the .data section.

I’ve seen a blog claim that MSVC makes them read-only, but in my testing with modern MSVC, that doesn’t appear to be the case, perhaps they realized it wasn’t a good fit and reverted the change? I’m not sure.

MSVC does make IAT read-only, as in this example: 
https://gcc.godbolt.org/z/Msfqhs7x3

Also my patch for binutils took LLD as a reference, as well as MSVC.


I say it’s not a good fit because changing permissions like that is generally a bad idea. Another thread might be executing code that relies on data in the same page remaining read-only or might be performing similar permission changes for other reasons. Taking a lock only protects against concurrent __delayLoadHelper2 calls.

It's actually a known issue, also referenced in the article in The Old New Thing, quoted in the commit message.

It also explains why a static lock is necessary here: The unprotect operation and write operation must happen atomically, so another thread will not make the IAT read-only in between.

If you have Visual Studio installed, you can also see that Microsoft code does similar stuff in 'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.43.34808\include\delayhlp.cpp'; however their code checks for image load config, which binutils does not support at the moment.


Wine provides its own __delayLoadHelper2 implementation, which simply forwards the call to the public ResolveDelayLoadedAPI function. I’m attaching a hack that does the same for mingw-w64 (since it’s a Windows 8 API, it’s not something mingw-w64 could use by default). ResolveDelayLoadedAPI doesn’t seem to perform the protection change. at least in this case, though maybe there’s a way to trigger it? Either way, the test case crashes. The only workaround would be modifying Wine’s __delayLoadHelper2 to duplicate ResolveDelayLoadedAPI inside a static library and add the necessary permission changes.

A writeable IAT is a conspicuous target for code injection.

If MSVC makes it read-only, LLD makes it read-only, and there have been few issues with MSVC in practice (see the Old New Thing article), then there's no reason for us to not do that; do you agree?

And MSYS2 have also updated their binutils since about a week ago, and there do not seem to be issues, either.


That’s unfortunate. If anyone has a better idea, please let me know. Ideally, I’d like to restore the previous behavior for delay load imports. Wine doesn’t use dlltool to create delay load import libraries; it generates them itself. In theory, this gives Wine more flexibility, but I haven’t found a way to make it work.


  SetEntryHookBypass:
+  while(InterlockedExchange(&gDelayLoadLock, 1) != 0)
+    Sleep(100);


You could just use a critical section.

The reason is that a critical section can't be initialized statically. This lock is only taken once for each symbol, so I suspect we'd better not introduce extra complexity.


--
Best regards,
LIU Hao

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature

_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to