2010-06-12 3 views
3

C++ 및 GCC를 사용하면 메모리의 특정 주소를 사용하는 extern 변수를 선언 할 수 있습니까?특정 주소의 Extern 변수

int key __attribute__((__at(0x9000))); 

같은 뭔가 AFAIK이 특정 옵션은 임베디드 시스템에서 작동합니다. x86 플랫폼에서 사용할 수있는 옵션이 있다면 어떻게 사용할 수 있습니까?

답변

10

쉬운 옵션 :

int * const key = (int *)0x9000; 

을 정의하고 다른 곳 *key 참조 (또는 참조를 사용).

, 포인터 옵션 :

모든 externs 특정 주소가! 이러한 주소는 링크 시간까지 알 수 없지만 결국 해결되어야합니다. extern int key;을 선언하는 경우 링크시 심볼 key의 주소를 제공해야합니다. 이 작업은 링커 스크립트 (Using ld 참조) 또는 링커 명령 행에서 --defsym 옵션을 사용하여 수행 할 수 있습니다.

gcc를 실행하는 경우 -Xlinker 플래그를 사용하여 링커에 옵션을 전달할 수 있습니다. 하여 예에서

gcc -o outfile -Xlinker --defsym -Xlinker key=0x9000 sourcefile.c 

다음 프로그램 따라서 출력 0x9000 컴파일. 당신은 당신이 메모리의 일부 지역에되고 싶은 변수의 모음이 있다면 아마도 사용자 정의 ld 스크립트와 함께, 니콜라이에 의해 제안

#include <stdio.h> 
extern int key; 
int main(void) { 
    printf("%p\n", &key); 
    return 0; 
} 

, 더 적절한 방법은 출력 섹션을 사용할 수 있습니다.

+0

'const' 포인터의 좋은 점. –

+1

이것은 내가 찾고 있었던 것이다. DLL 주입을 사용하여 프로그램을 뒤집을 것입니다. 내 DLL 코드 내에서 대상 프로세스에 속하는 변수에 액세스해야합니다. 그들을 포인터를 사용하지 않고 액세스하려면 extern 변수에 특정 주소를 지정하는 방법이 필요했습니다. 감사! – AndiNo

+0

어떤 이유로 든 변수 주소를 변경하려면 코드를 다시 컴파일 할 필요가 없습니다. 단지 다시 링크해야합니다. :) – Artelius

0

메모리가 x86 플랫폼의 MMU를 통해 가상화되기 때문에 데스크톱 응용 프로그램 (장치 드라이브의 메모리 매핑 I/O의 경우 의미가 있음)에서는 작동하지 않습니다. 따라서 가상 공간의 어딘가에 어떤 물리적 주소가 위치하는지 알 수 없습니다.

메모리 I/O 또는 다른 해킹을 테스트하는 것 외에 어떤 유스 케이스가 있을까요? x86에서 사용자 공간의 각 메모리 셀은 같습니다 ... 변수에 액세스하려면 변수 이름에 dlsym()이 Linux에서 친구가되고 Windows에서는 GetProcAddr()입니다. 직접 주소를 지정하는 것은 AFAIK를 예견하지 않습니다.

다른 공유 라이브러리와 중복되는 경우 다른 위치로 이동할 수 있기 때문에 공유 된 lib 또는 dll에 대해 원하는 기본로드 주소를 제공하는 것조차 도움이되지 않습니다. 최신 OS'es의 주소 무작위 화 기능은 거의 예측할 수 없게합니다 (재현 가능한 버퍼 오버플로 공격을 피하는 목표는 무엇입니까?)

4

GCC 문서에서이 속성을 찾을 수 없습니다. 많은 현대 시스템이 address space layout randomization을 제공하기 때문에 범용 프로그램에는 의미가 없습니다. 당신은 내가 추측을 요청할 수있는 최선의, 당신은 변수의 [가상] 주소를 알고 경우, 또한에서

int init_data __attribute__ ((section ("INITDATA"))); 

으로, 특정 부분에 변수를 넣어하는 것입니다, 왜 그냥 포인터를 통해 액세스 할 :

int* pkey = (int*)0x9000; 
*pkey = 0xdeadbeef; 
+0

커널 프로그래밍에 자주 gcc가 사용되는 것을 잊어 버리는 경우가 있습니다. 흔히 중요한 메모리 매핑 장치는 특정 위치에 있습니다. –

+1

커널에서는 물리적 메모리가 커널 가상 주소 공간으로 매핑 될 때 부트 스트랩 코드에서만 의미가 있습니다. 그렇다면 실제 주소를 소스 코드에 하드 코딩해야합니까 (일부 구성 가능한 기본 주소에 대한 오프셋과 반대)? –

+0

가끔 유용 할 때도 있습니다. 가상 주소가 고정되어있는 UTCB의 경우 가상 메모리가 없거나 가상에서 실제로의 단순한 선형 매핑으로 * 간단한 * 커널의 경우. 내가 생각할 수있는 유일한 이점은 기호가 링크 타임에 해결 될 수 있다는 것입니다 (따라서 내 대답에 나와 있음). 주소를 변경하기 위해 개체 파일을 다시 컴파일 할 필요가 없습니다. – Artelius

-2

번호 현대 데스크톱 운영 체제를 사용하면 특정 메모리 주소가 쓸모 만드는 OS에 제공 할 때까지 의미가있는 어떤 주소 즉, 가상 메모리를 사용합니다. 데스크탑/x86에서는이 방법이 유용하지 않습니다.

0

나는 IAR의 C 컴파일러가 보이는 비표준 확장을 사용한다는 생각 적어도 자신의 MSP430 컴파일러 이에 대한

char foo @ 0x9000; 

같은. 필자는 MSP430을 위해 GCC를 사용하지는 않았지만 IAR의 컴파일러와 소스 호환성을 얻을 수 있도록이 기능을 지원했을 수도 있습니다.

링커를 사용하지 않고 모든 컴파일러에서 작동 할 작업을 원한다면 조금 더 세게 작업해야합니다.

#define CONST_ADDR_VAR(type, name, address) type *const name##_addr =(type *)address 

각 변수에 대한 것을 호출 한 후에 당신은 또한 #DEFINE의 VAR (* var_addr)이이 이전 매크로와 결합 된 수 있다면

그것은 좋은 것을 수행해야합니다 지정하려면, 매크로 내에서 매크로를 정의하는 것은 표준이 아닙니다. 그래도 GCC의 전 처리기로 처리하는 방법이 있다고 생각합니다.

링커로 원숭이를 보내고 싶다면이 변수가 어디에 살았는지 알려주고 C 프로그램에서 extern으로 사용하면됩니다.

또한 GCC의 __attribute__((section(...)))을 사용할 수 있지만 주소를 지정하려는 각 변수마다 다른 섹션이 필요할 수 있습니다. 이것에 관해 약간 혼란스러워 보이는 다른 것들도 있었고, 링커에게이 섹션들이 어쨌든 어디에 있는지를 말해 줄 것을 요구할 것입니다.

http://www.ohse.de/uwe/articles/gcc-attributes.html#var-section

1

당신이 C++로이 태그 때문에, 당신은 쉽게 새로운 배치를 사용할 수 있습니다. 좋은 휴대용 어느 :

// an object type T at address 0x9000 
T* t = new(reinterpret_cast<void*>(0x9000)) T; 

은 분명히이 글로벌되지 않습니다 new 함수의 외부에서 사용할 수 있기 때문이다. 그러나 당신은 쉽게 이런 식으로 일부 전역을 초기화하기 위해 가능한 빨리 호출하는 함수를 가질 수 있습니다.

3

그냥 매크로를 사용할 수 있습니다

#define KEY (*(int*)0x9000) 

그래서 어떤 그 메모리 위치에 KEY 쓰기에 대한 쓰기, 및 그 메모리 위치에서 읽을 KEY로 읽습니다. (가 하드웨어 레지스터 또는 메모리 매핑 된 I/O의 일종을 나타내는 경우 등) 그 메모리 위치가 당신의 통제 밖에서 바꿀 수 있다면

, 당신은 그것을 volatile를 선언해야합니다 :

#define KEY (*(volatile int *)0x9000) 

이 의지 컴파일러가 읽을 때마다 메모리에서 값을 다시 읽고 컴파일 할 때마다 메모리에 다시 다시 쓰도록 강제합니다. 레지스터에 캐싱하지 않을 수도 있습니다.

+0

매크로가 마음에 들지 않으면 내 대답과 같이 const 포인터를 사용하십시오. – Artelius