First, some background info about elf32-x86-64 format.
It is a format that leverages 64-bit hardware while enforcing 32-bit pointers. Ref1 and Ref2.
Question
I am trying to link the Google Test framework binaries to my project.
I use objdump -f
to check the format of Google Test binaries and my binaries.
Google Test format is elf64-x86-64
. Mine elf32-x86-64
. So they cannot be linked together.
Then I add below content to the google test's internal_utils.cmake file:
set(ZEPHYR_LINK_FLAGS "-Wl,--oformat=elf32-x86-64")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ZEPHYR_LINK_FLAGS}")
I hope the linker flag can change the output format to elf32-x86-64
.
But google test build failed with below error:
/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so: error adding symbols: File in wrong format
The /usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so
is also a elf64-x86-64
format.
And I checked the generated object file, such as:
./googletest/CMakeFiles/gtest_main.dir/src/gtest_main.cc.o
It is still elf64-x86-64
.
So it seems the linker flag doesn't affect the object file format.
I remember the linker ld
will choose the output format based on its first encountered object file. So I guess I need to tell the compiler to output a elf32-x86-64
format.
How can I ask the compiler to output a elf32-x86-64
object file?
ADD 1 - 3:29 PM 11/1/2019
I have managed to compile the Google Test as elf32-x86-64
with below tuning:
- Add compile flag
-mx32
- And add link flag
-Wl,--oformat=elf32-x86-64
Now the output binaries libgtest.a
, libgtest_main.a
are elf32-x86-64
. But they need to be linked to libstdc++.so
. So far, it is elf64-x86-64
on my system. And I haven't found a elf32-x86-64
one. Thus below error:
/usr/lib/gcc/x86_64-linux-gnu/7/libstdc++.so: error adding symbols: File in wrong format
ADD 2 - 3:47 PM 11/1/2019
After installing sudo apt-get install gcc-multilib g++-multilib
(ref), I got a elf32-x86-64
version of libstdc++.so
at below location:
/usr/lib/gcc/x86_64-linux-gnu/7/x32/libstdc++.so
And it ultimately points to /usr/libx32/libstdc++.so.6.0.25
Now it seems I just need to find a way to tell the linker to use it... So close!
ADD 3 - 2:44 PM 11/4/2019
Thanks to Florian and EmployedRussian, I change Google Test's internal_utils.cmake
file to add below 4 lines:
set(MY_COMPILE_FLAGS "-mx32")
set(cxx_base_flags "${cxx_base_flags} ${MY_COMPILE_FLAGS}")
set(MY_LINK_FLAGS "-mx32")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MY_LINK_FLAGS}")
Now the generated executable are elf32_x86-64
format.
So basically, I add the -mx32
to both compile and link flags.
And in the generated rules.ninja
file, the link rule goes like this:
command = $PRE_LINK && /usr/bin/c++ $FLAGS $LINK_FLAGS $in -o $TARGET_FILE $LINK_PATH $LINK_LIBRARIES && $POST_BUILD
The $FLAGS
and $LINK_FLAGS
are defined in the build.ninja
file as below:
FLAGS = -Wall -Wshadow -Werror -mx32 ...
LINK_FLAGS = -mx32 ...
So essentially, there are 2 -mx32
options in the ninja command definition contributed by the $FLAGS $LINK_FLAGS
respectively.
So why do I need to specify the -mx32
for twice??
And I don't understand why I can specify -mx32
for CMAKE_EXE_LINKER_FLAGS
.
First, -mx32
is only a compile option (ref), not a linker option.
Second, from the link rule definition, the $LINK_FLAGS
are passed to usr/bin/c++
without a -Wl,
prefix, so even the option can be appreciated by the linker, it won't be passed to the linker.
export LDFLAGS='-m32 -L/usr/lib32'
– Lindgren