ndk icon indicating copy to clipboard operation
ndk copied to clipboard

[BUG] Can't auto hide STL Libc++ symbols since r22

Open metarutaiga opened this issue 3 years ago • 10 comments

Description

I started to use r22, and found it generated bigger binary than r21. And I found it show many std::string symbol in the binary.

So I need to add below code to hide it

#if (_LIBCPP_VERSION >= 11000)
#include <string>
#include <vector>
_LIBCPP_BEGIN_NAMESPACE_STD
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
    _LIBCPP_STRING_V1_EXTERN_TEMPLATE_LIST(_LIBCPP_EXTERN_TEMPLATE_DEFINE, char)
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD
#endif

and add options in CMakeLists.txt

add_compile_options( -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS )

Environment Details

  • NDK Version: r22
  • Build system: Android Studio 4.1
  • Host OS: Windows
  • ABI: Any
  • NDK API level: Any
  • Device API level: Any

metarutaiga avatar Dec 24 '20 08:12 metarutaiga

add_compile_options( -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS )

https://libcxx.llvm.org/docs/UsingLibcxx.html#libc-configuration-macros

This macro is used to disable all visibility annotations inside libc++. Defining this macro and then building libc++ with hidden visibility gives a build of libc++ which does not export any symbols, which can be useful when building statically for inclusion into another library.

The NDK ships a prebuilt libc++, so that macro does nothing for you. You'd need to build your own libc++ to use that. I'm unsure what part of this is "since r22". It looks like this has always been the case and is the expected behavior?

But I think your actual complaint here is that binary size has increased. Is this a duplicate of https://github.com/android/ndk/issues/1402? If not, we don't have the information we need to investigate and you'll need to provide the repro case the template asked for.

DanAlbert avatar Jan 26 '21 23:01 DanAlbert

add_compile_options( -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS )

https://libcxx.llvm.org/docs/UsingLibcxx.html#libc-configuration-macros

This macro is used to disable all visibility annotations inside libc++. Defining this macro and then building libc++ with hidden visibility gives a build of libc++ which does not export any symbols, which can be useful when building statically for inclusion into another library.

The NDK ships a prebuilt libc++, so that macro does nothing for you. You'd need to build your own libc++ to use that. I'm unsure what part of this is "since r22". It looks like this has always been the case and is the expected behavior?

That I tried to do the same result as r21. It would be many symbols without _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS.

But I think your actual complaint here is that binary size has increased. Is this a duplicate of #1402? If not, we don't have the information we need to investigate and you'll need to provide the repro case the template asked for.

Maybe the same problem. I think the different between r21 and r22, the r21 is inline std::string functions and the r22 is extern linking std::string functions. The result is not any std::string symbols in r21, and all std::string functions symbols in r22 that it need to link libc++ library. So what kind is right? Maybe r22 is accord to C++ Standard.

metarutaiga avatar Jan 27 '21 01:01 metarutaiga

It is possible that some template instantiation become visible without _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS. But it is difficult to locate what is changed. I eye scanned through string but didn't notice any obvious visibility change. Can you provide a repro case? So that we can figure what symbols become visible.

hhb avatar Feb 22 '21 23:02 hhb

Closing as we have insufficient information currently. If we get a repro case it'll get reopened.

DanAlbert avatar Feb 22 '21 23:02 DanAlbert

teststl.cpp

#include <string>
#include <vector>

__attribute__((visibility("default")))
std::string foo()
{
    return "Hello, World!";
}

__attribute__((visibility("default")))
std::vector<char> bar()
{
    return {1};
}

__attribute__((visibility("default")))
void add_string(std::string& value)
{
    value += "Hello, World!";
}

__attribute__((visibility("default")))
void add_vector(std::vector<char>& value)
{
    value.push_back(1);
}

#if defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
_LIBCPP_BEGIN_NAMESPACE_STD
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD
#endif

ndk-r21

$ clang++ teststl.cpp --shared -fno-exceptions -fvisibility=hidden -Ofast -o a.out.21 -Wl,--strip-all
$ objdump -d a.out.21 | grep 0000
00000000000006c0 .plt:
0000000000000740 .text:
000000000000077c _Z3foov:
00000000000007a8 _Z3barv:
00000000000007e0 _Z10add_stringRNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
00000000000007f0 _Z10add_vectorRNSt6__ndk16vectorIcNS_9allocatorIcEEEE:

ndk-r22

$ clang++ teststl.cpp --shared -fno-exceptions -fvisibility=hidden -Ofast -o a.out.22 -Wl,--strip-all
$ objdump -d a.out.22 | grep 0000
0000000000001758 .text:
0000000000001794 _Z3foov:
00000000000017bc _Z3barv:
00000000000017f4 _Z10add_stringRNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
0000000000001800 _Z10add_vectorRNSt6__ndk16vectorIcNS_9allocatorIcEEEE:
00000000000018f0 .plt:
0000000000001910 __cxa_finalize@plt:
0000000000001920 __cxa_atexit@plt:
0000000000001930 _Znwm@plt:
0000000000001940 _ZNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc@plt:
0000000000001950 memcpy@plt:
0000000000001960 _ZdlPv@plt:
0000000000001970 _ZNKSt6__ndk120__vector_base_commonILb1EE20__throw_length_errorEv@plt:

ndk-r22 (_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)

$ clang++ teststl.cpp --shared -fno-exceptions -fvisibility=hidden -Ofast -o a.out.22d -Wl,--strip-all -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
$ objdump -d a.out.22d | grep 0000
0000000000001680 .text:
00000000000016bc _Z3foov:
00000000000016e4 _Z3barv:
000000000000171c _Z10add_stringRNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE:
000000000000172c _Z10add_vectorRNSt6__ndk16vectorIcNS_9allocatorIcEEEE:
00000000000019b0 .plt:
00000000000019d0 __cxa_finalize@plt:
00000000000019e0 __cxa_atexit@plt:
00000000000019f0 _Znwm@plt:
0000000000001a00 memcpy@plt:
0000000000001a10 _ZdlPv@plt:
0000000000001a20 abort@plt:

metarutaiga avatar Feb 25 '21 15:02 metarutaiga

Thanks! You've missed the window for r22b but we can take a look.

DanAlbert avatar Feb 25 '21 20:02 DanAlbert

Been trying for an hour and I can't reproduce your r21 results. Which target are you using? Assuming x86_64-linux-android21 since you're using what appears to be your system's objdump and 64-bit addresses:

danalbert :: src/ndk/ndk ‹docs*› » ../../android-ndk-r21e/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -target x86_64-linux-android21 foo.cpp --shared -fno-exceptions -fvisibility=hidden -Ofast -o libfoo.21.so -Wl,--strip-all
danalbert :: src/ndk/ndk ‹docs*› » objdump -d libfoo.21.so | grep 0000
00000000000006d0 <__cxa_finalize@plt-0x10>:
00000000000006e0 <__cxa_finalize@plt>:
00000000000006f0 <__cxa_atexit@plt>:
0000000000000700 <_Znwm@plt>:
0000000000000710 <memcpy@plt>:
0000000000000720 <_ZdlPv@plt>:
0000000000000730 <abort@plt>:
0000000000000740 <_Z3foov@@Base-0x60>:
00000000000007a0 <_Z3foov@@Base>:
00000000000007e0 <_Z3barv@@Base>:
0000000000000810 <_Z10add_stringRNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE@@Base>:
0000000000000830 <_Z10add_vectorRNSt6__ndk16vectorIcNS_9allocatorIcEEEE@@Base>:

Using readelf to look for defined vs undefined symbols even shows the opposite, though the symbols that disappeared aren't really interesting and are probably just a bfd -> lld change:

danalbert :: src/ndk/ndk ‹docs*› » readelf -sW libfoo.22.so | grep -v UND

Symbol table '.dynsym' contains 12 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     8: 00000000000019b0    12 FUNC    GLOBAL DEFAULT   13 _Z10add_stringRNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
     9: 00000000000019c0   220 FUNC    GLOBAL DEFAULT   13 _Z10add_vectorRNSt6__ndk16vectorIcNS_9allocatorIcEEEE
    10: 0000000000001980    37 FUNC    GLOBAL DEFAULT   13 _Z3barv
    11: 0000000000001950    39 FUNC    GLOBAL DEFAULT   13 _Z3foov
danalbert :: src/ndk/ndk ‹docs*› » readelf -sW libfoo.21.so | grep -v UND

Symbol table '.dynsym' contains 14 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     7: 0000000000002000     0 NOTYPE  GLOBAL DEFAULT  ABS _end
     8: 0000000000002000     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
     9: 0000000000000810    17 FUNC    GLOBAL DEFAULT   12 _Z10add_stringRNSt6__ndk112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEE
    10: 00000000000007e0    37 FUNC    GLOBAL DEFAULT   12 _Z3barv
    11: 00000000000007a0    53 FUNC    GLOBAL DEFAULT   12 _Z3foov
    12: 0000000000002000     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
    13: 0000000000000830   218 FUNC    GLOBAL DEFAULT   12 _Z10add_vectorRNSt6__ndk16vectorIcNS_9allocatorIcEEEE

DanAlbert avatar Aug 17 '21 20:08 DanAlbert

I can't make sense of why your fix actually changes anything:

_LIBCPP_BEGIN_NAMESPACE_STD
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD

_LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS is an empty definition and afaict always has been for non-Windows.

DanAlbert avatar Aug 17 '21 20:08 DanAlbert

I can't make sense of why your fix actually changes anything:

_LIBCPP_BEGIN_NAMESPACE_STD
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __basic_string_common<true>;
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS basic_string<char>;
    template class _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS __vector_base_common<true>;
_LIBCPP_END_NAMESPACE_STD

_LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS is an empty definition and afaict always has been for non-Windows.

the _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS can be ignored. the code is copied from libcxx source. the code is Implemented code because libcxx changed method that let some codes to source to make building faster.

metarutaiga avatar Aug 18 '21 03:08 metarutaiga

If the visibility macro isn't the important part there then I really don't know what that would do anything.

And without a repro case we're back to not being able to do anything to help.

DanAlbert avatar Aug 18 '21 10:08 DanAlbert