Skip to content

Fix ZEND_EXT_API wrt accessibility of OPcache symbols on Windows #15592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

cmb69
Copy link
Member

@cmb69 cmb69 commented Aug 26, 2024

When building a DLL which exports symbols these need to be explicitly exported like on other platforms. When building a DLL which accesses these symbols, they should be imported for performance reasons if the symbols are referring to functions, and have to be imported if the symbols are referring to data.[1]

So we do the common dllexport/dllimport "dance" depending on a macro which is only set when building OPcache.

[1] https://learn.microsoft.com/en-us/cpp/build/importing-into-an-application-using-declspec-dllimport?view=msvc-170


This should solve @dstogov's concerns from PR #15543, and makes it possible to statically link to smm_shared_globals in the import library of php_opcache.dll.

cc @bwoebi, @realFlowControl, maybe you want to test this.

One problem remains, though, namely that apparently none of the OPcache headers are exported (aka. installed), so phpize builds can't use these (easily). Is there any particular reason for that?

Also note that almost all extensions doesn't handle the export/import on Windows properly; even if only function symbols are exported, accessing them without dllimport has a small performance impact. Maybe we should improve that over time.

When building a DLL which exports symbols these need to be explicitly
exported like on other platforms.  When building a DLL which accesses
these symbols, they should be imported for performance reasons if the
symbols are referring to functions, and *have* *to* be imported if the
symbols are referring to data.[1]

So we do the common dllexport/dllimport "dance" depending on a macro
which is only set when building OPcache.

[1] <https://learn.microsoft.com/en-us/cpp/build/importing-into-an-application-using-declspec-dllimport?view=msvc-170>
@dstogov
Copy link
Member

dstogov commented Aug 26, 2024

I didn't understand how this may perform linking between different DLL extensions loaded by dl().
For example how could Wndows load observer that import symbol from opcache.dll, if opcache.dll is not loaded at all.
On Linux this may work because of "lazy" linking.

I may be wrong. @bwoebi does this work for you?

I see this trick is already used in few other extensions, but not in all.
Probably everything should be fixed uniformly.

@cmb69
Copy link
Member Author

cmb69 commented Aug 26, 2024

I didn't understand how this may perform linking between different DLL extensions loaded by dl().

This is not related to dl() at all. It is just for import libraries, which are special to Windows; you can statically link to these, and they'll then load the DLLs on demand (I think https://github.com/yugr/Implib.so works similar to these import libraries). Consider the following quick hack:

 ext/zend_test/config.w32 | 1 +
 ext/zend_test/test.c     | 4 +++-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/ext/zend_test/config.w32 b/ext/zend_test/config.w32
index 65fe6d359b..44858d5f86 100644
--- a/ext/zend_test/config.w32
+++ b/ext/zend_test/config.w32
@@ -5,4 +5,5 @@ ARG_ENABLE("zend-test", "enable zend_test extension", "no");
 if (PHP_ZEND_TEST != "no") {
 	EXTENSION("zend_test", "test.c observer.c fiber.c iterators.c object_handlers.c zend_mm_custom_handlers.c", PHP_ZEND_TEST_SHARED, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
 	ADD_FLAG("CFLAGS_ZEND_TEST", "/D PHP_ZEND_TEST_EXPORTS ");
+	ADD_EXTENSION_DEP("zend_test", "opcache");
 }
diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c
index 11fb978ef1..4b06dbe50b 100644
--- a/ext/zend_test/test.c
+++ b/ext/zend_test/test.c
@@ -36,7 +36,8 @@
 #include "test_arginfo.h"
 #include "zend_call_stack.h"
 #include "zend_exceptions.h"
-#include "zend_mm_custom_handlers.h"
+#include "ext/opcache/ZendAccelerator.h"
+#include "ext/opcache/zend_shared_alloc.h"
 
 // `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from
 // assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we
@@ -91,6 +92,7 @@ static ZEND_FUNCTION(zend_test_func)
 
 static ZEND_FUNCTION(zend_test_array_return)
 {
+	zend_smm_shared_globals *smmsg = smm_shared_globals;
 	ZEND_PARSE_PARAMETERS_NONE();
 }
 

Now php -n -d extension=php_zend_test.dll -r "zend_test_array_return();" will load php_zend_test.dll and php_opcache.dll.

For full dynamic linking, DL_LOAD() and DL_FETCH_SYMBOL() can be used.

@bwoebi
Copy link
Member

bwoebi commented Aug 26, 2024

@dstogov I personally don't have any interest in directly depending on extensions, so it doesn't change anything for me. If it works, great, I guess.

@realFlowControl
Copy link
Contributor

realFlowControl commented Aug 27, 2024

One problem remains, though, namely that apparently none of the OPcache headers are exported (aka. installed), so phpize builds can't use these (easily). Is there any particular reason for that?

Not really, it was just the least invasive way to do it and we can copy the header files. What you mean would mean adding:

PHP_INSTALL_HEADERS([ext/opcache], m4_normalize([
  ZendAccelerator.h
  zend_accelerator_debug.h
  zend_accelerator_hash.h
  zend_shared_alloc.h
]))

to config.m4 (and accordingly to config.w32)? I can quickly setup a PR for this (EDIT: #15596)

This should solve @dstogov's concerns from PR #15543, and makes it possible to statically link to smm_shared_globals in the import library of php_opcache.dll.

We are not directly depending on other extensions. In the case of #15543 we are checking for the dl handle for OPcache and if that exists, we dlsym() a few symbols to gather information from OPcache, otherwise nothing happens. So I am okay with this.

Probably everything should be fixed uniformly.

👍

@dstogov
Copy link
Member

dstogov commented Aug 27, 2024

Now php -n -d extension=php_zend_test.dll -r "zend_test_array_return();" will load php_zend_test.dll and php_opcache.dll.

This means php_opcache.dll must be always installed and may be loaded, even if it's not used through "zend_extension=".
Then, I wouldn't expect anything reasonable from opcache before it's initialized through Zend extension mechanism.

@cmb69
Copy link
Member Author

cmb69 commented Aug 28, 2024

Given that PR #15596 has closed, I see no reason to keep this open, except to have a reminder about improving their API definition; thus I'm converting to draft.

@cmb69 cmb69 marked this pull request as draft August 28, 2024 16:52
@cmb69 cmb69 closed this Sep 21, 2024
@cmb69 cmb69 deleted the cmb/ZEND_EXT_API branch September 21, 2024 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants