Finding where relocations originate - c++

Using Ulrich Drepper's relinfo.pl script, one can easily count the number of relocations of a DSO, but it doesn't work on .o files.
Say I have a large shared library and I'm not happy about the number of its relocations. is there a way to find out where they come from (symbol, or at least .o), to check whether they're of the easily fixable type (e.g.: const char * str = "Hello World";' -> const char str[] = "Hello World";)?

Short answer: Use objdump or readelf instead.
Long answer: Let's look at an actual example case, example.c:
#include <stdio.h>
static const char global1[] = "static const char []";
static const char *global2 = "static const char *";
static const char *const global3 = "static const char *const";
const char global4[] = "const char []";
const char *global5 = "const char *";
const char *const global6 = "const char *const";
char global7[] = "char []";
char *global8 = "char *";
char *const global9 = "char *const";
int main(void)
{
static const char local1[] = "static const char []";
static const char *local2 = "static const char *";
static const char *const local3 = "static const char *const";
const char local4[] = "const char []";
const char *local5 = "const char *";
const char *const local6 = "const char *const";
char local7[] = "char []";
char *local8 = "char *";
char *const local9 = "char *const";
printf("Global:\n");
printf("\t%s\n", global1);
printf("\t%s\n", global2);
printf("\t%s\n", global3);
printf("\t%s\n", global4);
printf("\t%s\n", global5);
printf("\t%s\n", global6);
printf("\t%s\n", global7);
printf("\t%s\n", global8);
printf("\t%s\n", global9);
printf("\n");
printf("Local:\n");
printf("\t%s\n", local1);
printf("\t%s\n", local2);
printf("\t%s\n", local3);
printf("\t%s\n", local4);
printf("\t%s\n", local5);
printf("\t%s\n", local6);
printf("\t%s\n", local7);
printf("\t%s\n", local8);
printf("\t%s\n", local9);
return 0;
}
You can compile it to an object file using e.g.
gcc -W -Wall -c example.c
and to an executable using
gcc -W -Wall example.c -o example
You can use objdump -tr example.o to dump the symbol and relocation information for the (non-dynamic) object file, or objdump -TtRr example to dump the same for the executable file (and dynamic object files). Using
objdump -t example.o
on x86-64 I get
example.o: file format elf64-x86-64
SYMBOL TABLE:
0000000000000000 l df *ABS* 0000000000000000 example.c
0000000000000000 l d .text 0000000000000000 .text
0000000000000000 l d .data 0000000000000000 .data
0000000000000000 l d .bss 0000000000000000 .bss
0000000000000000 l d .rodata 0000000000000000 .rodata
0000000000000000 l O .rodata 0000000000000015 global1
0000000000000000 l O .data 0000000000000008 global2
0000000000000048 l O .rodata 0000000000000008 global3
00000000000000c0 l O .rodata 0000000000000015 local1.2053
0000000000000020 l O .data 0000000000000008 local2.2054
00000000000000d8 l O .rodata 0000000000000008 local3.2055
0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack
0000000000000000 l d .eh_frame 0000000000000000 .eh_frame
0000000000000000 l d .comment 0000000000000000 .comment
0000000000000050 g O .rodata 000000000000000e global4
0000000000000008 g O .data 0000000000000008 global5
0000000000000080 g O .rodata 0000000000000008 global6
0000000000000010 g O .data 0000000000000008 global7
0000000000000018 g O .data 0000000000000008 global8
00000000000000a0 g O .rodata 0000000000000008 global9
0000000000000000 g F .text 000000000000027a main
0000000000000000 *UND* 0000000000000000 puts
0000000000000000 *UND* 0000000000000000 printf
0000000000000000 *UND* 0000000000000000 putchar
0000000000000000 *UND* 0000000000000000 __stack_chk_fail
The output is described in man 1 objdump, under the -t heading. Note that the second "column" is actually fixed-width: seven characters wide, describing the type of the object. The third column is the section name, *UND* for undefined, .text for code, .rodata for read-only (immutable) data, .data for initialized mutable data, and .bss for uninitialized mutable data, and so on.
We can see from the above symbol table that local4, local5, local6, local7, local8, and local9 variables didn't actually get entries in the symbol table at all. This is because they are local to main(). The contents of the strings they refer to are stored in .data or .rodata (or constructed on the fly), depending on what the compiler sees best.
Let's look at the relocation records next. Using
objdump -r example.o
I get
example.o: file format elf64-x86-64
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000037 R_X86_64_32S .rodata+0x000000000000005e
0000000000000040 R_X86_64_32S .rodata+0x000000000000006b
0000000000000059 R_X86_64_32S .rodata+0x0000000000000088
0000000000000062 R_X86_64_32S .rodata+0x000000000000008f
0000000000000067 R_X86_64_32 .rodata+0x00000000000000a8
000000000000006c R_X86_64_PC32 puts-0x0000000000000004
0000000000000071 R_X86_64_32 .rodata+0x00000000000000b0
0000000000000076 R_X86_64_32 .rodata
0000000000000083 R_X86_64_PC32 printf-0x0000000000000004
000000000000008a R_X86_64_PC32 .data-0x0000000000000004
000000000000008f R_X86_64_32 .rodata+0x00000000000000b0
000000000000009f R_X86_64_PC32 printf-0x0000000000000004
00000000000000a6 R_X86_64_PC32 .rodata+0x0000000000000044
00000000000000ab R_X86_64_32 .rodata+0x00000000000000b0
00000000000000bb R_X86_64_PC32 printf-0x0000000000000004
00000000000000c0 R_X86_64_32 .rodata+0x00000000000000b0
00000000000000c5 R_X86_64_32 global4
00000000000000d2 R_X86_64_PC32 printf-0x0000000000000004
00000000000000d9 R_X86_64_PC32 global5-0x0000000000000004
00000000000000de R_X86_64_32 .rodata+0x00000000000000b0
00000000000000ee R_X86_64_PC32 printf-0x0000000000000004
00000000000000f5 R_X86_64_PC32 global6-0x0000000000000004
00000000000000fa R_X86_64_32 .rodata+0x00000000000000b0
000000000000010a R_X86_64_PC32 printf-0x0000000000000004
000000000000010f R_X86_64_32 .rodata+0x00000000000000b0
0000000000000114 R_X86_64_32 global7
0000000000000121 R_X86_64_PC32 printf-0x0000000000000004
0000000000000128 R_X86_64_PC32 global8-0x0000000000000004
000000000000012d R_X86_64_32 .rodata+0x00000000000000b0
000000000000013d R_X86_64_PC32 printf-0x0000000000000004
0000000000000144 R_X86_64_PC32 global9-0x0000000000000004
0000000000000149 R_X86_64_32 .rodata+0x00000000000000b0
0000000000000159 R_X86_64_PC32 printf-0x0000000000000004
0000000000000163 R_X86_64_PC32 putchar-0x0000000000000004
0000000000000168 R_X86_64_32 .rodata+0x00000000000000b5
000000000000016d R_X86_64_PC32 puts-0x0000000000000004
0000000000000172 R_X86_64_32 .rodata+0x00000000000000b0
0000000000000177 R_X86_64_32 .rodata+0x00000000000000c0
0000000000000184 R_X86_64_PC32 printf-0x0000000000000004
000000000000018b R_X86_64_PC32 .data+0x000000000000001c
0000000000000190 R_X86_64_32 .rodata+0x00000000000000b0
00000000000001a0 R_X86_64_PC32 printf-0x0000000000000004
00000000000001a7 R_X86_64_PC32 .rodata+0x00000000000000d4
00000000000001ac R_X86_64_32 .rodata+0x00000000000000b0
00000000000001bc R_X86_64_PC32 printf-0x0000000000000004
00000000000001c1 R_X86_64_32 .rodata+0x00000000000000b0
00000000000001d6 R_X86_64_PC32 printf-0x0000000000000004
00000000000001db R_X86_64_32 .rodata+0x00000000000000b0
00000000000001ef R_X86_64_PC32 printf-0x0000000000000004
00000000000001f4 R_X86_64_32 .rodata+0x00000000000000b0
0000000000000209 R_X86_64_PC32 printf-0x0000000000000004
000000000000020e R_X86_64_32 .rodata+0x00000000000000b0
0000000000000223 R_X86_64_PC32 printf-0x0000000000000004
0000000000000228 R_X86_64_32 .rodata+0x00000000000000b0
000000000000023d R_X86_64_PC32 printf-0x0000000000000004
0000000000000242 R_X86_64_32 .rodata+0x00000000000000b0
0000000000000257 R_X86_64_PC32 printf-0x0000000000000004
0000000000000271 R_X86_64_PC32 __stack_chk_fail-0x0000000000000004
RELOCATION RECORDS FOR [.data]:
OFFSET TYPE VALUE
0000000000000000 R_X86_64_64 .rodata+0x0000000000000015
0000000000000008 R_X86_64_64 .rodata+0x000000000000005e
0000000000000018 R_X86_64_64 .rodata+0x0000000000000088
0000000000000020 R_X86_64_64 .rodata+0x0000000000000015
RELOCATION RECORDS FOR [.rodata]:
OFFSET TYPE VALUE
0000000000000048 R_X86_64_64 .rodata+0x0000000000000029
0000000000000080 R_X86_64_64 .rodata+0x000000000000006b
00000000000000a0 R_X86_64_64 .rodata+0x000000000000008f
00000000000000d8 R_X86_64_64 .rodata+0x0000000000000029
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
0000000000000020 R_X86_64_PC32 .text
The relocation records are grouped by the section they relocation resides in. Because string contents are in the .data or .rodata sections, we can restrict ourselves to look at the relocations where the VALUE starts with .data or .rodata. (Mutable strings, like char global7[] = "char []";, are stored in .data, and immutable strings and string literals in .rodata.)
If we were to compile the code with debugging symbols enabled, it would be easier to determine which variable was used to refer to which string, but I might just look at the actual contents at each relocation value (target), to see which references to the immutable strings need fixing.
The command combination
objdump -r example.o | awk '($3 ~ /^\..*\+/) { t = $3; sub(/\+/, " ", t); n[t]++ } END { for (r in n) printf "%d %s\n", n[r], r }' | sort -g
will output the number of relocations per target, followed by the target section, followed by the target offset in the section, sorted with the target that occurs most in relocations last. That is, the last lines output above are the ones you need to concentrate on. For me, I get
1 .rodata
1 .rodata 0x0000000000000044
1 .rodata 0x00000000000000a8
1 .rodata 0x00000000000000b5
1 .rodata 0x00000000000000c0
1 .rodata 0x00000000000000d4
2 .rodata 0x0000000000000015
2 .rodata 0x0000000000000029
2 .rodata 0x000000000000005e
2 .rodata 0x000000000000006b
2 .rodata 0x0000000000000088
2 .rodata 0x000000000000008f
18 .rodata 0x00000000000000b0
If I add optimization (gcc -W -Wall -O3 -fomit-frame-pointer -c example.c), the result is
1 .rodata 0x0000000000000020
1 .rodata 0x0000000000000040
1 .rodata.str1.1
1 .rodata.str1.1 0x0000000000000058
2 .rodata.str1.1 0x000000000000000d
2 .rodata.str1.1 0x0000000000000021
2 .rodata.str1.1 0x000000000000005f
2 .rodata.str1.1 0x000000000000006c
3 .rodata.str1.1 0x000000000000003a
3 .rodata.str1.1 0x000000000000004c
18 .rodata.str1.1 0x0000000000000008
which shows that compiler options do have a big effect, but that there is that one target that is anyways used 18 times: section .rodata offset 0xb0 (.rodata.str1.1 offset 0x8 if optimization is enabled at compile time).
That is the `"\t%s\n" string literal.
Modifying the original program into
char *local8 = "char *";
char *const local9 = "char *const";
const char *const fmt = "\t%s\n";
printf("Global:\n");
printf(fmt, global1);
printf(fmt, global2);
and so on, replacing the format string with an immutable string pointer fmt, eliminates those 18 relocations altogether. (You can also use the equivalent const char fmt[] = "\t%s\n";, of course.)
The above analysis indicates that at least with GCC-4.6.3, most of the avoidable relocations are caused by (repeated use of) string literals. Replacing them with an array of const chars (const char fmt[] = "\t%s\n";) or a const pointer to const chars (const char *const fmt = "\t%s\n";) -- both cases putting the contents to .rodata section, read-only, and the pointer/array reference itself is immutable too -- seems an effective and safe strategy to me.
Furthermore, conversion of string literals to immutable string pointers or char arrays is completely a source-level task. That is, if you convert all string literals using the above method, you can eliminate at least one relocation per string literal.
In fact, I don't see how object-level analysis will help you much, here. It will tell you if your modifications reduce the number of relocations needed, of course.
The above awk stanza can be extended to a function that outputs the string constants for dynamic references with positive offsets:
#!/bin/bash
if [ $# -ne 1 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
exec >&2
echo ""
echo "Usage: %s [ -h | --help ]"
echo " %s object.o"
echo ""
exit 1
fi
export LANG=C LC_ALL=C
objdump -wr "$1" | awk '
BEGIN {
RS = "[\t\v\f ]*[\r\n][\t\n\v\f\r ]*"
FS = "[\t\v\f ]+"
}
$1 ~ /^[0-9A-Fa-f]+/ {
n[$3]++
}
END {
for (s in n)
printf "%d %s\n", n[s], s
}
' | sort -g | gawk -v filename="$1" '
BEGIN {
RS = "[\t\v\f ]*[\r\n][\t\n\v\f\r ]*"
FS = "[\t\v\f ]+"
cmd = "objdump --file-offsets -ws " filename
while ((cmd | getline) > 0)
if ($3 == "section") {
s = $4
sub(/:$/, "", s)
o = $NF
sub(/\)$/, "", o)
start[s] = strtonum(o)
}
close(cmd)
}
{
if ($2 ~ /\..*\+/) {
s = $2
o = $2
sub(/\+.*$/, "", s)
sub(/^[^\+]*\+/, "", o)
o = strtonum(o) + start[s]
cmd = "dd if=\"" filename "\" of=/dev/stdout bs=1 skip=" o " count=256"
OLDRS = RS
RS = "\0"
cmd | getline hex
close(cmd)
RS = OLDRS
gsub(/\\/, "\\\\", hex)
gsub(/\t/, "\\t", hex)
gsub(/\n/, "\\n", hex)
gsub(/\r/, "\\r", hex)
gsub(/\"/, "\\\"", hex)
if (hex ~ /[\x00-\x1F\x7F-\x9F\xFE\xFF]/ || length(hex) < 1)
printf "%s\n", $0
else
printf "%s = \"%s\"\n", $0, hex
} else
print $0
}
'
This is a bit crude, just slapped together, so I don't know how portable it is. On my machine, it does seem to find the string literals for the few test cases I tried it on; you should probably rewrite it to match your own needs. Or even use an actual programming language with ELF support to examine the object files directly.
For the example program shown above (prior to the modifications I suggest to reduce the number of relocations), compiled without optimization, the above script yields the output
1 .data+0x000000000000001c = ""
1 .data-0x0000000000000004
1 .rodata
1 .rodata+0x0000000000000044 = ""
1 .rodata+0x00000000000000a8 = "Global:"
1 .rodata+0x00000000000000b5 = "Local:"
1 .rodata+0x00000000000000c0 = "static const char []"
1 .rodata+0x00000000000000d4 = ""
1 .text
1 __stack_chk_fail-0x0000000000000004
1 format
1 global4
1 global5-0x0000000000000004
1 global6-0x0000000000000004
1 global7
1 global8-0x0000000000000004
1 global9-0x0000000000000004
1 putchar-0x0000000000000004
2 .rodata+0x0000000000000015 = "static const char *"
2 .rodata+0x0000000000000029 = "static const char *const"
2 .rodata+0x000000000000005e = "const char *"
2 .rodata+0x000000000000006b = "const char *const"
2 .rodata+0x0000000000000088 = "char *"
2 .rodata+0x000000000000008f = "char *const"
2 puts-0x0000000000000004
18 .rodata+0x00000000000000b0 = "\t%s\n"
18 printf-0x0000000000000004
Finally, you might notice that using a function pointer to printf() instead of calling printf() directly will reduce another 18 relocations from the example code, but I would consider that a mistake.
For code, you want relocations, as indirect function calls (calls via function pointers) are much slower than direct calls. Simply put, those relocations make function and subroutine calls much faster, so you most definitely want to keep those.
Apologies for the long answer; hope you find this useful. Questions?

Based on Nomainal Animals's answer, which I still have to fully digest, I have come up with the following simple shell script that seems to work for finding what I called the "easily fixable" variety:
for i in path/to/*.o ; do
REL="$(objdump -TtRr "$i" 2>/dev/null | grep '.data.rel.ro.local[^]+-]')"
if [ -n "$REL" ]; then
echo "$(basename "$i"):"
echo "$REL" | c++filt
echo
fi
done
Sample output (for the QtGui library):
qimagereader.o:
0000000000000000 l O .data.rel.ro.local 00000000000000c0 _qt_BuiltInFormats
0000000000000000 l d .data.rel.ro.local 0000000000000000 .data.rel.ro.local
qopenglengineshadermanager.o:
0000000000000000 l O .data.rel.ro.local 0000000000000090 QOpenGLEngineShaderManager::getUniformLocation(QOpenGLEngineShaderManager::Uniform)::uniformNames
0000000000000000 l d .data.rel.ro.local 0000000000000000 .data.rel.ro.local
qopenglpaintengine.o:
0000000000000000 l O .data.rel.ro.local 0000000000000020 vtable for (anonymous namespace)::QOpenGLStaticTextUserData
0000000000000000 l d .data.rel.ro.local 0000000000000000 .data.rel.ro.local
qtexthtmlparser.o:
0000000000000000 l O .data.rel.ro.local 00000000000003b0 elements
0000000000000000 l d .data.rel.ro.local 0000000000000000 .data.rel.ro.local
Looking up those symbols in the source file usually leads quickly to a fix, or else to the discovery that they're not easily fixable.
But I guess I'll have to revisit Nominal Animal's answer once I run out of .data.rel.ro.locals to fix...

Related

Multiple definitions of inline function C++

I know there is already a lot of topics about this subject, however I didn't find in any of them the explanation to how it is possible to have one definition of an inline function per translation unit. I know that inline functions have external linkage, so when I call one inline function in different translation units they all reference the same function. I also know that in Linux the compiler registers inline function with the "W" symbol, so it is registered as a weak symbol (thanks to it the first definition encountered by the compiler of the inline function is the one considered). However whenever I use nm on the object files created by g++ in Windows there is no weak symbol attached to the function signature. How can the linker know which definition to consider and not to accuse of multiple definitions? (I don't show the linker's work but I tested it).
Here is some example code:
// main1.cpp
#include "main.hpp"
/* inline accepts one definition in each TU's */
inline void Test::hello_world()
{
std::cout << "Hello world" << std::endl;
}
/*void Test::hello_world()
{
std::cout << "Hello world" << std::endl;
}*/
extern void return_hello_world();
int main()
{
Test t;
t.hello_world();
return_hello_world();
return 0;
}
// main2.cpp
#include "main.hpp"
/* inline accepts one definition in each TU's */
inline void Test::hello_world()
{
std::cout << "Hello world" << std::endl;
}
/* void Test::hello_world()
{
std::cout << "Hello world" << std::endl;
} */
void return_hello_world()
{
Test t;
t.hello_world();
}
// main.hpp
#ifndef TEST
#define TEST
#include <iostream>
class Test
{
public:
void hello_world();
};
#endif
The results I receive are:
Windows:
Experimentation4> g++ -g -O0 -c main1.cpp main2.cpp
Experimentation4> nm main1.o
0000000000000000 b .bss
0000000000000000 d .ctors
0000000000000000 d .data
0000000000000000 N .debug_abbrev
0000000000000000 N .debug_aranges
0000000000000000 N .debug_frame
0000000000000000 N .debug_info
0000000000000000 N .debug_line
0000000000000000 N .debug_ranges
0000000000000000 N .debug_str
0000000000000000 p .pdata
0000000000000000 p .pdata$_ZN4Test11hello_worldEv
0000000000000000 r .rdata
0000000000000000 r .rdata$.refptr._ZSt4cout
0000000000000000 r .rdata$.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 r .rdata$zzz
0000000000000000 R .refptr._ZSt4cout
0000000000000000 R .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 t .text
0000000000000000 t .text$_ZN4Test11hello_worldEv
0000000000000000 r .xdata
0000000000000000 r .xdata$_ZN4Test11hello_worldEv
U __main
0000000000000029 t __tcf_0
0000000000000080 t _GLOBAL__sub_I_main
U _Z18return_hello_worldv
0000000000000044 t _Z41__static_initialization_and_destruction_0ii
0000000000000000 T _ZN4Test11hello_worldEv
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 r _ZStL19piecewise_construct
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
U atexit
0000000000000000 T main
Linux:
Experimentation2$ g++ -O0 -g -c main1.cpp main2.cpp
Experimentation2$ nm main1.o
U __cxa_atexit
U __dso_handle
0000000000000081 t _GLOBAL__sub_I_main
0000000000000000 T main
U __stack_chk_fail
U _Z18return_hello_worldv
0000000000000043 t _Z41__static_initialization_and_destruction_0ii
0000000000000000 W _ZN4Test11hello_worldEv
U _ZNSolsEPFRSoS_E
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cout
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

static library convert to a shared lib symbols are hidden?

I am trying to link v8's static library to a shared library using the following cmake command
add_library(v8jni SHARED ${THIRDPARTY_LIB_PATH}/shared/v8jni.cpp)
target_link_libraries(v8jni log
-Wl,--whole-archive v8_inspector
v8_base
v8_snapshot
v8_libplatform
v8_libsampler
v8_libbase
-Wl,--no-whole-archive)
libv8jni.so is generated successfully. But it's useless because all the v8 function are marked as local.
nm -C libv8_base.a | grep v8::HandleScope
00000000 T v8::HandleScope::Initialize(v8::Isolate*)
00000000 T v8::HandleScope::CreateHandle(v8::internal::NeverReadOnlySpaceObject*, unsigned int)
00000000 T v8::HandleScope::CreateHandle(v8::internal::Isolate*, unsigned int)
00000000 T v8::HandleScope::NumberOfHandles(v8::Isolate*)
00000000 T v8::HandleScope::HandleScope(v8::Isolate*)
00000000 T v8::HandleScope::HandleScope(v8::Isolate*)
00000000 T v8::HandleScope::~HandleScope()
00000000 T v8::HandleScope::~HandleScope()
00000000 T v8::HandleScope::operator delete[](void*, unsigned int)
00000000 T v8::HandleScope::operator delete(void*, unsigned int)
00000000 T v8::HandleScope::operator new[](unsigned int)
00000000 T v8::HandleScope::operator new(unsigned int)
U v8::HandleScope::CreateHandle(v8::internal::Isolate*, unsigned int)
U v8::HandleScope::HandleScope(v8::Isolate*)
U v8::HandleScope::~HandleScope()
U v8::HandleScope::HandleScope(v8::Isolate*)
U v8::HandleScope::~HandleScope()
whereas nm -C libv8jni.so | gives me the following output.
Please note the symbol type is t not T, means they only be accessed locally.
nm -C libv8jni.so| grep v8::HandleScope
000c0b48 t v8::HandleScope::Initialize(v8::Isolate*)
000c0c32 t v8::HandleScope::CreateHandle(v8::internal::NeverReadOnlySpaceObject*, unsigned int)
000c0c0c t v8::HandleScope::CreateHandle(v8::internal::Isolate*, unsigned int)
000c0c08 t v8::HandleScope::NumberOfHandles(v8::Isolate*)
000c0b3c t v8::HandleScope::HandleScope(v8::Isolate*)
000c0b3c t v8::HandleScope::HandleScope(v8::Isolate*)
000c4ad4 t v8::HandleScope::~HandleScope()
000c4ad4 t v8::HandleScope::~HandleScope()
000c0c02 t v8::HandleScope::operator delete[](void*, unsigned int)
000c0bfc t v8::HandleScope::operator delete(void*, unsigned int)
000c0bf6 t v8::HandleScope::operator new[](unsigned int)
000c0bf0 t v8::HandleScope::operator new(unsigned int)
v8jni.cpp is very simple
#include <jni.h>
#include <android/log.h>
#include <assert.h>
static const char* LOG_TAG = "v8jni";
extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv* env = NULL;
jint result = -1;
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "JNI_OnLoad");
if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) {
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "GetEnv Failed!");
return result;
}
assert(env != nullptr && "env is nullptr");
return JNI_VERSION_1_4;
}
The link command as follows, it's a test script.
+ rm ../../../.././build/intermediates/cmake/debug/obj/armeabi-v7a/libv8jni.so
+ /Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/clang++ -v --target=armv7-none-linux-androideabi --gcc-toolchain=/Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64 --sysroot=/Users/leoliu/Library/Android/sdk/ndk-bundle/sysroot -fPIC -isystem /Users/leoliu/Library/Android/sdk/ndk-bundle/sysroot/usr/include/arm-linux-androideabi -D__ANDROID_API__=15 -g -DANDROID -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -std=c++11 --sysroot /Users/leoliu/Library/Android/sdk/ndk-bundle/platforms/android-15/arch-arm -L/Users/leoliu/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -shared -Wl,-soname,libv8jni.so -o ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libv8jni.so CMakeFiles/v8jni.dir/src/main/cpp/thirdparty/shared/v8jni.cpp.o -llog -Wl,--whole-archive ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_inspector.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_base.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_snapshot.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_libplatform.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_libsampler.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_libbase.a -Wl,--no-whole-archive -latomic -lm /Users/leoliu/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++.a
Android clang version 5.0.300080 (based on LLVM 5.0.300080)
Target: armv7-none-linux-android
Thread model: posix
InstalledDir: /Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin
Found candidate GCC installation: /Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x
Selected GCC installation: /Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x
Candidate multilib: thumb;#thumb
Candidate multilib: armv7-a;#armv7
Candidate multilib: armv7-a/thumb;#armv7#thumb
Candidate multilib: .;
Selected multilib: armv7-a;#armv7
"/Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/bin/ld" --sysroot=/Users/leoliu/Library/Android/sdk/ndk-bundle/platforms/android-15/arch-arm -X --eh-frame-hdr -m armelf_linux_eabi -shared -o ../../../../build/intermediates/cmake/debug/obj/armeabi-v7a/libv8jni.so /Users/leoliu/Library/Android/sdk/ndk-bundle/platforms/android-15/arch-arm/usr/lib/../lib/crtbegin_so.o -L/Users/leoliu/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a -L/Users/leoliu/Library/Android/android-ndk-r16b/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/5.0.300080/lib/linux/arm -L/Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/armv7-a -L/Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/lib/../lib/armv7-a -L/Users/leoliu/Library/Android/sdk/ndk-bundle/platforms/android-15/arch-arm/usr/lib/../lib -L/Users/leoliu/Library/Android/sdk/ndk-bundle/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/../../../../arm-linux-androideabi/lib/armv7-a -L/Users/leoliu/Library/Android/sdk/ndk-bundle/platforms/android-15/arch-arm/usr/lib -soname libv8jni.so CMakeFiles/v8jni.dir/src/main/cpp/thirdparty/shared/v8jni.cpp.o -llog --whole-archive ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_inspector.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_base.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_snapshot.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_libplatform.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_libsampler.a ../../../../src/main/cpp/thirdparty/library/static/armeabi-v7a/libv8_libbase.a --no-whole-archive -latomic -lm /Users/leoliu/Library/Android/sdk/ndk-bundle/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++.a -lstdc++ -lm -lgcc -ldl -lc -lgcc -ldl /Users/leoliu/Library/Android/sdk/ndk-bundle/platforms/android-15/arch-arm/usr/lib/../lib/crtend_so.o
+ nm -C ../../../.././build/intermediates/cmake/debug/obj/armeabi-v7a/libv8jni.so
+ grep v8::HandleScope
000c0b48 t v8::HandleScope::Initialize(v8::Isolate*)
000c0c32 t v8::HandleScope::CreateHandle(v8::internal::NeverReadOnlySpaceObject*, unsigned int)
000c0c0c t v8::HandleScope::CreateHandle(v8::internal::Isolate*, unsigned int)
000c0c08 t v8::HandleScope::NumberOfHandles(v8::Isolate*)
000c0b3c t v8::HandleScope::HandleScope(v8::Isolate*)
000c0b3c t v8::HandleScope::HandleScope(v8::Isolate*)
000c4ad4 t v8::HandleScope::~HandleScope()
000c4ad4 t v8::HandleScope::~HandleScope()
000c0c02 t v8::HandleScope::operator delete[](void*, unsigned int)
000c0bfc t v8::HandleScope::operator delete(void*, unsigned int)
000c0bf6 t v8::HandleScope::operator new[](unsigned int)
000c0bf0 t v8::HandleScope::operator new(unsigned int)
Any possible reason causing the problem? Thanks in advance.
I might know the answer, I suspect the root cause is the .hidden in the object file
cpu-arm.o: file format elf32-littlearm
SYMBOL TABLE:
00000000 l df *ABS* 00000000 cpu-arm.cc
00000000 l d .text._ZN2v88internal11CpuFeatures11FlushICacheEPvj 00000000 .text._ZN2v88internal11CpuFeatures11FlushICacheEPvj
00000000 g F .text._ZN2v88internal11CpuFeatures11FlushICacheEPvj 00000010 .hidden _ZN2v88internal11CpuFeatures11FlushICacheEPvj
00000000 *UND* 00000000 __aeabi_unwind_cpp_pr0
The nm's output is a miss leading.
What does ".hidden" mean in the output of output objdump -t?
For anyone encounters the problem, there is a switch in v8's build script
v8/gni/v8.gni
if ((is_posix || is_fuchsia) && (v8_enable_backtrace || v8_monolithic)) {
v8_remove_configs += [ "//build/config/gcc:symbol_visibility_hidden" ]
v8_add_configs += [ "//build/config/gcc:symbol_visibility_default" ]
}
so we need set v8_enable_backtrace=true when compiling v8, problem resolved.

With vcpkg how do I build boost using a different c++ standard?

Building an application linked with the default vcpkg build of boost on macos 10.14.1 yields the following errors:
Undefined symbols for architecture x86_64:
"boost::system::detail::system_category_instance", referenced from:
boost::system::system_category() in main.cxx.o
boost::asio::io_context::run() in main.cxx.o
boost::asio::detail::socket_ops::close(int, unsigned char&, bool, boost::system::error_code&) in main.cxx.o
boost::asio::detail::socket_holder::~socket_holder() in main.cxx.o
boost::asio::detail::reactive_socket_service_base::destroy(boost::asio::detail::reactive_socket_service_base::base_implementation_type&) in main.cxx.o
_main in main.cxx.o
boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> boost::asio::connect<boost::asio::ip::tcp, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp> >(boost::asio::basic_socket<boost::asio::ip::tcp>&, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>, boost::asio::ip::basic_resolver_iterator<boost::asio::ip::tcp>) in main.cxx.o
...
"boost::system::detail::generic_category_instance", referenced from:
boost::system::generic_category() in main.cxx.o
ld: symbol(s) not found for architecture x86_64
collect2: error: ld returned 1 exit status
make[2]: *** [cleverly] Error 1
make[1]: *** [CMakeFiles/cleverly.dir/all] Error 2
make: *** [all] Error 2
If I'm reading the following correctly:
https://github.com/Microsoft/vcpkg/issues/4437
https://github.com/boostorg/system/issues/26
I assume boost must be recompiled with the same version of c++ as the application.
With vcpkg, how might one change the c++ standard used to compile the boost libraries?
Updates
libboost_system.a is indeed 64 bit.
lipo -info libboost_system.a
Non-fat file: libboost_system.a is architecture: x86_64
Linking commands when make is run with VERBOSE=1:
/usr/local/Cellar/cmake/3.12.4/bin/cmake -E cmake_link_script CMakeFiles/cleverly.dir/link.txt --verbose=1
/usr/local/bin/g++-HEAD -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX10.14.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/cleverly.dir/Users/sheel/Projects/sheeldme/cleverly-misogamist/source/main.cxx.o -o cleverly /opt/vcpkg/installed/x64-osx/debug/lib/libboost_system.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_filesystem.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_date_time.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_thread.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_regex.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_serialization.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_chrono.a /opt/vcpkg/installed/x64-osx/debug/lib/libboost_atomic.a
Symbol table through: objdump -t libboost_system.a
libboost_system.a(error_code.o): file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000016138 l __DATA,__bss __ZGVZNK5boost6system6detail22generic_error_category7messageEiE11unknown_err
0000000000016120 l __DATA,__bss __ZZNK5boost6system6detail22generic_error_category7messageEiE11unknown_err
0000000000001080 l __TEXT,__gcc_except_tab GCC_except_table0
0000000000016178 l __DATA,__bss __ZGVZN5boost6system6detail20generic_category_ncxEvE25generic_category_instance
0000000000016160 l __DATA,__bss __ZZN5boost6system6detail20generic_category_ncxEvE25generic_category_instance
0000000000016158 l __DATA,__bss __ZGVZN5boost6system6detail19system_category_ncxEvE24system_category_instance
0000000000016140 l __DATA,__bss __ZZN5boost6system6detail19system_category_ncxEvE24system_category_instance
0000000000001060 gw F __TEXT,__text __ZN5boost6system14error_category12std_categoryD0Ev
0000000000001050 gw F __TEXT,__text __ZN5boost6system14error_category12std_categoryD1Ev
0000000000000e90 g F __TEXT,__text __ZN5boost6system6detail19system_category_ncxEv
0000000000000f20 g F __TEXT,__text __ZN5boost6system6detail20generic_category_ncxEv
0000000000001030 gw F __TEXT,__text __ZN5boost6system6detail21system_error_categoryD0Ev
0000000000000f10 gw F __TEXT,__text __ZN5boost6system6detail21system_error_categoryD1Ev
0000000000000fb0 gw F __TEXT,__text __ZN5boost6system6detail22generic_error_categoryD0Ev
0000000000000fa0 gw F __TEXT,__text __ZN5boost6system6detail22generic_error_categoryD1Ev
0000000000001010 gw F __TEXT,__text __ZNK5boost6system14error_category10equivalentERKNS0_10error_codeEi
0000000000000fe0 gw F __TEXT,__text __ZNK5boost6system14error_category10equivalentEiRKNS0_15error_conditionE
0000000000001070 gw F __TEXT,__text __ZNK5boost6system14error_category12std_category4nameEv
0000000000000fd0 gw F __TEXT,__text __ZNK5boost6system14error_category23default_error_conditionEi
0000000000000220 g F __TEXT,__text __ZNK5boost6system6detail21system_error_category23default_error_conditionEi
0000000000001040 gw F __TEXT,__text __ZNK5boost6system6detail21system_error_category4nameEv
0000000000000e00 g F __TEXT,__text __ZNK5boost6system6detail21system_error_category7messageEi
0000000000000fc0 gw F __TEXT,__text __ZNK5boost6system6detail22generic_error_category4nameEv
0000000000000000 g F __TEXT,__text __ZNK5boost6system6detail22generic_error_category7messageEi
0000000000001148 gw __DATA,__const __ZTIN5boost12noncopyable_11noncopyableE
0000000000001220 gw __DATA,__const __ZTIN5boost6system14error_category12std_categoryE
0000000000001160 gw __DATA,__const __ZTIN5boost6system14error_categoryE
00000000000011e0 g __DATA,__const __ZTIN5boost6system6detail21system_error_categoryE
0000000000001180 g __DATA,__const __ZTIN5boost6system6detail22generic_error_categoryE
0000000000001280 gw __TEXT,__const __ZTSN5boost12noncopyable_11noncopyableE
00000000000012e0 gw __TEXT,__const __ZTSN5boost6system14error_category12std_categoryE
0000000000001260 gw __TEXT,__const __ZTSN5boost6system14error_categoryE
00000000000012b0 g __TEXT,__const __ZTSN5boost6system6detail21system_error_categoryE
0000000000001230 g __TEXT,__const __ZTSN5boost6system6detail22generic_error_categoryE
00000000000011f8 gw __DATA,__const __ZTVN5boost6system14error_category12std_categoryE
0000000000001198 g __DATA,__const __ZTVN5boost6system6detail21system_error_categoryE
0000000000001100 g __DATA,__const __ZTVN5boost6system6detail22generic_error_categoryE
0000000000000000 *UND* __Unwind_Resume
0000000000000000 *UND* __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6assignEPKc
0000000000000000 *UND* __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEEC1ERKS5_
0000000000000000 *UND* __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev
0000000000000000 *UND* __ZTVN10__cxxabiv117__class_type_infoE
0000000000000000 *UND* __ZTVN10__cxxabiv120__si_class_type_infoE
0000000000000000 *UND* __ZdlPv
0000000000000000 *UND* ___cxa_atexit
0000000000000000 *UND* ___cxa_begin_catch
0000000000000000 *UND* ___cxa_end_catch
0000000000000000 *UND* ___cxa_guard_acquire
0000000000000000 *UND* ___cxa_guard_release
0000000000000000 *UND* ___dso_handle
0000000000000000 *UND* ___gxx_personality_v0
0000000000000000 *UND* ___stack_chk_fail
0000000000000000 *UND* ___stack_chk_guard
0000000000000000 *UND* _free
0000000000000000 *UND* _malloc
0000000000000000 *UND* _strerror_r
Patch the file at vcpkg/ports/boost-modular-build-helper/CMakeLists.txt.
Patch the custom boost target with cxxstd= followed by the standard you wish to compile with.
Reference: https://github.com/Microsoft/vcpkg/issues/4476

AWL Lambda CGO not deterministic SIGILL: illegal instruction

I tried to test AWS lambda function with golang and cgo. I compiled everything on Amazon Linux AMI 2018.03.0 (HVM) and attached all necessary libraries. When I run it looks like a lambda function is not deterministic. Sometimes it's working properly and sometimes I get an exception attached below. It looks like lambda has two different environments (architectures). When it's working properly, lambda response properly to every query until will die or I will deploy a new version. The same binary working now and not working in half an hour.
SIGILL: illegal instruction
PC=0xb94571 m=10 sigcode=2
goroutine 0 [idle]:
runtime: unknown pc 0xb94571
stack: frame={sp:0x7f8957ffcef0, fp:0x0} stack=[0x7f89577fd830,0x7f8957ffd430)
00007f8957ffcdf0: 00007f8950000078 00007f8968e64de2
00007f8957ffce00: 0000000800000002 0000000000001000
00007f8957ffce10: 3ff0000000000000 0000000000000000
00007f8957ffce20: 0000000100000000 0000000000000001
00007f8957ffce30: 0000000100000002 0000000000000100
00007f8957ffce40: 0000000000000000 00000000014351f8
00007f8957ffce50: 00000000000000fa 00007f8950000078
00007f8957ffce60: 00007f8950000020 000000000002d97e
00007f8957ffce70: 0000000000002710 000000000002d990
00007f8957ffce80: 00007f8950000078 00007f8968e65ba5
00007f8957ffce90: 000000000002d97e 00007f896c05b5c4
00007f8957ffcea0: 0000000000000b66 00007f89693c3678
00007f8957ffceb0: 0000000000000005 000000000000000b
00007f8957ffcec0: 000000000f71e367 00007f896c05bcfb
00007f8957ffced0: 0000007c0000009b 00007f8957ffcf10
00007f8957ffcee0: 00007f89693c30ec 00007f89693c3c48
00007f8957ffcef0: <00007f8957ffd020 00007f8957ffd010
00007f8957ffcf00: d04e2b6900000027 eeba4bc401709342
00007f8957ffcf10: 0000000000000000 3fdfdf19b3eb7010
00007f8957ffcf20: 00000000000005e2 00007f8964663010
00007f8957ffcf30: 00000000000000f8 00000000000001f6
00007f8957ffcf40: 00000000000001f3 00000000000002ee
00007f8957ffcf50: 0000000000000000 00007f896c107010
00007f8957ffcf60: 0000000000000000 bfdfdf19b3eb7010
00007f8957ffcf70: 00007f896c26aca8 00007f896c2754a8
00007f8957ffcf80: 00007f896c275150 00007f896c05bfdf
00007f8957ffcf90: 00000000000000f9 00007f896c26aca8
00007f8957ffcfa0: 0000000000000005 0000000000000000
00007f8957ffcfb0: 00007f8900000001 00007f896c275150
00007f8957ffcfc0: 00007f8957ffd0f0 00007f8957ffd0e0
00007f8957ffcfd0: 00007f8900000029 0000000000b7652d
00007f8957ffcfe0: 0000000000000000 00007f896c2754a8
runtime: unknown pc 0xb94571
stack: frame={sp:0x7f8957ffcef0, fp:0x0} stack=[0x7f89577fd830,0x7f8957ffd430)
00007f8957ffcdf0: 00007f8950000078 00007f8968e64de2
00007f8957ffce00: 0000000800000002 0000000000001000
00007f8957ffce10: 3ff0000000000000 0000000000000000
00007f8957ffce20: 0000000100000000 0000000000000001
00007f8957ffce30: 0000000100000002 0000000000000100
00007f8957ffce40: 0000000000000000 00000000014351f8
00007f8957ffce50: 00000000000000fa 00007f8950000078
00007f8957ffce60: 00007f8950000020 000000000002d97e
00007f8957ffce70: 0000000000002710 000000000002d990
00007f8957ffce80: 00007f8950000078 00007f8968e65ba5
00007f8957ffce90: 000000000002d97e 00007f896c05b5c4
00007f8957ffcea0: 0000000000000b66 00007f89693c3678
00007f8957ffceb0: 0000000000000005 000000000000000b
00007f8957ffcec0: 000000000f71e367 00007f896c05bcfb
00007f8957ffced0: 0000007c0000009b 00007f8957ffcf10
00007f8957ffcee0: 00007f89693c30ec 00007f89693c3c48
00007f8957ffcef0: <00007f8957ffd020 00007f8957ffd010
00007f8957ffcf00: d04e2b6900000027 eeba4bc401709342
00007f8957ffcf10: 0000000000000000 3fdfdf19b3eb7010
00007f8957ffcf20: 00000000000005e2 00007f8964663010
00007f8957ffcf30: 00000000000000f8 00000000000001f6
00007f8957ffcf40: 00000000000001f3 00000000000002ee
00007f8957ffcf50: 0000000000000000 00007f896c107010
00007f8957ffcf60: 0000000000000000 bfdfdf19b3eb7010
00007f8957ffcf70: 00007f896c26aca8 00007f896c2754a8
00007f8957ffcf80: 00007f896c275150 00007f896c05bfdf
00007f8957ffcf90: 00000000000000f9 00007f896c26aca8
00007f8957ffcfa0: 0000000000000005 0000000000000000
00007f8957ffcfb0: 00007f8900000001 00007f896c275150
00007f8957ffcfc0: 00007f8957ffd0f0 00007f8957ffd0e0
00007f8957ffcfd0: 00007f8900000029 0000000000b7652d
00007f8957ffcfe0: 0000000000000000 00007f896c2754a8
goroutine 12 [syscall]:
runtime.cgocall(0xb20bc0, 0xc420144af0, 0x240)
/usr/local/go/src/runtime/cgocall.go:128 +0x64 fp=0xc420144ab0 sp=0xc420144a78 pc=0x4b7c84
github.com/app/vectorization._Cfunc_GetFaceRectangles(0xc420413680, 0x7f89500008c0, 0xc, 0x0)
_cgo_gotypes.go:99 +0x4e fp=0xc420144af0 sp=0xc420144ab0 pc=0xb1df8e
github.com/app/vectorization.GetFaceBoundingRectangles(0xc420402f40, 0x32, 0xc40000000c, 0x0, 0x0, 0x0, 0x0, 0x0)
...

Undefined reference within static library, although the function is there

I try to compile QDP++ C++ library using the Intel 17 compiler and Intel MPI on an Intel Xeon supercomputer. The dependency QMP C library has already been compiled with that compiler (mpiicc), there were no compilation errors.
When trying to configure QDP++, I get this error from the Intel compiler:
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `QMP_comm_get_allocated':
QMP_init.c:(.text+0x55): undefined reference to `QMP_abort_mpi(int)'
And this from GCC 5.4:
~/local-jureca/lib/libqmp.a(QMP_init.o):QMP_init.c:function QMP_comm_get_allocated: error: undefined reference to 'QMP_abort_mpi(int)'
So it is an actual problem and not just something that the Intel C++ with MPI compiler cannot do.
The output of nm ~/local-jureca/lib/libqmp.a contains this stanza where QMP_comm_get_allocated resides in.
QMP_init.o:
U atol
U __ctype_b_loc
U exit
U __gcc_personality_v0
U __gxx_personality_v0
U malloc
00000000000015f0 T QMP_abort
00000000000015c0 T QMP_abort_string
0000000000000010 D QMP_allocated_comm
0000000000000018 d QMP_allocated_comm_s
0000000000000000 D QMP_args
0000000000000000 b QMP_args_s
U QMP_barrier
U QMP_comm_declare_logical_topology_map
0000000000000000 T QMP_comm_get_allocated
0000000000001760 T QMP_comm_get_default
00000000000000e0 T QMP_comm_get_job
U QMP_comm_get_logical_coordinates
U QMP_comm_logical_topology_is_declared
0000000000000070 T QMP_comm_set_allocated
00000000000016f0 T QMP_comm_set_default
0000000000000150 T QMP_comm_set_job
U QMP_comm_split
0000000000000048 D QMP_default_comm
U QMP_error
00000000000001c0 T QMP_finalize_msg_passing
U QMP_get_allocated_dimensions
U QMP_get_allocated_number_of_dimensions
U QMP_get_msg_passing_type
0000000000001620 T QMP_init_msg_passing
0000000000000040 D QMP_job_comm
0000000000000008 D QMP_machine
0000000000000048 b QMP_machine_s
0000000000000080 B QMP_stack_level
U __svml_idiv4
0000000000000000 r __$U0
0000000000000017 r __$U1
000000000000002e r __$U2
000000000000003f r __$U3
0000000000000091 r __$U4
000000000000007c r __$U5
0000000000000050 r __$U6
000000000000005a r __$U7
0000000000000067 r __$U8
U _Unwind_Resume
0000000000000500 t _Z12process_argsPiPPPc
000000000000002c r _Z12process_argsPiPPPc$$LSDA
U _Z13QMP_abort_mpii
U _Z20QMP_init_machine_mpiPiPPPc16QMP_thread_levelPS3_
U _Z28QMP_finalize_msg_passing_mpiv
00000000000001e0 t _Z9get_colorv
0000000000000000 r _Z9get_colorv$$LSDA
Another stanza contains the function QMP_abort_mpi which supposedly cannot be found:
QMP_init_mpi.o:
U malloc
U MPI_Abort
U MPI_Comm_dup
U MPI_Comm_rank
U MPI_Comm_size
U MPI_Finalize
U MPI_Get_processor_name
U MPI_Init_thread
0000000000000010 T QMP_abort_mpi
U QMP_abort_string
U QMP_allocated_comm
0000000000000000 T QMP_finalize_msg_passing_mpi
0000000000000020 T QMP_init_machine_mpi
U QMP_machine
The relevant output of `configure is:
configure: Parscalar build! Checking for QMP
checking for qmp-config... ~/local-jureca/bin/qmp-config
configure: Found QMP configuration program ~/local-jureca/bin/qmp-config
configure: QMP compile flags: -I~/local-jureca/include
configure: QMP linking flags: -L~/local-jureca/lib
configure: QMP libraries flags: -lqmp
checking if we can compile/link of a simple QMP C++ program... no
configure: error: Cannot compile/link a basic QMP C++ program!
Check QMP_CFLAGS, QMP_LDFLAGS, QMP_LIBS.
So it seems to find the library just fine.
In the config.log a little larger chunk is this:
configure:4227: /usr/local/software/jureca/Stages/2016b/software/impi/2017.0.098-iccifort-2017.0.098-GCC-5.4.0/bin64/mpiicpc -o conftest -O2 -Wall -fopenmp --std=c++11 -I~/local-jureca/include -L~/local-jureca/lib conftest.cpp -lqmp >&5
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `QMP_comm_get_allocated':
QMP_init.c:(.text+0x55): undefined reference to `QMP_abort_mpi(int)'
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `QMP_comm_set_allocated':
QMP_init.c:(.text+0xc7): undefined reference to `QMP_abort_mpi(int)'
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `QMP_comm_get_job':
QMP_init.c:(.text+0x135): undefined reference to `QMP_abort_mpi(int)'
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `QMP_comm_set_job':
QMP_init.c:(.text+0x1a7): undefined reference to `QMP_abort_mpi(int)'
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `QMP_finalize_msg_passing':
QMP_init.c:(.text+0x1cf): undefined reference to `QMP_finalize_msg_passing_mpi()'
~/local-jureca/lib/libqmp.a(QMP_init.o): In function `get_color()':
QMP_init.c:(.text+0x29b): undefined reference to `QMP_abort_mpi(int)'
QMP_init.c:(.text+0x45c): undefined reference to `QMP_abort_mpi(int)'
QMP_init.c:(.text+0x4be): undefined reference to `QMP_abort_mpi(int)'
configure:4227: $? = 1
configure: failed program was:
| /* confdefs.h */
| #define PACKAGE_NAME "qdp++"
| #define PACKAGE_TARNAME "qdp--"
| #define PACKAGE_VERSION "1.44.0"
| #define PACKAGE_STRING "qdp++ 1.44.0"
| #define PACKAGE_BUGREPORT "edwards#jlab.org"
| #define PACKAGE_URL ""
| #define PACKAGE "qdp--"
| #define VERSION "1.44.0"
| #define QDP_ND 4
| #define QDP_NC 3
| #define QDP_NS 4
| #define QDP_AC_ALIGNMENT_SIZE 16
| #define QDP_USE_GENERIC_OPTS 1
| #define QDP_USE_BLUEGENEL 1
| #define BASE_PRECISION 64
| #define QDP_USE_CB2_LAYOUT 1
| #define ARCH_PARSCALAR 1
| /* end confdefs.h. */
| #include "qmp.h"
| int
| main ()
| {
|
| int argc ; char **argv ;
| QMP_thread_level_t prv;
| ;
| QMP_init_msg_passing(&argc, &argv, QMP_THREAD_SINGLE, &prv) ;
| ;
| QMP_finalize_msg_passing() ;
|
| ;
| return 0;
| }
configure:4253: checking if we can compile/link of a simple QMP C++ program
configure:4261: result: no
configure:4263: error: Cannot compile/link a basic QMP C++ program!
Check QMP_CFLAGS, QMP_LDFLAGS, QMP_LIBS.
I have replaced the absolute path to my home directory with ~ because the actual path is not interesting.
What happens here? And how can I go about fixing it?
Update 1
This is part of the make output for QMP. It seems to be compiled with mpiicc which is a C (not C++) compiler:
depbase=`echo mpi/QMP_topology_mpi.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
/usr/local/software/jureca/Stages/2016b/software/impi/2017.0.098-iccifort-2017.0.098-GCC-5.4.0/bin64/mpiicc -DHAVE_CONFIG_H -I. -I../include -I../include -O2 -Wall -fopenmp -MT mpi/QMP_topology_mpi.o -MD -MP -MF $depbase.Tpo -c -o mpi/QMP_topology_mpi.o mpi/QMP_topology_mpi.c &&\
mv -f $depbase.Tpo $depbase.Po
And then the static library is linked together from the various units:
rm -f libqmp.a
ar cru libqmp.a QMP_comm.o QMP_error.o QMP_grid.o QMP_init.o QMP_machine.o QMP_mem.o QMP_split.o QMP_topology.o QMP_util.o mpi/QMP_comm_mpi.o mpi/QMP_error_mpi.o mpi/QMP_init_mpi.o mpi/QMP_mem_mpi.o mpi/QMP_split_mpi.o mpi/QMP_topology_mpi.o