Ami*_*ram 21 c glibc ld static-linking
我已经构建了glibc 2.14并将其安装在目录中~/GLIBC/glibc_install.现在我想使用这个C库而不是系统的默认C库来构建和运行程序.
为了确保我使用的是自定义glibc,我添加了一个put glibc/stdio-common/printf.c:__printf来打印消息的调用.
然后我重建并重新安装了glibc.
然后我写了一个"Hello,World"程序并尝试编译并链接如下:
gcc -nodefaultlibs -static -lgcc -L~/GLIBC/glibc_install/lib -o myprog myprog.c
Run Code Online (Sandbox Code Playgroud)但是我得到以下链接器错误报告:
/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crt1.o: In function `_start':
(.text+0x19): undefined reference to `__libc_csu_init'
/usr/lib/gcc/x86_64-linux-gnu/4.4.3/../../../../lib/crt1.o: In function `_start':
(.text+0x25): undefined reference to `__libc_start_main'
/tmp/ccACTQEp.o: In function `main':
c1.c:(.text+0xa): undefined reference to `puts'
collect2: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
Ami*_*ram 21
根据glibc帮助邮件列表(libc-help@sourceware.org)的一些建议,我有一个解决方案.事实证明,这个任务是有点棘手,因为你必须告诉链接省略一切它通常会自动(默默)包括,然后回包括它需要,包括一堆开始和结束文件的一切.一些开始和结束文件来自libc,一些来自gcc,因此make规则有点复杂.下面是一个通用示例makefile来说明该方法.我将假设您正在从名为prog.c的源文件构建一个名为prog的程序,并且已在目录/ home/my_acct/glibc_install中安装了自定义glibc .
TARGET = prog
OBJ = $(TARGET).o
SRC = $(TARGET).c
CC = gcc
CFLAGS = -g
LDFLAGS = -nostdlib -nostartfiles -static
GLIBCDIR = /home/my_acct/glibc_install/lib
STARTFILES = $(GLIBCDIR)/crt1.o $(GLIBCDIR)/crti.o `gcc --print-file-name=crtbegin.o`
ENDFILES = `gcc --print-file-name=crtend.o` $(GLIBCDIR)/crtn.o
LIBGROUP = -Wl,--start-group $(GLIBCDIR)/libc.a -lgcc -lgcc_eh -Wl,--end-group
$(TARGET): $(OBJ)
$(CC) $(LDFLAGS) -o $@ $(STARTFILES) $^ $(LIBGROUP) $(ENDFILES)
$(OBJ): $(SRC)
$(CC) $(CFLAGS) -c $^
clean:
rm -f *.o *.~ $(TARGET)
Run Code Online (Sandbox Code Playgroud)
你的命令行只是假的.尝试:
gcc -nodefaultlibs -static -L~/GLIBC/glibc_install/lib -o myprog myprog.c -lgcc -lc -lgcc -lc
Run Code Online (Sandbox Code Playgroud)
或类似的.您省略了-lc,并且在输入文件之前错误地拥有了库.
而你正在寻找一个名为libibgcc而不是libgcc... 的图书馆
Without static also working at: Multiple glibc libraries on a single host
This setup might work and is quick as it does not recompile the whole GCC toolchain, just glibc.
But it is not reliable as it uses host C runtime objects such as crt1.o, crti.o, and crtn.o provided by glibc. This is mentioned at: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Those objects do early setup that glibc relies on, so I wouldn't be surprised if things crashed in wonderful and awesomely subtle ways.
For a more reliable setup, see Setup 2 below.
Build glibc and install locally:
export glibc_install="$(pwd)/glibc/build/install"
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`
Run Code Online (Sandbox Code Playgroud)
test_glibc.c
#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int acnt;
int cnt;
int f(void* thr_data) {
for(int n = 0; n < 1000; ++n) {
++cnt;
++acnt;
}
return 0;
}
int main(int argc, char **argv) {
/* Basic library version check. */
printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());
/* Exercise thrd_create from -pthread,
* which is not present in glibc 2.27 in Ubuntu 18.04.
* /sf/ask/3976731/#52453291 */
thrd_t thr[10];
for(int n = 0; n < 10; ++n)
thrd_create(&thr[n], f, NULL);
for(int n = 0; n < 10; ++n)
thrd_join(thr[n], NULL);
printf("The atomic counter is %u\n", acnt);
printf("The non-atomic counter is %u\n", cnt);
}
Run Code Online (Sandbox Code Playgroud)
Compile and run with test_glibc.sh:
#!/usr/bin/env bash
set -eux
rm -rf tmp
mkdir tmp
gcc \
-L "${glibc_install}/lib" \
-I "${glibc_install}/include" \
-Wl,--rpath="${glibc_install}/lib" \
-Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
-static \
-std=c11 \
-o tmp/test_glibc.out \
-v \
test_glibc.c \
-pthread \
;
sudo chroot tmp /test_glibc.out
Run Code Online (Sandbox Code Playgroud)
The program outputs the expected:
gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674
Run Code Online (Sandbox Code Playgroud)
even though we ran it on a clean chroot, so the -static must have worked.
Command adapted from https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location but --sysroot made it fail with:
cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install
Run Code Online (Sandbox Code Playgroud)
so I removed it.
ldd output confirms that the ldd and libraries that we've just built are actually being used as expected:
+ ldd test_glibc.out
linux-vdso.so.1 (0x00007ffe4bfd3000)
libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)
Run Code Online (Sandbox Code Playgroud)
The gcc compilation debug output shows that my host runtime objects were used, which is bad as mentioned previously, but I don't know how to work around it, e.g. it contains:
COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o
Run Code Online (Sandbox Code Playgroud)
Now let's modify glibc with:
diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <stdio.h>
+
#include "thrd_priv.h"
int
thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
{
+ puts("hacked");
_Static_assert (sizeof (thr) == sizeof (pthread_t),
"sizeof (thr) != sizeof (pthread_t)");
Run Code Online (Sandbox Code Playgroud)
Then recompile and re-install glibc, and recompile and re-run our program:
cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh
Run Code Online (Sandbox Code Playgroud)
and we see hacked printed a few times as expected.
This further confirms that we actually used the glibc that we compiled and not the host one.
Tested on Ubuntu 18.04.
This is an alternative to setup 1, and it is the most correct setup I've achieved far: everything is correct as far as I can observe, including the C runtime objects such as crt1.o, crti.o, and crtn.o.
In this setup, we will compile a full dedicated GCC toolchain that uses the glibc that we want.
The only downside to this method is that the build will take longer. But I wouldn't risk a production setup with anything less.
crosstool-NG is a set of scripts that downloads and compiles everything from source for us, including GCC, glibc and binutils.
Yes the GCC build system is so bad that we need a separate project for that.
This setup is only not perfect because crosstool-NG does not support building the executables without extra -Wl flags, which feels weird since we've built GCC itself. But everything seems to work, so this is only an inconvenience.
Get crosstool-NG and configure it:
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig
Run Code Online (Sandbox Code Playgroud)
The only mandatory option that I can see, is making it match your host kernel version to use the correct kernel headers. Find your host kernel version with:
uname -a
Run Code Online (Sandbox Code Playgroud)
which shows me:
4.15.0-34-generic
Run Code Online (Sandbox Code Playgroud)
so in menuconfig I do:
Operating System
Version of linuxso I select:
4.14.71
Run Code Online (Sandbox Code Playgroud)
which is the first equal or older version. It has to be older since the kernel is backwards compatible.
Now you can build with:
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
Run Code Online (Sandbox Code Playgroud)
and now wait for about thirty minutes to two hours for compilation.
The .config that we generated with ./ct-ng x86_64-unknown-linux-gnu has:
CT_GLIBC_V_2_27=y
Run Code Online (Sandbox Code Playgroud)
To change that, in menuconfig do:
C-libraryVersion of glibcsave the .config, and continue with the build.
Or, if you want to use your own glibc source, e.g. to use glibc from the latest git, proceed like this:
Paths and misc options
Try features marked as EXPERIMENTAL: set to trueC-library
Source of glibc
Custom location: say yesCustom location
Custom source location: point to a directory containing your glibc sourcewhere glibc was cloned as:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
Run Code Online (Sandbox Code Playgroud)
Once you have built he toolchain that you want, test it out with:
#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
rm -rf tmp
mkdir tmp
PATH="${PATH}:${install_dir}/bin" \
x86_64-unknown-linux-gnu-gcc \
-Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
-Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
-static \
-v \
-o tmp/test_glibc.out \
test_glibc.c \
-pthread \
;
sudo chroot tmp /test_glibc.out
Run Code Online (Sandbox Code Playgroud)
Everything seems to work as in Setup 1, except that now the correct runtime objects were used:
COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o
Run Code Online (Sandbox Code Playgroud)
It does not seem possible with crosstool-NG, as explained below.
If you just re-build;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
Run Code Online (Sandbox Code Playgroud)
then your changes to the custom glibc source location are taken into account, but it builds everything from scratch, making it unusable for iterative development.
If we do:
./ct-ng list-steps
Run Code Online (Sandbox Code Playgroud)
it gives a nice overview of the build steps:
Available build steps, in order:
- companion_tools_for_build
- companion_libs_for_build
- binutils_for_build
- companion_tools_for_host
- companion_libs_for_host
- binutils_for_host
- cc_core_pass_1
- kernel_headers
- libc_start_files
- cc_core_pass_2
- libc
- cc_for_build
- cc_for_host
- libc_post_cc
- companion_libs_for_target
- binutils_for_target
- debug
- test_suite
- finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.
Run Code Online (Sandbox Code Playgroud)
therefore, we see that there are glibc steps intertwined with several GCC steps, most notably libc_start_files comes before cc_core_pass_2, which is likely the most expensive step together with cc_core_pass_1.
In order to build just one step, you must first set the "Save intermediate steps" in .config option for the intial build:
Paths and misc options
Debug crosstool-NG
Save intermediate stepsand then you can try:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
Run Code Online (Sandbox Code Playgroud)
but unfortunately, the + required as mentioned at: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Note however that restarting at an intermediate step resets the installation directory to the state it had during that step. I.e., you will have a rebuilt libc - but no final compiler built with this libc (and hence, no compiler libraries like libstdc++ either).
并且基本上仍然使重建太慢而无法进行开发,而且我不知道如何在不修补 crosstool-NG 的情况下克服这个问题。
此外,从该libc步骤开始似乎没有再次从 复制源Custom source location,进一步使此方法无法使用。
如果您也对 C++ 标准库感兴趣,还有一个好处:如何编辑和重新构建 GCC libstdc++ C++ 标准库源代码?