레거시 gcc 컴파일러 문제
-
13-09-2019 - |
문제
우리는 여전히 사용하고 있는 오래된 내장 프로세서에 대한 크로스 컴파일을 위해 gcc 2.6.0 기반의 레거시 컴파일러를 사용하고 있습니다(예, 1994년부터 계속 사용 중입니다!).이 칩에 대한 gcc 포트를 수행한 엔지니어는 오래 전에 다른 곳으로 이동했습니다.웹 어딘가에서 GCC 2.6.0 소스를 복구 할 수는 있지만이 칩의 변경 사항은 기업 역사 홀에서 사라졌습니다.최근까지 컴파일러가 계속 실행되고 실행 가능한 실행 파일을 생성하면서 혼란을 겪었지만 Linux 커널 2.6.25(및 2.6.26)에서는 다음 메시지와 함께 실패합니다. gcc: virtual memory exhausted
...매개변수 없이 또는 매개변수만 사용하여 실행하는 경우에도 -v
.2.6.24 커널을 사용하여 개발 시스템(2.6.26부터)을 재부팅했는데 컴파일러가 다시 작동합니다(2.6.25로 재부팅하면 작동하지 않음).
우리는 단지 이 칩을 빌드하기 위한 목적으로 2.6.24에 유지하고 있는 하나의 시스템을 가지고 있지만 Linux 세계가 더 이상 실행될 시스템을 재구축할 수 없는 지점으로 이동하는 경우 약간 노출되는 느낌이 듭니다. 컴파일러(예:2.6.24 시스템이 종료되고 일부 소프트웨어 부분을 더 이상 사용할 수 없기 때문에 2.6.24를 새 시스템에 설치하고 실행할 수 없습니다.
이 레거시 컴파일러를 실행하기 위해 보다 현대적인 설치로 무엇을 할 수 있는지에 대한 아이디어가 있는 사람이 있습니까?
편집하다:
일부 댓글에 답변을 드리자면...
안타깝게도 손실된 것은 우리 칩과 관련된 소스 코드 변경 사항입니다.이러한 손실은 두 개의 주요 회사 조직 개편과 여러 시스템 관리자(그 중 두 개는 실제로 혼란을 야기함)로 인해 발생했습니다.이제 구성 제어를 사용하지만 이 문제에 비해 헛간 문이 너무 늦게 닫힙니다.
VM을 사용하는 것은 좋은 생각이며 결국 우리가 할 일이 될 수도 있습니다.그 아이디어에 감사드립니다.
마지막으로, 나는 임시 제안대로 strace를 시도했고 마지막 시스템 호출이 새 시스템(2.6.26 커널)에서는 오류를 반환하고 이전 시스템(2.6.24 커널)에서는 성공을 반환한 brk()라는 것을 발견했습니다.이는 tcsh "limit"가 이전 시스템과 새 시스템에서 동일한 값을 반환하고 /proc/meminfo에서 새 시스템이 약간 더 많은 메모리와 상당히 더 많은 스왑 공간을 가지고 있음을 보여주는 점을 제외하면 실제로 가상 메모리가 부족하다는 것을 나타냅니다.어쩌면 조각화 문제이거나 프로그램이 로드되는 위치 때문일까요?
좀 더 자세히 조사한 결과 "brk 무작위화"가 커널 2.6.25에 추가되었습니다. CONFIG_COMPAT_BRK
기본적으로 활성화되어 있는 것으로 추정됩니다(brk 무작위화가 비활성화됨).
편집하다:
알겠습니다. 추가 정보:brk 무작위화가 범인인 것처럼 보입니다. 레거시 gcc는 데이터 세그먼트의 끝을 변경하기 위해 brk()를 호출하고 있으며 이제 실패하여 레거시 gcc가 "가상 메모리 소진"을 보고하게 됩니다.brk 무작위화를 비활성화하는 몇 가지 문서화된 방법이 있습니다:
sudo echo 0 > /proc/sys/kernel/randomize_va_space
sudo sysctl -w kernel.randomize_va_space=0
새로운 쉘 시작하기
setarch i386 -R tcsh
(또는 "-R -L")
나는 그것들을 시도했고 brk() 반환 값이 그것들 없이(커널 2.6.25와 2.6.26 모두에서 시도됨) 것과 다르고(항상 동일하다는 점에서) 효과가 있는 것 같습니다. 그러나 brk() 여전히 실패하므로 레거시 gcc도 여전히 실패합니다. :-(.
게다가 나는 설정했다 vm.legacy_va_layout=1
그리고 vm.overcommit_memory=2
변경사항 없이 재부팅했습니다. vm.legacy_va_layout=1
그리고 kernel.randomize_va_space=0
설정은 /etc/sysctl.conf에 저장됩니다.여전히 변화가 없습니다.
편집하다:
사용 kernel.randomize_va_space=0
커널 2.6.26(및 2.6.25)에서 다음 brk() 호출이 보고됩니다. strace legacy-gcc
:
brk(0x80556d4) = 0x8056000
이는 brk()가 실패했음을 나타내지만 데이터 세그먼트가 이미 요청한 것 이상으로 끝나기 때문에 실패한 것처럼 보입니다.objdump를 사용하면 데이터 세그먼트가 0x805518c에서 끝나야 하는 것을 볼 수 있지만 실패한 brk()는 데이터 세그먼트가 현재 0x8056000에서 끝나는 것을 나타냅니다.
Sections: Idx Name Size VMA LMA File off Algn 0 .interp 00000013 080480d4 080480d4 000000d4 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 1 .hash 000001a0 080480e8 080480e8 000000e8 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .dynsym 00000410 08048288 08048288 00000288 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 3 .dynstr 0000020e 08048698 08048698 00000698 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .rel.bss 00000038 080488a8 080488a8 000008a8 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 5 .rel.plt 00000158 080488e0 080488e0 000008e0 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 6 .init 00000008 08048a40 08048a40 00000a40 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 7 .plt 000002c0 08048a48 08048a48 00000a48 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 8 .text 000086cc 08048d10 08048d10 00000d10 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 9 .fini 00000008 080513e0 080513e0 000093e0 2**4 CONTENTS, ALLOC, LOAD, READONLY, CODE 10 .rodata 000027d0 080513e8 080513e8 000093e8 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 11 .data 000005d4 08054bb8 08054bb8 0000bbb8 2**2 CONTENTS, ALLOC, LOAD, DATA 12 .ctors 00000008 0805518c 0805518c 0000c18c 2**2 CONTENTS, ALLOC, LOAD, DATA 13 .dtors 00000008 08055194 08055194 0000c194 2**2 CONTENTS, ALLOC, LOAD, DATA 14 .got 000000b8 0805519c 0805519c 0000c19c 2**2 CONTENTS, ALLOC, LOAD, DATA 15 .dynamic 00000088 08055254 08055254 0000c254 2**2 CONTENTS, ALLOC, LOAD, DATA 16 .bss 000003b8 080552dc 080552dc 0000c2dc 2**3 ALLOC 17 .note 00000064 00000000 00000000 0000c2dc 2**0 CONTENTS, READONLY 18 .comment 00000062 00000000 00000000 0000c340 2**0 CONTENTS, READONLY SYMBOL TABLE: no symbols
편집하다:
아래에 ephemient의 의견을 반영하려면 다음을 수행하십시오."GCC를 소스 없는 바이너리로 취급하는 것은 정말 이상합니다!"
따라서 strace, objdump, gdb와 386 어셈블러 및 아키텍처에 대한 제한된 이해를 사용하여 레거시 코드의 첫 번째 malloc 호출에서 문제를 추적했습니다.레거시 gcc는 NULL을 반환하는 malloc을 호출하여 stderr에 "가상 메모리 소진" 메시지가 표시됩니다.이 malloc은 libc.so.5에 있으며, getenv를 여러 번 부르고 brk ()에게 전화하게됩니다.힙을 늘리는거 같은데...실패합니다.
이것으로부터 나는 문제가 brk 무작위화 이상의 것이라고 추측할 수 있습니다. 또는 randomize_va_space=0 및 Legacy_va_layout=1 sysctl 설정에도 불구하고 brk 무작위화를 완전히 비활성화하지 않았습니다.
해결책
Linux + 기존 GCC를 가상 시스템에 설치하십시오.
다른 팁
당신은 있습니다 출처 이 사용자 지정 컴파일러를 위해? 2.6.0 기준선을 복구 할 수 있다면 (그리고 비교적 쉬워야 함) Diff와 Patch는 변경 세트를 복구해야합니다.
그런 다음 권장하는 것은 해당 변경 세트를 사용하여 최신 GCC에 대해 새 버전을 구축하는 것입니다. 그런 다음 구성 제어에 넣습니다.
죄송합니다. 외치는 것을 의미하지 않습니다. 나는 단지 30 년 동안 같은 말을 해왔다.
할 수 있나요 strace
그만큼 gcc-2.6.0
실행 가능?독서와 같은 일을 하고 있을지도 모릅니다 /proc/$$/maps
, 출력이 사소한 방식으로 변경되면 혼란스러워집니다.비슷한 문제가 있었습니다. 최근에 알아차린 2.6.28과 2.6.29 사이.
그렇다면 해킹할 수 있다 /usr/src/linux/fs/proc/task_mmu.c
또는 그 무렵 이전 출력을 복원하거나 일부 설정을 설정합니다. $LD_PRELOAD
속이기 위해 gcc
다른 파일을 읽습니다.
편집하다
당신이 언급한 이후로 brk
...
CONFIG_COMPAT_BRK
기본값으로 설정 kernel.randomize_va_space=1
대신에 2
, 그러나 이는 여전히 힙(brk
).
다음과 같은 경우 문제가 해결되는지 확인하세요. echo 0 > /proc/sys/kernel/randomize_va_space
또는 sysctl kernel.randomize_va_space=0
(동등한).
그렇다면 추가하세요. kernel.randomize_va_space = 0
에게 /etc/sysctl.conf
또는 추가 norandmaps
커널 명령줄(동등)로 이동하고 다시 행복해집니다.
나는 만났다 이것 그리고 당신의 문제에 대해 생각했습니다. 이진을 사용하여 ELF 형식으로 이동하는 방법을 찾을 수 있습니까? 또는 관련이 없을 수도 있지만 ObjDump를 사용하면 더 많은 정보를 제공 할 수 있습니다.
프로세스 메모리 맵을 볼 수 있습니까?
그래서 뭔가 해결을 해봤는데...완전한 해결책은 아니지만 레거시 gcc에서 겪었던 원래 문제를 해결했습니다.
.plt(프로시저 연결 테이블)의 모든 libc 호출에 중단점을 설정하면 malloc(libc.so.5에서)이 getenv()를 호출하여 다음을 얻는 것을 볼 수 있습니다.
MALLOC_TRIM_THRESHOLD_ MALLOC_TOP_PAD_ MALLOC_MMAP_THRESHOLD_ MALLOC_MMAP_MAX_ MALLOC_CHECK_
그래서 웹서핑해서 이런걸 발견했어요 이것 조언한 것
setenv MALLOC_TOP_PAD_ 536870912
그러면 레거시 gcc가 작동합니다!!!!
하지만 홈 프리는 아니고 실패하기 전에 빌드의 링크까지 올라갔으므로 우리가 가지고 있는 레거시 nld에 대해 추가 작업이 진행되고 있습니다. :-( 다음과 같이 보고됩니다.
Virtual memory exceeded in `new'
/etc/sysctl.conf에는 다음이 있습니다.
kernel.randomize_va_space=0 vm.legacy_va_layout=1
다음과 같은 경우에도 여전히 동일하게 작동합니다.
kernel.randomize_va_space=1 vm.legacy_va_layout=0
하지만 그렇지 않다면
kernel.randomize_va_space=2
공유 라이브러리 종속성을 확인하려면 "ldd"를 사용하라는 제안이 있었습니다.레거시 gcc에는 libc5 만 필요하지만 레거시 NLD에는 libg ++ .so.27 , libstdc ++ .so.27 , libm.so.5 가 필요하며 libg ++ .so.27 (libg ++ 27-altdev ??) libc5-compat은 어떻습니까?
그래서 제가 말했듯이 아직 집에 무료가 아닙니다 ...점점 가까워지세요.아마도 nld 문제에 대한 새로운 질문을 게시할 것입니다.
편집하다:
원래는 해당 레거시 링커에 여전히 문제가 있기 때문에 이 답변을 "수락"하지 않으려고 했지만 적어도 이 질문에 대한 최종성을 얻기 위해 해당 입장을 다시 생각하고 있습니다.
감사합니다:
- vm 사용을 제안한 an0nym0usc0ward(궁극적으로 승인된 답변이 될 수 있음)
- strace 사용을 제안하고 stackoverflow 사용에 도움을 주는 표현
- objdump 사용을 제안하는 shodanex
편집하다
다음은 제가 배운 마지막 내용입니다. 다른 방법으로는 완전히 해결할 수 없으므로(적어도 이에 대해 할당된 시간 동안) 이제 VM 솔루션을 수락하겠습니다.
최신 커널에는 libc5를 사용할 수 있도록 하는 CONFIG_COMPAT_BRK 빌드 플래그가 있으므로 아마도 이 플래그를 사용하여 새 커널을 빌드하면 문제가 해결될 것입니다. (그리고 커널 src를 살펴보면 그렇게 될 것 같지만 그렇게 했기 때문에 확신할 수는 없습니다. 모든 경로를 따르지는 않습니다).(커널 빌드 시간이 아닌) 런타임에 libc5 사용을 허용하는 또 다른 문서화된 방법도 있습니다.sudo sysctl -w kernel.randomize_va_space=0.그러나 이것은 완전한 작업을 수행하지 않고 일부 (대부분?) libc5 앱은 여전히 중단됩니다.우리의 레거시 컴파일러와 링커.이는 최신 커널과 이전 커널 간의 정렬 가정이 다르기 때문인 것 같습니다.bss의 끝을 페이지 경계까지 가져오기 위해 더 큰 bss 섹션이 있다고 생각하도록 링커 바이너리를 패치했습니다. 이는 sysctl var kernel.randomize_va_space=0일 때 최신 커널에서 작동합니다.중요한 바이너리 실행 파일을 맹목적으로 패치하고 있고, 최신 커널에서 패치된 링커를 실행하면 이전 커널에서 실행되는 원래 링커와 비트가 동일한 출력이 생성되기 때문에 이것은 나에게 만족스러운 솔루션이 아닙니다. 다른 링커 입력(예:링크되는 프로그램을 변경하면) 역시 동일한 결과를 생성합니다.
시스템이 죽으면 다시 설치할 수있는 디스크 이미지를 만들 수 없습니까? 아니면 VM을 만들까요?