-
Notifications
You must be signed in to change notification settings - Fork 5.8k
8305935: Resolve multiple definition of 'jmm_<interface|version>' when statically linking with JDK native libraries #13451
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
Conversation
…n statically linking with JDK native libraries
👋 Welcome back jiangli! A progress list of the required criteria for merging this PR into |
@jianglizhou The following labels will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command. |
Webrevs
|
const JmmInterface* jmm_interface_management_ext = NULL; | ||
static JavaVM* jvm = NULL; | ||
jint jmm_version = 0; | ||
jint jmm_version_management_ext = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there not a way to stop these from being exported from the library, as I assume they are not actually intended for external use. ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there not a way to stop these from being exported from the library, as I assume they are not actually intended for external use. ??
Good question.
We could make those as weak symbols as long as there is no concern about portability. In our current prototype on JDK 11, we use weak symbol to help detect if we are dealing with a statically linked binary at runtime then handle some of the cases conditionally (dynamic vs. static). Around the end of last year, I became aware that there could be issues in some cases on macos with weak symbols (e.g. without '-undefined dynamic_lookup'). I'm planning to look into alternatives (besides using weak symbol) when porting the support to the latest OpenJDK code base.
Another approach is using 'objcopy' (https://web.mit.edu/gnu/doc/html/binutils_4.html) to localize the problematic symbols in the object file. It was suggested by our C++ colleague. We used that to hide symbols in libfreetype and libharfbuzz (there were problems when user code requires its own specific statically linked libfreetype and libharfbuzz due to versioning difference). So we first partially link all .o for the particular native library (in JDK) to form one .o file, then run 'objcopy' to localize the symbols. That hides the affected symbols during final link time. We had to do that since we don't control libfreetype and libharfbuzz. It worked for our specific case (for linux). It's probably not a general solution.
The direct renaming in this case seems to be more strait forward. Any thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to mention that using 'static' effectively resolves the symbol issue when feasible, like the 'jvm' variable case. That doesn't work for the 'jmm_interface' and 'jmm_version' ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar with the details of symbol scoping and linkage with libraries, but I would have hoped there was a way to have symbols like this shareable throughout the code that comprises the library without exposing them to users of the library. It used to be IIRC only functions we listed in the mapfiles were exposed, and these days we use explicit attributes to export them. Is there not some equivalent thing for data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The direct renaming in this case seems to be more strait forward.
If we were to do this then we should have a naming convention of some kind e.g. <lib-name>_<var-name>
but it strikes me as wrong as the code shouldn't need to know what library it is part of. In this case we do something as a simple point-fix, but to me it says there is a bigger problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not familiar with the details of symbol scoping and linkage with libraries, but I would have hoped there was a way to have symbols like this shareable throughout the code that comprises the library without exposing them to users of the library. It used to be IIRC only functions we listed in the mapfiles were exposed, and these days we use explicit attributes to export them. Is there not some equivalent thing for data?
If my understanding is correct the mapfile is for exported symbols, which are in the export table. Those symbols can be dynamically looked up, e.g. via dlsym. By default, '-fvisibility=hidden' is used (https://github.com/openjdk/jdk/blob/master/make/common/modules/LibCommon.gmk#L41). The symbols are '.hidden' by default if not exported. E.g. jmm_interface is 'hidden' as objdump shows below. However, the linker error that we are seeing here for statically linking the libraries together is a different issue. The linker founds multiple ones in different object files, hence the failures. We'd have to change to use internal linkage for the affect variables to resolve the failure if feasible (without renaming). Please let me know if I'm missing anything.
objdump: ./linux-x86_64-server-release/support/native/jdk.management/libmanagement_ext/management_ext.o: not a dynamic object
SYMBOL TABLE:
0000000000000000 l df ABS 0000000000000000 management_ext.c
...
0000000000000000 g F .text 0000000000000068 JNI_OnLoad
0000000000000008 g O .bss 0000000000000008 .hidden jvm
0000000000000000 UND 0000000000000000 JVM_GetManagement
0000000000000010 g O .bss 0000000000000008 .hidden jmm_interface
0000000000000000 g O .bss 0000000000000004 .hidden jmm_version
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we were to do this then we should have a naming convention of some kind e.g.
<lib-name>_<var-name>
but it strikes me as wrong as the code shouldn't need to know what library it is part of. In this case we do something as a simple point-fix, but to me it says there is a bigger problem.
Using a naming convention as you suggested sounds good. I'm not completely clear what's the bigger problem though. Could you please clarify?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
David, I was doing some more reading on the topic for our discussion in the thread and just found this: https://stackoverflow.com/questions/61663118/avoid-multiple-definition-linker-error-when-not-using-the-redefined-symbols.
It has some good information on the symbol collision issue. It describes using 'objcopy' to localize or redefine symbols. It also mentions '--allow-multiple-definitions', which I didn't know before. However, '--allow-multiple-definitions' doesn't seem to be a good approach.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the pointer to stackoverflow - that made things a lot clearer.
The symbol localization using objcopy
seems to achieve what we desire but has the same drawback as renaming, that you need to know the symbols will clash to localize them. And it is also not ideal that changing the code may also need a change to the build file. :(
With that in mind a simple renaming seems the least worst option for fixing this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -31,9 +31,9 @@ | |||
|
|||
#define ERR_MSG_SIZE 128 | |||
|
|||
const JmmInterface* jmm_interface = NULL; | |||
const JmmInterface* jmm_interface_management_ext = NULL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment before declaring the two "exported" symbols together:
// These symbols are global in this library but need to be uniquely named to avoid conflicts
// with same-named symbols in other libraries, when statically linking.
Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops! Sorry meant to add this comment to the declarations in the hpp file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comment as suggested (with minor adjustment) in management_ext.h. Thanks.
@jianglizhou This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 25 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Thanks for the review and discussion. |
/integrate |
Going to push as commit 314bad3.
Your commit was automatically rebased without conflicts. |
@jianglizhou Pushed as commit 314bad3. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Rename 'jmm_<interface|version>' to 'jmm_<interface|version>_management_ext' in libmanagement_ext to resolve related linker errors when statically linking with both libmanagement and libmanagement_ext.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/13451/head:pull/13451
$ git checkout pull/13451
Update a local copy of the PR:
$ git checkout pull/13451
$ git pull https://git.openjdk.org/jdk.git pull/13451/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 13451
View PR using the GUI difftool:
$ git pr show -t 13451
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/13451.diff
Webrev
Link to Webrev Comment