더 큰 애플리케이션 범위를 제공하기 위해 이전 버전의 libc에 대한 링크
Linux 바이너리는 일반적으로 코어 시스템 라이브러리 (libc)에 동적으로 연결됩니다. 이것은 바이너리의 메모리 풋 프린트를 아주 작게 유지하지만 최신 라이브러리에 의존하는 바이너리는 이전 시스템에서 실행되지 않습니다. 반대로 오래된 라이브러리에 연결된 바이너리는 최신 시스템에서 원활하게 실행됩니다.
따라서 배포 중에 응용 프로그램이 좋은 범위를 갖도록하려면 지원할 수있는 가장 오래된 libc를 파악하고 이에 대해 바이너리를 연결할 필요가 있습니다.
링크 할 수있는 가장 오래된 libc 버전을 어떻게 결정해야합니까?
실행 파일의 어떤 기호가 원하지 않는 glibc 버전에 대한 종속성을 생성하는지 확인하십시오.
$ objdump -p myprog
...
Version References:
required from libc.so.6:
0x09691972 0x00 05 GLIBC_2.3
0x09691a75 0x00 03 GLIBC_2.2.5
$ objdump -T myprog | fgrep GLIBC_2.3
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.3 realpath
종속 된 라이브러리 내에서 링크 할 수있는 이전 버전의 기호가 있는지 확인하십시오.
$ objdump -T /lib/libc.so.6 | grep -w realpath
0000000000105d90 g DF .text 0000000000000021 (GLIBC_2.2.5) realpath
000000000003e7b0 g DF .text 00000000000004bf GLIBC_2.3 realpath
우리는 운이 좋다!
GLIBC_2.2.5
코드에서 버전을 요청하십시오 .
#include <limits.h>
#include <stdlib.h>
__asm__(".symver realpath,realpath@GLIBC_2.2.5");
int main () {
realpath ("foo", "bar");
}
GLIBC_2.3이 더 이상 필요하지 않음을 확인하십시오.
$ objdump -p myprog
...
Version References:
required from libc.so.6:
0x09691a75 0x00 02 GLIBC_2.2.5
$ objdump -T myprog | grep realpath
0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 realpath
자세한 내용은 http://web.archive.org/web/20160107032111/http://www.trevorpounds.com/blog/?p=103을 참조 하십시오 .
불행히도 @Sam의 솔루션은 내 상황에서 잘 작동하지 않습니다. 그러나 그의 방식에 따라 나는 그것을 해결할 방법을 찾았습니다.
이것은 내 상황입니다.
Thrift 프레임 워크 (RPC 미들웨어)를 사용하여 C ++ 프로그램을 작성하고 있습니다. 내 프로그램이 연결되어, 그래서 나는, 동적 링크 정적 링크를 선호 libthrift.a 의 정적 대신 libthrift.so . 그러나 libthrift.a 는 glibc에 동적으로 연결되어 있으며 내 libthrift.a 는 glibc 2.15가 설치된 시스템에 빌드 되었으므로 libthrift.a 는 glibc 2.15에서 제공하는 버전 2.14 ( memcpy@GLIBC_2.14 )의 memcpy 를 사용합니다 .
그러나 문제는 우리의 서버 시스템에 memcpy@GLIBC_2.2.5 만있는 glibc 버전 2.5 만 있다는 것 입니다. memcpy@GLIBC_2.14 보다 훨씬 낮습니다 . 물론 내 서버 프로그램은 해당 컴퓨터에서 실행할 수 없습니다.
그리고 나는 다음과 같은 해결책을 찾았습니다.
.symver를 사용하여 memcpy@GLIBC_2.2.5에 대한 참조를 얻습니다 .
memcpy@GLIBC_2.2.5를 직접 호출하는 내 자신의 __wrap_memcpy 함수를 작성하십시오 .
내 프로그램을 연결할 때 gcc / g ++ 에 -Wl,-wrap = memcpy 옵션을 추가 합니다.
1 단계와 2 단계에 관련된 코드는 다음과 같습니다. https://gist.github.com/nicky-zs/7541169
To do this in a more automated fashion, you can use the following script to create a list of all the symbols that are newer in your GLIBC than in a given version (set on line 2). It creates a glibc.h
file (filename set by the script argument) which contains all the necessary .symver
declarations. You can then add -include glibc.h
to your CFLAGS to make sure it gets picked up everywhere in your compilation.
This is sufficient if you don't use any static libraries that were compiled without the above include. If you do, and you don't want to recompile, you can use objcopy
to create a copy of the library with the symbols renamed to the old versions. The second to bottom line of the script creates a version of your system libstdc++.a
that will link against the old glibc symbols. Adding -L.
(or -Lpath/to/libstdc++.a/
) will make your program statically link libstdc++ without linking in a bunch of new symbols. If you don't need this, delete the last two lines and the printf ... redeff
line.
#!/bin/bash
maxver=2.9
headerf=${1:-glibc.h}
set -e
for lib in libc.so.6 libm.so.6 libpthread.so.0 libdl.so.2 libresolv.so.2 librt.so.1; do
objdump -T /usr/lib/$lib
done | awk -v maxver=${maxver} -vheaderf=${headerf} -vredeff=${headerf}.redef -f <(cat <<'EOF'
BEGIN {
split(maxver, ver, /\./)
limit_ver = ver[1] * 10000 + ver[2]*100 + ver[3]
}
/GLIBC_/ {
gsub(/\(|\)/, "",$(NF-1))
split($(NF-1), ver, /GLIBC_|\./)
vers = ver[2] * 10000 + ver[3]*100 + ver[4]
if (vers > 0) {
if (symvertext[$(NF)] != $(NF-1))
count[$(NF)]++
if (vers <= limit_ver && vers > symvers[$(NF)]) {
symvers[$(NF)] = vers
symvertext[$(NF)] = $(NF-1)
}
}
}
END {
for (s in symvers) {
if (count[s] > 1) {
printf("__asm__(\".symver %s,%s@%s\");\n", s, s, symvertext[s]) > headerf
printf("%s %s@%s\n", s, s, symvertext[s]) > redeff
}
}
}
EOF
)
sort ${headerf} -o ${headerf}
objcopy --redefine-syms=${headerf}.redef /usr/lib/libstdc++.a libstdc++.a
rm ${headerf}.redef
glibc 2.2 is a pretty common minimum version. However finding a build platform for that version may be non-trivial.
Probably a better direction is to think about the oldest OS you want to support and build on that.
'Program Tip' 카테고리의 다른 글
Grep 및 Python (0) | 2020.11.21 |
---|---|
파이썬 : 두 단어로 된 이름을 가진 모듈 이름 지정 (0) | 2020.11.21 |
동일한 열에서 여러 WHERE 조건으로 선택 (0) | 2020.11.21 |
javascript / html5로 즉석에서 사운드 생성 (0) | 2020.11.21 |
필드 대 속성. (0) | 2020.11.21 |