JZ2440 베어 보드 개발 연습 # 6 링커 스크립트 및 재배치

SDRAM, SDRAM의 완전한 컨트롤과 코드의 내용이 SDRAM 재배치 뭔가를 할 수 있도록 이제 우리는, 읽기 및 쓰기 수 있습니다. 일부 콘텐츠가있다 https://blog.csdn.net/G_METHOD/article/details/104508545이 때문에, 링커 스크립트를 주소로 사용뿐만 아니라 같은 이유 재배치를 구분해야하는지, 재배치에 언급 여기 간단 설명 될 것이다.

우리의 프로그램은 원래의 목적지 주소에서 실행 할 수없는 경우, 코드는 이전해야합니다, 그리고 코드는 프로그램의 목적은 현재 정상적으로 실행 할 수없는 주소의 정상 작동에서 실행 주소로 이동 이전 프로그램을 수행하는 것입니다.

일반적으로 재배치 부분 복제를 포함하고, 상기 BSS 섹션을 취소 데이터 세그먼트 현재 BSS 부로서 BSS 부 전역 변수의 초기 값은 0 또는 변수 컬렉션의 초기 값, 그리고 파일 크기 함을 저장한다. 링크의 메모리 맵핑 장치의 위치 및 임의의 메모리 분포 배열 세그먼트의 상대 위치, 떠나는 동안 및 재배치 스크립트가이기 예컨대 소스 어드레스, 목적지 어드레스와 같은 네비게이션 링크를하고 있으므로 링커 스크립트들 수 스크립트는 할 수 나는 자신의 빈, 링커 스크립트 구체적이고 자세한 내용을 읽을 수 있기를 바랍니다 http://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_mono/ld.html#IDX237을 더 명확하게 이해 될 수있다, 코어 부분을 간소화에 대해 이야기하려면 여기를 링커 스크립트를 사용합니다.

SECTIONS {
...
secname start BLOCK(align) (NOLOAD) : AT ( ldadr )
  { contents } >region :phdr =fill
...
}

이것은 우리가 스크립트에 링크를 어디에의 핵심 섹션 고정 형식, 링크 스크립트는 대부분 하나 가지고해야하며, 우리는 내부의 제 메모리 매핑 세그먼트를 정렬 할 수 있습니다. secname에 일반적 .DATA,는 .text, .rodata가 .bss라고 등 세그먼트 이름은 링커에 의해 인식되어야 세그먼트 이름이다. 우리의 원하는 프로그램의 시작 주소가 실행 입력하고 지정되지 않은 경우, 언론 섹션의 순서와 길이는 주어진 진행할. 블록 (정렬) 우리는 텍스트의 배향이 다른 방식으로 언급 될 수있는 유일한 방법은 아니다 후 프로그램을 보장하도록, 정렬 된 세그먼트 어드레스의 시작 어드레스에서 절대적 정상 동작을 설정할 수있다. 무부하은 실행 파일의 세그먼트, 엘프 세그먼트를 볼 수 있습니다 읽을 수 있음을 나타냅니다 만, 프로그램이 실행 중일 때 우리는 베어 보드 절차이기 때문에, 그이 저장 위치 주소에로드되기 때문에이 부하 말하지 않았다, 메모리에로드되지 개념은 개인적으로 만 엘프 응용 프로그램 계층 거기에로드되어 있다고 생각합니다. 참고 것을 : AT는 AT 앞에 : 양쪽의 공간이 있어야합니다. 프로그램 (ldadr)의 지시에로드 주소가 빈 파일이 기능은 텍스트 데이터 및 BSS 다음 장소에 배치 한, 빈의 크기를 제어하기 위해 사용될 수 있지만마다 각 런타임 재배치 주소 같은 시작 주소는 AT (ldadr) 주소, 기본로드 주소 및 실행을 지정하지 않은 경우. 우리의 자유의 내용은 순서의 같은 단락 내에서 지역 콘텐츠를 구성합니다. 그리고 여기에 사용되지 않는 작성하고 지역 의한 phdr 뒤에하는 세부 사항으로 이동하지 않는 것입니다, 전술 한 두 번째 사이트 링크 된 문서에서이 자세히 설명되어 있습니다.

여기에 사용 된 다음 스크립트, 시작 주소로 사용 된 SDRAM 0x30000000이라면,에서 시작 주소에 예 JZ2440 출력 링크. 기호는, 현재 위치의 주소를 나타내는 기호 만 섹션에서 사용할 수있는 권리 값으로 사용됩니다 다음 링크 스크립트 __copy_start의 =에서와 같이 변수에 현재의 주소 할당 .. 최종 심볼을, 좌측의 값은 현재의 주소를 지정하는 데 사용되는 바와 같이 사용될 때, 할당의 필요성에 관한 작업이 추가 주목해야한다. 암부 (4)는 어드레스 우리가 정렬되지 않는 경우가 발생할 수 있으며, 4 바이트 정렬 강제 정렬되지 않을 때, 실행 단계 복호 기준값 바이트 이후 알긴 (4)는 4 바이트 정렬 된 어드레스를 나타내는 데이터 영역을 작성하는 수고가 필요에 0x3002 데이터 세그먼트 어드레스는 유효한 코드가 오동작을 일으키는 프로그램을 덮어 따라서 보험 경우 주소 할당은 0x3000,은 0x3000 경우 수행 직접 정렬된다 이유는 각각의 세그먼트와 정렬되어야한다.

linker.lds
-------------------------
SECTIONS{
	. = 0x30000000;
	. = ALIGN(4);
	
	_copy_start = .;
	.text : { *(.text) }
	
	. = ALIGN(4);
	.rodata :{ *(.rodata) }
	
	. = ALIGN(4);
	.data : { *(.data) }
	
	. = ALIGN(4);
	_copy_end = .; 
	
	_bss_start = . ;
	.bss : {
		*(.bss)
		*(.COMMON)
	}
	_bss_end = .;
}

우리는 세그먼트에 배치됩니다 무엇을 설명하는 링커 스크립트의 내용 부분은, 모든 파일에 대해 와일드 카드 *, 여기에 메모리에 LD -T linker.lds xxx.o yyy.o 지정된 대상 파일, 각 대상 파일의 구현 지정된 객체의 순서는 위치 및 LD의 순으로 실행되고, 상기 방식으로 배치하는 경우는 상술 한 후 위해 우리가 시작해야 같은 대상 파일의 내용을 지정하기 위하여, 물론, xxx.o yyy.o이다. 다른 파일 앞에 위치 시작 파일 S, 당신이 할 수 있도록

.text : { Start.o(.text) *(.text) }

중간 구역으로 구분.

여기 재배치 예시적인 프로그램 세그먼트 복제와 관련된 세그먼트를 삭제 기지국, 위치에 정의 된 대응 변수 재배치 프로그램을위한 세그먼트의 대응. 절에서 정의 된 변수 값의 흔적이 없다고 말할 필요가 심볼 테이블에서 엘프에 존재하여 확장, 전역 변수와 함수는 심볼 테이블에 저장되어있는 심볼에 해당하는 심볼 테이블은 해당 주소는이있다 지역에 주소 점은 변수의 초기 값은, 상황이 확장하지 여기 더 복잡한의 기능, 여기에 저장 변수 링크 스크립트뿐만 아니라 해당 주소이지만, 값이없는, 해당 주소가 링커 스크립트 변수의 값이, 따라서 우리는 외부 사용을위한 상징으로 사용되어야한다,하지만 단지 소프트웨어 (이 단계에서 신속하게 완료 할 수 있습니다 상응하는 동작으로 32 비트 주소 포인터 타입 가리키는를 사용하여, 같은 다음, 주소를 데리고와 하드웨어가 결정 수준을 제공합니다 ).

extern uint32_t _bss_start;
uint32_t *target_start_address = &_bss_start;

심볼 테이블 및 링커 스크립트 변수 및 방법을 볼 수있는 C 언어 스크립트 가변 링크를 사용하는 상세한 지식 https://sourceware.org/ml/binutils/2007-07/msg00154.html을 상기에 기초하여, 상기 출력 코드는 다음과 같이된다 :

Start.S
----------------
.text
.global _start

_start:
	MOV R0,#0
	LDR R1,[R0]
	
	STR R0,[R0]
	LDR R2,[R0]
	
	CMP R2,R0
	LDR SP,=0x40000000+4096
	MOVEQ SP,#4096
	STREQ R1,[R0]
	
	bl HardwareInitAll          //相对跳转
	ldr pc,=main                //绝对跳转,到SDRAM上运行
halt:
    b halt
s3c2440.c
------------------------
#include "s3c2440.h"

....

static void CopySegmentForReloacte(void)
{
	extern uint32_t _copy_start,_copy_end;
	uint32_t *source_start = 0;
	uint32_t *target_start = &_copy_start;
	uint32_t *target_end = &_copy_end;

	while(target_start <= target_end)
	{
		*target_start++ = *source_start++;
	}
}

static void CleanBssSegment(void)
{
	extern uint32_t _bss_start,_bss_end;
	uint32_t *target_start_address = &_bss_start;
	uint32_t *target_end = &_bss_end;

	while(target_start_address <= target_end)
	{
		*target_start_address++ = 0;
	}
}


void HardwareInitAll(void)
{
	WatchDogDisable();
	ClockDevideConfig();
	ChangeModeToAsynchronous();
	MPLLConfig();
	MemoryControllerInit();
	CopySegmentForReloacte();
	CleanBssSegment();
}

main.c
------
#include <stdint.h>

#include "s3c2440.h"
#include "led.h"
#include "uart.h"

char test_char = 'A';

int main()
{
	UartInit();

	while(1)
	{
		putc(test_char);
		if(++test_char > 'Z') { test_char = 'A'; }
		Delay(1000);
	}
	return 0;
}

다음과 같이 메이크 파일은 링커 스크립트를 지정하려면 -T 옵션을 사용하여

al:
        arm-linux-gcc -o Start.o -c Start.S
        arm-linux-gcc -o main.o -c main.c
        arm-linux-gcc -o s3c2440.o -c s3c2440.c
        arm-linux-gcc -o uart.o -c uart.c
        arm-linux-gcc -o led.o -c led.c
        arm-linux-gcc -o key.o -c key.c
        arm-linux-ld -T linker.lds -o led.elf Start.o s3c2440.o led.o key.o uart.o main.o
        arm-linux-objcopy -O binary -S led.elf led.bin
        arm-linux-objdump -D led.elf > led.dis

clean:
        rm *.dis *.o *.bin *.elf

통상 직렬 출력 순차적 AZ 즉 성공적으로 재배치하는 경우, 컴파일 NorFlash에 쓰기.

어드레스가 완료되지 않은 경우 재배치 작업을하기 전에, 유효 명령 데이터를 실행하지 않기 때문에 BL Start.S 초기화 기능 초기화 재배치의 상대 점프, 프로그램 실행은 NorFlash, 재배치 프로그램 비교적 지능적으로 점프 즉, SDRAM 데이터의 실행 시간 주소 뒤에 SDRAM 작업에 절대 점프 공식 점프 LDR 사용 준비가 된 것입니다. 코드는 프로그램 코드의 실행의 위치에 관계없이 사용할 수 있기 전에 이전 위치 의존적 인 코드의 사용을 금지하는 것을 결론 지을 수있다.

나중에 위치 독립적 인 코드를 결정 보충이 비워 둡니다.

게시 19 개 원래 기사 · 원 찬양 7 · 전망 6921

추천

출처blog.csdn.net/G_METHOD/article/details/104527632