[c++] 2GB보다 큰 코드로 GCC 컴파일 오류



4 Answers

Linux에서 사용하는 x86-64 ABI 는 GOT 및 PLT의 64 비트 재배치 유형을 포함하여 이러한 크기 제한을 피하기 위해 특별히 "대형 모델"을 정의합니다. (4.4.2 절의 표 및 3.5.5의 명령 시퀀스에서 사용 방법을 보여줍니다.)

gcc가 대형 모델을 지원하지 않기 때문에 함수가 2.8GB를 차지하므로 운이 없게됩니다. 할 수있는 일은 코드를 동적으로 링크 할 공유 라이브러리로 분리 할 수있는 방식으로 코드를 재구성하는 것입니다.

누군가가 제안했듯이 데이터를 코드에 집어 넣는 대신 (컴파일하고 링크하는 것), 코드가 거대하기 때문에 런타임에 파일을로드 할 수 있습니다 (일반 파일 또는 mmap 할 수 있음).

편집하다

대형 모델이 gcc 4.6에서 지원되는 것처럼 보입니다 ( 이 페이지 참조 ). 시도해 볼 수는 있지만 위 코드는 코드 재구성에 적용됩니다.

Question

나는 약 2.8GB의 객체 코드를 가지고있는 엄청난 수의 함수를 가지고있다. (불행하게도, 과학적 컴퓨팅 ...)

필자가 링크를 시도 할 때 relocation truncated to fit: R_X86_64_32S 오류 relocation truncated to fit: R_X86_64_32S 될 것으로 예상됩니다. 컴파일러 플래그 -mcmodel=medium 하여 우회 -mcmodel=medium 합니다. 추가로 링크 된 모든 라이브러리는 -fpic 플래그로 컴파일됩니다.

그래도 오류가 지속되고 내가 링크 한 일부 라이브러리가 PIC로 컴파일되지 않는다고 가정합니다.

여기에 오류가 있습니다.

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x12): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_fini'     defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x19): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_init'    defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o: In function    `call_gmon_start':
(.text+0x7): relocation truncated to fit: R_X86_64_GOTPCREL against undefined symbol      `__gmon_start__'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0xb): relocation truncated to fit: R_X86_64_PC32 against `.bss' 
crtstuff.c:(.text+0x13): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o
crtstuff.c:(.text+0x19): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x28): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x3f): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x46): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x51): additional relocation overflows omitted from the output
collect2: ld returned 1 exit status
make: *** [testsme] Error 1

내가 링크하는 시스템 라이브러리 :

-lgfortran -lm -lrt -lpthread

문제를 찾을 수있는 단서가 있습니까?

편집 : 우선, 토론 해 주셔서 감사합니다 ... 조금 명확히하기 위해,이 같은 별도의 개체 파일에 수백 가지 기능 (각각 약 1 MB의 크기가 별도의) :

double func1(std::tr1::unordered_map<int, double> & csc, 
             std::vector<EvaluationNode::Ptr> & ti, 
             ProcessVars & s)
{
    double sum, prefactor, expr;

    prefactor = +s.ds8*s.ds10*ti[0]->value();
    expr =       ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
           1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -
           27/10.*s.x14*s.x15*csc[49304] + 12/5.*s.x14*s.x15*csc[49305] -
           3/10.*s.x14*s.x15*csc[49306] - 4/5.*s.x14*s.x15*csc[49307] +
           21/10.*s.x14*s.x15*csc[49308] + 1/10.*s.x14*s.x15*csc[49309] -
           s.x14*s.x15*csc[51370] - 9/10.*s.x14*s.x15*csc[51371] -
           1/10.*s.x14*s.x15*csc[51372] + 3/5.*s.x14*s.x15*csc[51373] +
           27/10.*s.x14*s.x15*csc[51374] - 12/5.*s.x14*s.x15*csc[51375] +
           3/10.*s.x14*s.x15*csc[51376] + 4/5.*s.x14*s.x15*csc[51377] -
           21/10.*s.x14*s.x15*csc[51378] - 1/10.*s.x14*s.x15*csc[51379] -
           2*s.x14*s.x15*csc[55100] - 9/5.*s.x14*s.x15*csc[55101] -
           1/5.*s.x14*s.x15*csc[55102] + 6/5.*s.x14*s.x15*csc[55103] +
           27/5.*s.x14*s.x15*csc[55104] - 24/5.*s.x14*s.x15*csc[55105] +
           3/5.*s.x14*s.x15*csc[55106] + 8/5.*s.x14*s.x15*csc[55107] -
           21/5.*s.x14*s.x15*csc[55108] - 1/5.*s.x14*s.x15*csc[55109] -
           2*s.x14*s.x15*csc[55170] - 9/5.*s.x14*s.x15*csc[55171] -
           1/5.*s.x14*s.x15*csc[55172] + 6/5.*s.x14*s.x15*csc[55173] +
           27/5.*s.x14*s.x15*csc[55174] - 24/5.*s.x14*s.x15*csc[55175] +
           // ...
           ;

        sum += prefactor*expr;
    // ...
    return sum;
}

객체 s 는 상대적으로 작고 필요한 상수 x14, x15, ..., ds0, ... 등을 유지하는 반면 ti 는 외부 라이브러리에서 double을 반환합니다. 보시다시피, csc[] 는 미리 계산 된 값의지도로, 다음 형식의 개별 객체 파일 (각각 ~ 1MB 크기로 수백 개 정도)로 평가됩니다.

void cscs132(std::tr1::unordered_map<int,double> & csc, ProcessVars & s)
{
    {
    double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
           32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x35*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.x45*s.mWpowinv2 +
           64*s.x12pow2*s.x35*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.x45pow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.mbpow4*s.mWpowinv2 +
           64*s.x12*s.p1p3*s.x15pow2*s.mbpow2*s.mWpowinv2 +
           96*s.x12*s.p1p3*s.x15*s.x25*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.mbpow4*s.mWpowinv2 +
           32*s.x12*s.p1p3*s.x25pow2*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x45*s.mbpow2 +
           64*s.x12*s.x14*s.x15pow2*s.x35*s.mWpowinv2 +
           96*s.x12*s.x14*s.x15*s.x25*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.x14*s.x15*s.x35pow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25pow2*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x25*s.x35pow2*s.mWpowinv2 -
           // ...

       csc.insert(cscMap::value_type(192953, csc19295));
    }

    {
       double csc19296 =      // ... ;

       csc.insert(cscMap::value_type(192956, csc19296));
    }

    // ...
}

그게 다야. 마지막 단계는 모든 func[i] 를 호출하고 결과를 합산하는 것입니다.

이것은 매우 특별하고 드문 경우입니다. 그렇습니다. 이것은 입자 물리학에 대한 고정밀 계산을 시도 할 때 사람들이 대처해야하는 것입니다.

EDIT2 : 나는 또한 x12, x13, 등등은 정말 상수가 아니라는 것을 추가해야합니다. 그들은 특정 값으로 설정되고 모든 함수가 실행되고 결과가 반환 된 다음 x12, x13 등의 새 집합이 선택되어 다음 값을 생성합니다. 그리고 이것은 10 ^ 5에서 10 ^ 6 번 ...

EDIT3 : 제안 및 토론 주셔서 감사합니다 지금까지 ... 어떻게 든 코드 생성시 루프를 롤백하려고합니다. 솔직히이 방법을 정확히 알지 못하지만, 이것이 최선의 방법입니다.

BTW, 나는 이것이 "과학적 컴퓨팅 - 최적화 할 수있는 방법이 아닙니다"뒤에 숨기려고하지 않았습니다. 이 코드의 기초는 내가 실제로 접근 할 수없는 "블랙 박스"에서 나오는 것이며, 게다가 모든 것이 간단한 예제로 훌륭하게 작동했으며, 실제로는 실제 상황에서 어떤 일이 일어날 지 압도 당하고 있다고 느낍니다. 세계적인 응용 프로그램 ...

EDIT4 : 그래서 컴퓨터 대수학 시스템 ( Mathematica )에서 표현식을 단순화하여 약 1만큼 csc 정의의 코드 크기를 줄였습니다. 코드를 생성하기 전에 다른 트릭을 적용하여 몇 가지 방법으로 크기를 줄이는 방법도 있습니다.이 방법을 사용하면이 부분을 약 100MB로 줄일 수 있습니다.

이제 당신의 대답과 관련이 있습니다 : 나는 CAS가 많은 도움이되지 않는 func 에서 루프를 다시 롤백하려고 노력하고 있지만 이미 아이디어가 있습니다. 예를 들어 x12, x13,... 과 같은 변수로 표현식을 정렬하면 csc 를 Python으로 구문 분석하고 서로 관련있는 테이블을 생성합니다. 그런 다음 최소한 이러한 부분을 루프로 생성 할 수 있습니다. 이것이 지금까지 가장 좋은 해결책 인 것 같아서, 나는 이것을 가장 좋은 대답으로 표시했다.

그러나 VJo에 대해서도 공을 들여야합니다. GCC 4.6은 실제로 잘 작동 하고 , 더 작은 코드를 생성하며 빠릅니다. 대형 모델을 사용하면 코드에서 그대로 작동합니다. 그래서 기술적으로 이것은 정답이지만 전체 개념을 바꾸는 것이 훨씬 더 나은 접근법입니다.

귀하의 제안과 도움에 감사드립니다. 관심있는 사람이 있으면 준비가 완료되는대로 최종 결과를 게시하겠습니다.

비고 : 몇 가지 다른 답변이 있습니다. 실행하려고하는 코드는 간단한 함수 / 알고리즘의 확장과 불필요한 불필요한 언 롤링에서 유래하지 않습니다. 실제로 일어나는 일은 우리가 시작하는 것들이 꽤 복잡한 수학적 객체이며 수치 계산 가능한 형태로 가져 오는 것이 이러한 표현을 생성한다는 것입니다. 문제는 실제로 기본 물리 이론에 있습니다. 중간 표현의 복잡성은 요인에 따라 달라 지지만,이 모든 것들을 물리적으로 측정 할 수있는 것, 즉 관찰 할 수있는 것으로 결합하면 표현의 기본을 구성하는 아주 작은 함수들로 끝납니다. ( "섭동 이론 (perturbation theory)"이라고 불리는 일반적이고 유일하게 이용 가능한 ansatz 대해서는이 점에서 분명히 "틀린"것이있다.) 우리는이 ansatz를 다른 수준으로 가져 오려고 노력한다. 이것은 분석적으로는 더 이상 가능하지 않으며 필요한 기능의 기초는 불명. 그래서 우리는 그것을 이렇게 무차별 적으로 시도합니다. 최선의 방법은 아니지만, 결국에는 물리학에 대한 우리의 이해에 도움이되는 한 가지 방법이 있습니다.

마지막 편집 : 모든 제안 덕분에 필자는 코드 크기를 상당히 줄였습니다. Mathematica와 코드 생성기의 수정을 사용하여 최상위 답변 라인을 따라 다소 단축되었습니다. :)

필자는 Mathematica로 csc 함수를 단순화하여 92 MB로 낮추었습니다. 이것은 환원 불가능한 부분입니다. 첫 번째 시도는 영원히 걸렸지 만 일부 최적화 후에는 이제 단일 CPU에서 약 10 분 만에 실행됩니다.

func 에 대한 효과는 극적이었습니다. 코드 크기가 약 9MB로 줄어들 었으므로 코드는 이제 100MB 범위로 합쳐집니다. 이제는 최적화를 실행하는 것이 좋으며 실행은 매우 빠릅니다.

다시 한 번, 여러분의 제안에 대해 모두 감사 드리며, 많이 배웠습니다.




그 표현은 나에게 반복되는 시리즈처럼 많이 보인다. 나머지 코드는 어떻게 생겼는지 모르지만 생성 식을 유도하는 것이 어려울 것 같지 않습니다. 아마도 실행 시간에 가치가있을 것입니다. 특히 2.8 GB의 풀리지 않은 코드가있는 경우 특히 그렇습니다.




몇 가지 제안 사항 : - 크기 (-Os)에 맞게 최적화하십시오. 인라인 함수 호출, 일반 함수 호출을 만듭니다. 문자열 풀링을 사용합니다.

여러 DLL (공유 객체, Linux의 경우 .so, Mac OS X의 경우 .dylib)로 분할 해보십시오. 그것들을 내릴 수 있는지 확인하십시오. 그런 다음 요구에 따라 물건을 적재하고 필요하지 않을 때 물건을 비우기 위해 무언가를 구현하십시오.

그렇지 않다면 코드를 다른 실행 파일로 나눠서 무언가를 사용하여 그들 사이에서 통신하십시오 (파이프, 소켓, 파일 쓰기 / 읽기). 서투른,하지만 어떤 옵션이 있습니까?

완전히 대안 : - JIT 와 함께 동적 언어를 사용하십시오. 내 머리 꼭대기에 LuaJIT 사용하고 Lua 나 코드를 가비지 수집 할 수있는 다른 언어 및 런타임에서 이러한 많은 표현식을 다시 작성 (다시 생성) 할 수 있습니다.

LuaJIT는 매우 효율적이며 어떤 경우 C / C ++을 때리고 때로는 매우 가깝습니다. (가끔 가비지 콜렉션 때문에 느려질 수도 있습니다.) 직접 확인하십시오.

http://luajit.org/performance_x86.html

거기에서 scimark2.lua 파일을 다운로드하고 "C"버전 (google it)과 비교하십시오. 종종 결과가 매우 비슷합니다.




오류를 올바르게 읽은 경우 초기화 된 데이터 섹션이 한계를 넘기게됩니다 (코드 인 경우 IMHO 오류가 훨씬 더 많음). 대규모 데이터 배열이 있습니까? 그렇다면 동적으로 할당되도록 프로그램을 재구성 할 것입니다. 데이터가 초기화되면 구성 파일에서 읽습니다.

이것을보고 BTW :

(. 텍스트 + 0x20) : 정의되지 않은 'main'참조

다른 문제가 있다고 생각합니다.




데이터가 아닌 CODE가 너무 많아서 오류가 발생합니다! 예를 들어 _start 에서 참조되는 __libc_csu_fini (함수)가 표시되고 재배치가 맞게 잘립니다. 이것은 _start (프로그램의 참 진 엔트리 포인트)가 2GB의 범위만을 가진 SIGNED 32 비트 오프셋을 통해 해당 함수를 호출하려고한다는 것을 의미합니다. 오브젝트 코드의 총량이 ~ 2.8GB이므로 사실을 확인합니다.

데이터 구조를 재 설계 할 수 있다면 커다란 표현을 간단한 루프로 다시 작성함으로써 코드의 상당 부분을 "압축"할 수 있습니다.

또한 다른 프로그램에서 csc[] 를 계산하고 결과를 파일에 저장 한 다음 필요할 때로드 할 수 있습니다.






Related