programing

응용프로그램별 링커 스크립트에 정의된 접근 기호

lovejava 2023. 10. 26. 20:28

응용프로그램별 링커 스크립트에 정의된 접근 기호

링커 스크립트 파일에서 두 개의 기호를 정의했습니다.

define symbol _region_RAM_start__     = 0xC0000000;
define symbol _region_RAM_end__       = 0xC00fffff; 

그 후 아래와 같이 수출했습니다.

export symbol _region_RAM_start__;
export symbol _region_RAM_end__;

애플리케이션 코드에서 이 기호들에 접근하려고 합니다.

extern const unsigned int _region_RAM_start__;
extern const unsigned int _region_RAM_end__;
....
int GetRAMSize()
{
    int size = 0;
    unsigned int address_1 = _region_RAM_start__;
    unsigned int address_2 = _region_RAM_end__;
    size = address_2 - address_1 + 1U;
    return size;
}

지금은 반품 값이 0x00100000이라고 예상했는데 0밖에 안 나와요.그래서 디버거를 찾아보니,_region_RAM_start__그리고._region_RAM_end__ 및 의 값을,각 0xC0000000및 0xC00ffff만,address_1그리고.address_2값이 0입니다.

컴파일러 최적화는 "없음"으로 설정됩니다.이것 때문에 한동안 신경이 쓰였습니다.제가 여기서 놓치고 있는 것이 분명한가요? "애초에 이런 일을 해서는 안 된다"는 것 말고요?

해결책 답변을 주신 n.

  unsigned int address_1 = (unsigned int) (&_region_RAM_start__);

그렇지않으면address_1그리고.address_2둘 다 가비지 값(즉, 주소 0xC0000000 및 0xC00ffff에서 사용 가능한 값이지만 이 코드의 관점에서는 가비지)을 포함합니다.

그건 좀 오래된 얘기지만 어쨌든 제가 답하겠습니다.

설명서에서:

소스 코드에서 링커 스크립트 정의 변수에 접근하는 것은 직관적이지 않습니다.특히 링커 스크립트 기호는 고급 언어의 변수 선언과 동일하지 않으며 대신 값이 없는 기호입니다.

여기서 더 나아가기 전에 컴파일러는 소스 코드의 이름을 심볼 테이블에 저장할 때 다른 이름으로 변환하는 경우가 많습니다.예를 들어, 포트란 컴파일러는 일반적으로 밑줄을 붙이거나 붙이며, C++는 광범위한 이름 망글링을 수행합니다.따라서 소스 코드에 사용되는 변수의 이름과 링커 스크립트에 정의된 동일한 변수의 이름 사이에 불일치가 있을 수 있습니다.예를 들어, Collinker 스크립트 변수는 다음과 같습니다.

extern int foo;

그러나 링커 스크립트에서는 다음과 같이 정의될 수 있습니다.

_foo = 1000;

그러나 나머지 예에서는 이름 변환이 수행되지 않은 것으로 가정합니다.

C와 같은 상위 언어로 기호를 선언하면 두 가지 일이 발생합니다.첫 번째는 컴파일러가 프로그램의 메모리에 기호의 을 저장할 수 있는 충분한 공간을 확보한다는 것입니다.두 번째는 컴파일러가 프로그램의 심볼 테이블에 심볼의 주소를 저장하는 항목을 생성하는 것입니다.즉, 심볼 테이블은 심볼의 값을 보유하는 메모리 블록의 주소를 포함합니다.예를 들어 파일 범위에서 다음과 같은 C 선언을 합니다.

int foo = 1000;

는 기호 테이블에 "foo"라는 항목을 만듭니다.이 항목은 숫자 1000이 처음 저장된 메모리 블록의 주소를 저장합니다.

프로그램이 기호를 참조할 때 컴파일러는 먼저 기호 테이블에 액세스하여 기호의 메모리 블록의 주소를 찾은 다음 해당 메모리 블록에서 값을 읽도록 코드화하는 코드를 생성합니다.그래서:

foo = 1;

는 기호 테이블에서 기호 foo를 찾아 이 기호와 연결된 주소를 가져온 다음 값 1을 해당 주소에 씁니다.반면:

int * a = & foo;

는 기호 테이블에서 기호 foo를 찾아 주소를 가져온 다음 이 주소를 변수 "a"와 연관된 메모리 블록에 복사합니다.

반대로 링커 스크립트 심볼 선언은 심볼 테이블에 항목을 만들지만 해당 항목에 메모리를 할당하지 않습니다.따라서 값이 없는 주소입니다.예를 들어 링커 스크립트 정의:

foo = 1000;

는 메모리 위치 1000의 주소를 보유한 @samp{foo}라는 항목을 기호 테이블에 생성하지만 주소 1000에는 특별한 내용이 저장되지 않습니다.즉, 링커 스크립트 정의 기호의 에 액세스할 수 없습니다. 값이 없습니다. 링커 스크립트 정의 기호의 주소만 사용할 수 있습니다.

따라서 소스 코드에서 링커 스크립트로 정의된 심볼을 사용할 때는 항상 심볼의 주소를 사용해야 하며, 절대로 심볼의 값을 사용하려고 해서는 안 됩니다.예를 들어, 라고 하는 메모리의 섹션의 내용을 복사하고 싶다고 가정합니다.ROM은 로 불리는 섹션으로 이동합니다.FLASH와 링커 스크립트는 다음과 같은 선언을 포함합니다.

start_of_ROM   = .ROM;
end_of_ROM     = .ROM + sizeof (.ROM);
start_of_FLASH = .FLASH;

그러면 복사를 수행하는 C 소스 코드는 다음과 같습니다.

extern char start_of_ROM, end_of_ROM, start_of_FLASH;

memcpy (& start_of_FLASH, & start_of_ROM, & end_of_ROM - & start_of_ROM);

"&" 연산자의 사용에 유의합니다.맞아요.

액세스하려는 일반 주소 기호이며 반드시 특정 유형을 가리키는 포인터는 아니므로 서명되지 않은 int로 선언하지 않고 다음과 같이 선언합니다.

외부 공백 _지역_RAM_START;

&_지역_RAM_START에는 적절한 유형의 'void *'가 있습니다.

아래 코드는 예상대로 작동해야 합니다.

extern const volatile unsigned int _region_RAM_start__;

extern const volatile unsigned int _region_RAM_end__;

....
int GetRAMSize()

{

int size = 0;

unsigned int address_1 = &_region_RAM_start__;

unsigned int address_2 = &_region_RAM_end__;

size = address_2 - address_1 + 1U;

return size;

}

언급URL : https://stackoverflow.com/questions/8398755/access-symbols-defined-in-the-linker-script-by-application