2013-07-29 8 views
2

리눅스 관련 경험이 많지 않아서 제 질문에 정확하지 않은 점 사과드립니다. 나는 현재 스크래치 (주로 linuxfromscratch.org 버전 7.3의 가이드를 따르는)에서 리눅스를 만들고있다. 다음과 같은 문제가 발생했습니다 : 실행 파일을 빌드 할 때 은 ELF 인터프리터라는 하드 코딩 된 경로를 가져옵니다.elf 인터프리터 (ld-linux.so.2/ld-2.17.so)를 정적 라이브러리로 빌드하는 방법은 무엇입니까?

readelf -l program 

[Requesting program interpreter: /lib/ld-linux.so.2] 

같은 내가 glibc는의 일부가이 라이브러리 LD-리눅스 so.2을 추적 보여줍니다. 이진이 매우 이식성을 잃어 버리기 때문에이 동작에 만족하지 않습니다. - 실행 파일 /lib/ld-linux.so.2의 위치를 ​​변경하면 더 이상 작동하지 않으며 길이가 더 길고 발견 된 유일한 "수정"은 다음과 같습니다. Ncalc의 patchelf 유틸리티 을 사용하여 하드 코드 된 경로를 다른 하드 코드 된 경로로 변경하십시오. 의 경우이 이유는 ld 라이브러리의 정적 버전과 연결하고 싶지만 그러한 것은 생성되지 않습니다. 그리고 이것은 제 질문입니다. 당신은 어떻게하면 정적 버전의 ld-linux.so.2를 생성 할 수 있도록 glibc를 빌드 할 수 있었는지 설명 할 수 있었고 나중에 실행 파일에 링크 할 수있었습니다. 나는이 라이브러리가 무엇을하는지 완전히 이해하지 못한다. 그러나 은 다른 동적 라이브러리 (또는 에서 적어도 glibc.so)를로드하는 부분이라고 가정한다. 내 실행 파일을 동적으로 링크하고 싶습니다. 그러나 동적 인 링커 자체를 에 정적으로 내장하고 싶습니다. 따라서 하드 코드 된 경로에 의존하지 않을 것입니다. 또는 은 환경 변수가 LD_LIBRARY_PATH와 비슷하거나 아마도 LD_INTERPRETER_PATH 인 인터프리터 경로를 설정할 수 있기를 원합니다. 목표는 디렉토리 구조가 무엇이든 관계없이 동일한 ABI가있는 플랫폼에서 실행할 수있는 이식 가능한 바이너리를 생성 할 수있게하는 것입니다.

관련성이있는 몇 가지 배경 : Slackware 14 x86에서 i686 컴파일러 툴체인을 빌드하므로 전반적으로 모든 x86 호스트와 대상이됩니다. glibc 2.17과 gcc 4.7.x를 사용하고 있습니다.

+0

저는 ELF 프로그램 인터프리터를 바꾸는 것이 나쁜 생각이라고 생각합니다 (Linux & binutils 전문가가 아닌 이상). 그것은 Glibc로 만들어졌습니다. 다른 것을 시도해 볼 수 있습니다 (예 : [MUSL-Libc] (http://musl-libc.org) ...). 왜 그것을 바꾸고 싶습니까? 어떤 동적 로더에 ?? 그 위치와 존재 (나쁜 생각)에 의존하기를 원하지 않는다면 동적 링크를 포기하고 정적으로 링크 된 프로그램 만 갖도록하십시오. 그리고 동적 링커'/ lib/ld-linux.so.2'는 정적으로 만들어졌지만 (여전히 공유 라이브러리이며, VDSO를 제공하는 커널을 제외한 외부 라이브러리를 사용하지 않습니다). –

+0

동적 연결은 정적 위치에 의존하지 않고 동적이어야합니다. 이 [hardwired] 방식은 완전히 잘못되었습니다. 나는 그것을 내 시스템에서 고치고 싶다. 그리고 그 해결책은 쉽습니다. 나는 그것을 스스로 해결할 수있는 모든면에 익숙하지 않았습니다. – bobef

+0

그런 다음 필요에 맞게 커널을 패치하십시오. 그런 다음 도구 체인 (컴파일러 및 링커)에 패치를 적용해야합니다. 사실,이 모든 것은 자유 소프트웨어이고 당신은 그것을 향상시킬 수 있습니다. –

답변

10

LD_LIBRARY_PATH와 비슷한 환경 변수 (아마도 LD_INTERPRETER_PATH)로 인터프리터 경로를 설정하고 싶습니다.

이것은 단순히 불가능합니다. execve(2), elf(5) & ld.so(8) 매뉴얼 페이지 및 Linux ABI & ELF 사양을주의 깊게 (그리고 여러 번) 읽으십시오. 또한 커널 코드는 execve입니다.

ELF 해석기는 동적 연결을 담당합니다. 그것은 1990 년대에서 오래 a.out 형식이 내장 동적 링커를했다

파일 계층 (종종 /lib/ld.so.2 또는 /lib/ld-linux.so.2 또는 /lib64/ld-linux-x86-64.so.2)의 일부 고정 위치에 파일 (기술적으로 정적으로 링크 된 ELF 공유 라이브러리)이어야한다 오래된 리눅스 1.x 커널에서 부분적으로 구현되었다. 그것은 훨씬 덜 유연하고 훨씬 덜 강력했습니다.

커널은 그러한 (원칙적으로) 임의의 동적 링커 경로가 다양한 동적 링커를 가질 수있게합니다. 그러나 대부분의 시스템에는 하나만 있습니다. 동적 링커를 매개 변수화하는 좋은 방법입니다. 다른 파일을 시험해 보려면 파일 시스템에 설치하고 해당 경로를 언급하는 ELF 실행 파일을 생성하십시오. 큰 고통과 노력으로

, 당신은 당신의 자신의 ld.so -like 동적 링커가 당신의 LD_INTERPRETER_PATH 소원을 구현하지만, 링커는 여전히 ELF 공유 라이브러리 파일 트리의 일부 고정 위치에 앉아 있어야한다 만들 수 있습니다.

당신이 시스템이 (/lib/ld.so, /dev/null, /sbin/init ... 같은 몇 가지 미리 정의에서, 유선 위치) 파일을 필요로하지 않는 싶은 경우에, 당신은 정적으로 모든 실행 가능한 바이너리를 구축해야합니다. 동적 인 링커가없는 시점에서 시스템을 복구 할 수있게 해주는 몇 가지 정적 링크 된 실행 파일 (예 : /sbin/init, /bin/sash ...)을 사용하기를 원할 수 있습니다 (현재의 Linux 배포판에서는 그렇지 않습니다). BTW

상기 /sbin/init -OR /bin/sh - 경로 커널 자체 내부 유선된다. 부트로드시에 커널에 인수를 전달할 수 있습니다 (예 : -e.g). GRUB을 사용하여 기본값을 덮어 씁니다. 그래서 커널조차도 여기에있는 파일을 원합니다!

내가 설명했듯이 MUSL-Libc을 보면 (자체 동적 링커를 제공하는) 대체 Libc 구현을 볼 수 있습니다. VDSOASLRinitrd도 읽으십시오.

사실 현대 리눅스와 유닉스가 비어 있지 않은 파일 시스템을 기대하고 있다는 사실을 받아 들인다 ... 동적 링크와 공유 라이브러리가 커다란 진전을 보았다. (1990 년대 리눅스 커널과 배포판에서는 훨씬 더 고통 스러웠다.).

또는 자신 만의 이진 형식을 정의한 다음 커널 모듈 또는 binfmt_misc 항목을 처리하십시오.

현재 대부분의 (또는 전체) Linux는 free software이므로 개선 할 수 있습니다 (단, 몇 달 또는 몇 년이 걸릴 수 있습니다). 게시하여 개선 사항을 공유하십시오.

도 읽으십시오. Drepper's Hwo to Write Shared Libraries 용지; 및 this question.

+0

내 바이너리 형식을 정의하는 것이 이식성이 없어 보인다. 이 모든 작업을 수행하는 대신 하드 코딩 된 위치 (및 가능하면 이름)를 무시하고이 API를 사용자 프로그램에 노출시킬 수있는 커널의 일부 API를 노출 할 수 있습니다.이 API는 단순히 프로그램을 호출하여 위치를 구성 할 수 있습니다. 쉘 ... LD_INTERPRETER_PATH를 설정하는 것과 매우 비슷하지만 사용자 공간 프로그램이 루트 나 그와 비슷한 것으로 제한 될 수 있기 때문에 더 좋습니다. 모든 것을 정적으로 만들거나 모든 것을 다시 쓸 필요가 없습니다. – bobef

+0

즐거운 시간을 보내십시오. 아마도 ELF가 사용할 수있는 모든 복잡함을 (전체적으로) 사용하는 수천 개의 Linux 프로그램을 구축 할 때 예기치 않은 문제가 발생할 수 있습니다. –

0

같은 문제가 발생했습니다. 제 경우에는 설치된 시스템보다 다른 GLIBC를 사용하여 응용 프로그램을 묶고 싶습니다. ld-linux.so는 GLIBC 버전과 일치해야하기 때문에 단순히 GLIBC와 함께 응용 프로그램을 배포 할 수 없습니다. 문제는 필요한 GLIBC 버전이없는 이전 설치에서 응용 프로그램을 실행할 수 없다는 것입니다.

로더 인터프리터의 경로는 --dynamic-linker =/path/to/interp로 수정할 수 있습니다. 그러나 이것은 컴파일 시간에 설정해야하므로 내 응용 프로그램을 해당 위치에 설치해야합니다 (또는 최소한 GLIBC와 함께 사용하는 ld-linux.so를 배포해야합니다.

그래서 필요한 것은 -rpath 옵션에서 처리 할 수있는 것과 동일한 $ ORIGIN 옵션으로 완전히 동적으로 배포 할 수 있습니다.실행 파일이 실행되기 전에

가) 경로를 수정 patchelf를 사용

동적 인터프리터 경로의 부족을 감안할 때 (런타임에) 두 가지 옵션을 떠난다. b) ld-linux.so를 실행 파일과 함께 직접 호출하십시오.

두 옵션 모두 실행 파일 자체에서 컴파일 된 $ ORIGIN 경로로 '통합'되어 있지 않습니다.