[Makefile] relocation R_X86_64_32 againg. recompile with -fPIC

윤찬호·2023년 3월 21일
0

에러

목록 보기
5/6

현상

리눅스 64bit 빌드중 정적 라이브러리(.a)를 링크하여 공유 라이브러리(.so)를 생성하는 과정에서 아래 에러가 발생.


/usr/bin/ld: aaa.o: relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC

/usr/bin/ld: xxx.a(x.o): relocation R_X86_64_32S against '.rodata' can not be used when making a shared object; recompile with -fPIC
...

똑같은 환경에서 -m32 옵션을 이용해 32bit 빌드했을 때는 해당 에러가 발생하지 않았는데, 64bit 빌드(-m32 옵션 제거)시에 해당 에러가 발생했다.

테스트 환경이 갖춰지지 않은 관계로 32bit 빌드로 생성한 파일에 대해서는 실행 및 테스트를 해보지 않았기 때문에 실제로 정상적인 파일인지 확인은 못했지만 빌드 과정에서는 별다른 에러가 발생하지 않았다.

해결과정

에러 메시지의 마지막(recompile with -fPIC)을 보면 -fPIC를 사용하여 컴파일을 다시 하라고 나와있다.

fPIC 옵션이란?

fPIC에서 PIC(Position Independent Code)는 메모리의 어느 공간에든 위치할 수 있고 수정없이 실행 가능한 위치 독립코드를 의미한다.

fPIC는 상대적인 위치를 저장함으로서(상대 주소) 프로세스마다 위치 독립적인 코드(Position Independent Code)로 컴파일 하여 사용한다. 즉, 공유 라이브러리 내의 심볼들이 어느 위치에 있더라도 동작하게 해준다.

보통 공유 라이브러리를 만들때 실행시 재배치에 소요되는 시간을 줄이고 다른 프로세스와 코드를 공유한다는 장점을 이용하기 위해 -fPIC옵션을 이용해서 코드를 컴파일 한다.

심볼(Symbol)
변수, 함수와 같이 프로세스가 실행될때 메모리를 지정해줘야 하는 객체

재배치
라이브러리의 주소를 현재 사용하려는 프로세스 주소에서 접근 가능하도록 재배치 한다는 개념


내가 작성한 Makefile에는 -fPIC 옵션을 사용하지 않았기 때문에 해당 옵션을 추가하고 다시 make를 해보니 몇개의 에러들은 해결되었지만 여전히 많은 오류가 발생했다.

에러코드를 다시 자세히 보면 현재 Makefile에서 링크해서 사용하는 .a 파일들에 대해서도 -fPIC 옵션을 사용해서 다시 컴파일을 하라고 나와있다.

링크해서 사용하는 모든 라이브러리 파일들에 대해 -fPIC 옵션을 추가하고 빌드한 결과물을 이용해 다시 make를 해보니 에러 없이 빌드가 되었다.

fPIC 옵션을 사용했는지 확인하기

라이브러리 파일이 -fPIC 옵션을 사용해서 컴파일 했는지 확인하는 방법은 아래와 같다.

(라이브러리 파일의 이름을 foo.a라고 가정)

ar -x foo.a

foo.a 를 만들기 위한 object 파일이 나오면 (xxx.o)

readelf --relocs xxx.o | egrep '(GOT|PLT|JU?MP_SLOT)'

위 명령어 실행 결과 아무런 메시지도 나오지 않으면 -fPIC 옵션을 사용하지 않고 컴파일 한 것이다.


fPIC 옵션을 사용한 경우 명령어의 실행 결과는 아래 이미지와 같다.

에러 발생 원인

해당 오류와 관련하여 검색중 아래와 같은 내용을 발견했다.

다른 정적 라이브러리를 링킹하는 과정에서 fPIC 옵션을 지정한 경우, 모든 정적 라이브러리가 fPIC 옵션을 가지고 컴파일 되어야 한다. 하지만, 그 중에 fPIC으로 컴파일 되지 않은 라이브러리가 있는 경우에는 이를 다시 컴파일 해주어야 한다.

Makefile 에서 사용한 라이브러리 파일 중에 fPIC 옵션을 사용하여 컴파일된 파일이 있었다면 위에 설명대로 모든 라이브러리에 대해 fPIC 옵션을 사용하여 다시 컴파일 해야 하는게 맞겠지만, 확인해본 결과 fPIC 옵션을 사용해서 컴파일한 라이브러리 파일은 없었다...

앞에서도 말했지만 32bit fPIC 옵션과 관계없이 에러 없이 빌드가 잘 됬다.

stackoverflow에서 이와 비슷한 현상을 발견했지만 정확한 원인은 모르겠다.
https://stackoverflow.com/questions/19768267/relocation-r-x86-64-32s-against-linking-error


(내용 추가)

검색을 더 해보다가 아래 블로그에서 해답을 찾을수 있었다.
https://junstar92.tistory.com/445

내용을 요약해보면

32bit 환경에서 동적(공유) 라이브러리를 빌드할때 -fPIC옵션은 필수가 아니라고 한다.

64bit 환경에서는 실행 파일에 링크된 정적 라이브러리는 -fPIC옵션을 사용하거나 사용하지 않고 컴파일 할 수 있다. (fPIC 사용 여부는 중요하지 않다.)
하지만, 동적 라이브러리에 링크된 정적 라이브러리는 -fPIC옵션을 사용하여(또는 -fPIC대신 -mcmodel=large 옵션) 컴파일 해야 한다. 정적 라이브러리가 두 옵션중 하나로 컴파일되지 않고 동적 라이브러리에 링크하려고 하면, 다음과 같이 링크 에러가 발생한다.

relocation R_X86_64_32 againg. recompile with -fPIC

정리

공유 라이브러리를 생성할 때는 무조건 -fPIC 옵션을 사용하자.

링킹하는 과정에서 fPIC 옵션을 지정한 경우, 모든 정적 라이브러리가 fPIC 옵션을 가지고 컴파일 되어야 한다.




참고
https://xn--vj5b11biyw.kr/127
https://asung123456.tistory.com/18
https://jurecord.tistory.com/10
https://stackoverflow.com/questions/19768267/relocation-r-x86-64-32s-against-linking-error
https://junstar92.tistory.com/445

0개의 댓글