Egloos | Log-in
F/OSS study
F/OSS study
[Linux] RELOC_HIDE 매크로
Linux: 2.6.35


RELOC_HIDE() 매크로는 컴파일러의 최적화/오동작(?)을 방지하려는 목적으로 만들어진 것으로
gcc의 경우 다음과 같이 정의되어 있다.

include/linux/compiler-gcc.h:
#define RELOC_HIDE(ptr, off)                    \
  ({ unsigned long __ptr;                       \
    __asm__ ("" : "=r"(__ptr) : "0"(ptr));      \
    (typeof(ptr)) (__ptr + (off)); })

이러한 (요상하기 짝이 없는) 매크로의 의미는 사실 단순한데
ptr 포인터에 off 오프셋을 더하여 리턴하는 것일 뿐이다.
즉 ((unsigned long) ptr + off)과 동일한 계산을 하는 것이다.
(물론 최종적으로 다시 원래의 포인터 타입으로 cast한다)

그럼 이러한 작업이 왜 필요한 것일까?
간단하게 말하면 (대부분의 경우) 필요없다!! (-_-;;)
(사실 커널 소스 내에도 불필요하게 사용된 부분이 조금씩 보인다.)

원래 RELOC_HIDE 매크로가 사용되는 상황은
주어진 ptr을 통해 off 만큼 떨어진 데이터에 접근하는 경우인데
사실 이 ptr 값이 실제로 메모리 상에 존재하는 데이터 (객체)에 대한 타입이 아니라
(구현 상의 어떤 제약에 따른) 다른 타입의 포인터인 경우이다.

일반적인 경우에는 ptr이 가리키는 해당 객체의 내부 영역에만 접근할 것이므로
ptr이 어떠한 구조체에 대한 포인터이고 해당 구조체 내의 field 필드에 접근한다고 하면
(너무나 당연하게도) 이러한 매크로가 필요없이 ptr->field와 같이 접근하면 된다.

하지만 ptr이 가리키는 원래의 객체의 크기를 넘어가는 영역에 접근하기 위해서
(type cast하여) 강제로 off 값을 더하게 되면 컴파일러가 잘못된 접근을 감지하고
컴파일 시에 의도하지 않은 코드를 생성하게 될 가능성이 있다.

C 표준에서는 포인터를 통해 지정된 크기를 넘어서 접근하는 경우는 undefined behavior로 명시하고 있다.
실제로 PPC64 아키텍처에서 gcc 4.1 이전의 버전을 사용하는 경우 이러한 문제가 발생했다고 하는데
이 경우 ptr 값을 unsigned long 타입으로 cast하더라도 원래의 포인터 정보가 남아있어서
(copy propagation에 의해?) 동일한 문제가 발생한 것 같다.

따라서 gcc에게 이러한 타입 정보를 완전히 숨기기 위해 중간의 inline asm 부분이 추가되었는데
해당 코드는 단순히 (타입 정보를 무시하고) 다음의 C 코드와 동일하다.

__ptr = ptr;

대신 이 부분은 gcc가 관여하지 않도록 assembly 루틴으로 생성되기 때문에
gcc는 __ptr 값이 어디서 왔는지 전혀 알 수 없으며 따라서 이에 대한 어떠한 최적화(?)도 수행할 수 없다.

RELOC_HIDE 매크로가 필요한 유일한(?) 경우는 per-CPU 메모리 영역에 접근할 때이다.
per-CPU 영역은 kernel image 상에는 1 set의 데이터 만이 포함되어 있지만
실행 시에 이를 CPU 수 만큼 복제하여 할당하기 때문에 원래의 크기를 넘어서는 접근이 발생한다.

한 마디 추가하자면 RELOC_HIDE는 (이름에서 쉽게 연상할 수 있는 것과 달리)
linker relocaiton과는 전혀 상관이 없다는 것을 알아두기 바란다.
(이것 때문에 얼마나 고민+삽질했는지.. ;;)

그냥 ptr을 off 만큼 이동시키는 것을 (이것 자체를 relocation이라고 생각하자)
gcc에게 숨기는 (hide) 역할일 뿐이다.

참고로 (나중에 알고는 충격을 받았지만;;) 이 매크로는 컴파일러에 종속적인 특성이므로
gcc가 아닌 다른 컴파일러의 경우는 단순히 RELOC_HIDE 매크로가 다음과 같이 정의되어 있다.

include/linux/compiler-intel.h:
#define RELOC_HIDE(ptr, off)                    \
  ({ unsigned long __ptr;                       \
     __ptr = (unsigned long) (ptr);             \
    (typeof(ptr)) (__ptr + (off)); })


=== 참조 문서 ===

by namhyung | 2010/08/08 15:26 | Kernel | 트랙백 | 핑백(1) | 덧글(1)
트랙백 주소 : http://studyfoss.egloos.com/tb/5374731
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at June Note : sche at 2015/02/09 02:10

... (typeof(ptr)) (__ptr + (off)); }) 이 부분도 김남형님 블로그에 잘설명이 되어있네요 ㅎㅎ http://studyfoss.egloos.com/5374731정말 감사할 따름이죠. this_rq하다가 여기까지 와버렸는데. 이는건 않될꺼같아요 ㅋㅋㅋㅋ ... more

Commented by 문태호 at 2015/05/27 12:44
설명 진짜 잘해주셨네요 감사합니다. xen코드 분석하다가 갑자기 저런게 나와서 포인터에 offset더하는건가 추측만 했어요. 중간에 asm이 뭐하는지 모르겠어서;;ㅠㅠ
감사합니다.!!

그런데 궁금한게

per-CPU 영역은 kernel image 상에는 1 set의 데이터 만이 포함되어 있지만
실행 시에 이를 CPU 수 만큼 복제하여 할당하기 때문에 원래의 크기를 넘어서는 접근이 발생한다.

이 부분이 말하는게 kernel image에서 per-CPU에 관한 자료구조가 CPU 1 set 분량만 있는데 runtime에서 CPU 수 만큼 복제해서 할당하기때문에 우리가 코드를 짜서 접근하는게 불가능(컴파일러때문에) 하니까 RELOC_HIDE(ptr, off) 를 쓴다는건가요?
잘 이해한건지 모르겠어요 ㅎㅎ

:         :

:

비공개 덧글

◀ 이전 페이지 다음 페이지 ▶

카테고리
General
Application
System
Kernel
Book
Tips
태그
linux bash x86 computer-architecture emacs binutils documentation gcc script synchronization patch sed algorithm block-layer C perf memory awk elf SMP blktrace vcs scm compiler kernel git build glibc CARM CAaQA3
전체보기
이글루 파인더

최근 등록된 덧글
informsi yang bagus dan b..
by agen qnc at 06/22
informasi yang bagus dan b..
by agen qnc at 06/22
informasi yang bagus dan b..
by agen qnc at 06/22
최근 등록된 트랙백
Tod's Ferrari Homme
by Tods Pas Cher,Kodak did ..
Mocassin Femme
by Mocassins Homme, I got so..
natural garcinia cambogia
by
rss

skin by jiinny


X