天嵌 ARM开发社区

 找回密码
 注册
查看: 1743|回复: 0

TQ210裸机编程(10)——代码重定位

[复制链接]
freewing 发表于 2014-6-8 01:06:15 | 显示全部楼层 |阅读模式
关于重定位的理论知识推荐大家观看韦东山的视频《6410裸板视频》中的第5章(位置无关码、重定位)。

下载地址:http://pan.baidu.com/share/link? ... 0%E8%A3%B8%E6%9D%BF

在S5PV210上的实验方法:烧写程序到SD的第1块,从SD启动,程序的链接地址为0xD0024000,在程序中将程序拷贝到0xD0024000地址处,然后跳转到main函数去执行。

运行效果如下:

before relocate

after relocate
t = 0
t = 1
t = 2
t = 3
t = 4
t = 5
8ððàÿÿÿÿÿÿÿø

在重定位之前,用自己实现的puts函数打印字符串“before relocate”,重定位后,循环打印t的值。

注意这里在重定位前不能使用printf("before relocate")这样的操作,因为字符串"before relocate"是放在数据段中的,而程序中访问数据段的内容使用的是链接地址(0xD0024000之后),而这时程序还位于0xD0020010。具体怎么处理见代码。




start.S





[cpp] view plaincopy
01..global br_str              /* 声明全局标号 */  
02..global ar_str  
03..global _start  
04._start:  
05.    bl clock_init           /* 时钟初始化 */  
06.    bl uart_init            /* 串口初始化 */  
07.  
08.    adr r0, br_str          /* 取得br_str的当前地址(重定位之前) */  
09.    /* 调用C函数before_relocate,接收一个参数 */  
10.    bl before_relocate  
11.  
12.    /* 重定位 */  
13.    adr r0, _start          /* 相对寻址:取得_start的当前地址0xD0020010 */  
14.    ldr r1, =_start         /* 绝对寻址:取得_start的链接地址0xD0024000 */  
15.    ldr r2, =bss_start      /* bss段的起始地址 */  
16.    cmp r0, r1              /* 如果取得_start的当前地址和链接地址相等,则说明程序已经位于它的链接地址 */  
17.    beq clean_bss  
18.      
19.copy_loop:  
20.    ldr r3, [r0], #4    // 源  
21.    str r3, [r1], #4    // 目的  
22.    cmp r1, r2  
23.    bne copy_loop  
24.  
25.  
26.    /* 清bss段 */  
27.clean_bss:  
28.    ldr r0, =bss_start                    
29.    ldr r1, =bss_end  
30.    cmp r0, r1  
31.    beq relocate_done  
32.    /* 为什么这里要比较呢?
33.    ** 因为如果相等,则bss段没有数据,而这时如果进行下面的清bss段操作
34.    ** 首先执行“str r2, [r0], #4”后,r0加4,再执行“cmp r0, r1”就不相等了,这样一直循环。
35.    */  
36.  
37.    mov r2, #0  
38.1:  
39.    str r2, [r0], #4  
40.    cmp r0, r1  
41.    bne 1b          /* b是back的意思,代表向后跳转;如果向前跳转则使用f意思是forward */  
42.  
43.    /* 跳转 */  
44.relocate_done:            
45.    ldr pc, =main  
46.  
47.halt:  
48.    b halt  
49.  
50./* 定义一个字符串:.asciz会自动添加一个'\0',而ascii不会 */  
51.br_str:  
52.    .asciz "\nbefore relocate\n"  





types.h





[cpp] view plaincopy
01.#ifndef TYPES_H_  
02.#define TYPES_H_  
03.  
04.typedef volatile char           s8;  
05.typedef volatile short          s16;  
06.typedef volatile int            s32;  
07.  
08.typedef volatile unsigned char  u8;  
09.typedef volatile unsigned short u16;  
10.typedef volatile unsigned int   u32;  
11.  
12.#endif  



clock.c




[cpp] view plaincopy
01.#include <stdarg.h>  
02.#include "types.h"  
03.  
04.#define GPA0CON     *((volatile unsigned int *)0xE0200000)  
05.#define ULCON0      *((volatile unsigned int *)0xE2900000)  
06.#define UCON0       *((volatile unsigned int *)0xE2900004)  
07.#define UFCON0      *((volatile unsigned int *)0xE2900008)  
08.#define UTRSTAT0    *((volatile unsigned int *)0xE2900010)  
09.#define UTXH0       *((volatile unsigned int *)0xE2900020)  
10.#define URXH0       *((volatile unsigned int *)0xE2900024)  
11.#define UBRDIV0     *((volatile unsigned int *)0xE2900028)  
12.#define UDIVSLOT0   *((volatile unsigned int *)0xE290002C)  
13.  
14./*
15.** UART0初始化
16.*/  
17.void uart_init()  
18.{  
19.    /*
20.    ** 配置GPA0_0为UART_0_RXD
21.    ** 配置GPA0_1为UART_0_TXD
22.    */  
23.    GPA0CON &= ~0xFF;  
24.    GPA0CON |= 0x22;  
25.  
26.    /* 8-bits/One stop bit/No parity/Normal mode operation */  
27.    ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);  
28.  
29.    /* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/  
30.    UCON0 = 1 | (1 << 2) | (0 << 10);  
31.  
32.    /* 静止FIFO */  
33.    UFCON0 = 0;  
34.  
35.    /*
36.    ** 波特率计算:115200bps
37.    ** PCLK = 66MHz
38.    ** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
39.    ** UBRDIV0 = 34(DIV_VAL的整数部分)
40.    ** (num of 1's in UDIVSLOTn)/16 = 0.8
41.    ** (num of 1's in UDIVSLOTn) = 12
42.    ** UDIVSLOT0 = 0xDDDD (查表)
43.    */  
44.    UBRDIV0 = 34;  
45.    UDIVSLOT0 = 0xDDDD;  
46.}  
47.  
48./* 输出一字节的数据到终端 */  
49.void uart_send_byte(u8 byte)  
50.{  
51.    while (!(UTRSTAT0 & (1 << 2)));   /* 等待发送缓冲区为空 */  
52.    UTXH0 = byte;                   /* 发送一字节数据 */         
53.}  
54.  
55./* 从终端接收一字节数据 */  
56.u8 uart_recv_byte()  
57.{  
58.    while (!(UTRSTAT0 & 1));    /* 等待接收缓冲区有数据可读 */  
59.    return URXH0;               /* 接收一字节数据 */         
60.}  
61.  
62./* 打印字符c到终端 */  
63.void putchar(u8 c)  
64.{  
65.    uart_send_byte(c);  
66.    if (c == '\n')  
67.        uart_send_byte('\r');  
68.}  
69.  
70./* 打印字符串s到终端 */  
71.void puts(s8 *s)  
72.{  
73.    s8 *p = s;  
74.    while (*p)  
75.        putchar(*p++);  
76.}  
77.  
78./* 打印整数v到终端 */  
79.void put_int(u32 v)  
80.{  
81.    int i;  
82.    u8 a[10];  
83.    u8 cnt = 0;  
84.  
85.    if (v == 0)  
86.    {  
87.        putchar('0');  
88.        return;  
89.    }  
90.  
91.    while (v)  
92.    {  
93.        a[cnt++] = v % 10;  
94.        v /= 10;   
95.    }  
96.  
97.    for (i = cnt - 1; i >= 0; i--)  
98.        putchar(a + 0x30);  
99.    /*
100.    ** 整数0-9的ASCII分别为0x30-0x39
101.    */  
102.}  
103.  
104./* 将一字节十六进制数按十六进制显示打印到终端 */  
105.void put_hex(u8 v, u8 small)  
106.{  
107.    /* 注意:必须用volatile修饰,否则会出错 */  
108.    u8 h, l;        /* 高4位和第4位(这里按二进制算) */  
109.    char *hex1 = "0123456789abcdef";        /* 这里放在数据段中 */  
110.    char *hex2 = "0123456789ABCDEF";  
111.  
112.    h = v >> 4;  
113.    l = v & 0x0F;  
114.  
115.    if (small)  /* 小写 */  
116.    {  
117.        putchar(hex1[h]);   /* 高4位 */  
118.        putchar(hex1[l]);   /* 低4位 */  
119.    }  
120.    else        /* 大写 */  
121.    {  
122.        putchar(hex2[h]);   /* 高4位 */  
123.        putchar(hex2[l]);   /* 低4位 */  
124.    }  
125.}  
126.  
127./* 将int型整数按16进制打印到终端 */  
128.void put_int_hex(u32 v, u8 small)  
129.{  
130.    if (v >> 24)  
131.    {  
132.        put_hex(v >> 24, small);  
133.        put_hex((v >> 16) & 0xFF, small);  
134.        put_hex((v >> 8) & 0xFF, small);  
135.        put_hex(v & 0xFF, small);  
136.    }  
137.    else if ((v >> 16) & 0xFF)  
138.    {  
139.        put_hex((v >> 16) & 0xFF, small);  
140.        put_hex((v >> 8) & 0xFF, small);  
141.        put_hex(v & 0xFF, small);  
142.    }  
143.    else if ((v >> 8) & 0xFF)  
144.    {  
145.        put_hex((v >> 8) & 0xFF, small);  
146.        put_hex(v & 0xFF, small);  
147.    }  
148.    else  
149.        put_hex(v & 0xFF, small);  
150.}  
151.  
152./* 格式化输出到终端 */  
153.int printf(const char *fmt, ...)  
154.{  
155.    va_list ap;  
156.    s8 c;  
157.    s8 *s;  
158.    u32 d;  
159.    u8 small;  
160.  
161.    va_start(ap, fmt);  
162.    while (*fmt)  
163.    {  
164.        small = 0;  
165.        c = *fmt++;  
166.        if (c == '%')  
167.        {  
168.            switch (*fmt++)  
169.            {  
170.            case 'c':              /* char */  
171.                c = (char) va_arg(ap, int);  
172.                putchar(c);  
173.                break;  
174.            case 's':              /* string */  
175.                s = va_arg(ap, char *);  
176.                puts(s);  
177.                break;  
178.            case 'd':              /* int */  
179.            case 'u':  
180.                d = va_arg(ap, int);  
181.                put_int(d);  
182.                break;  
183.            case 'x':  
184.                small = 1;  // small  
185.            case 'X':  
186.                d = va_arg(ap, int);  
187.                put_int_hex(d, small);  
188.                break;  
189.            }  
190.        }  
191.        else  
192.            putchar(c);  
193.    }  
194.    va_end(ap);  
195.}  




[cpp] view plaincopy
01.#define APLLCON0        *((volatile unsigned int *)0xE0100100)  
02.#define MPLLCON         *((volatile unsigned int *)0xE0100108)  
03.#define EPLLCON0        *((volatile unsigned int *)0xE0100110)  
04.#define VPLLCON         *((volatile unsigned int *)0xE0100120)  
05.#define CLK_SRC0        *((volatile unsigned int *)0xE0100200)  
06.#define CLK_DIV0        *((volatile unsigned int *)0xE0100300)  
07.#define CLK_DIV1        *((volatile unsigned int *)0xE0100304)  
08.#define CLK_DIV2        *((volatile unsigned int *)0xE0100308)  
09.#define CLK_DIV3        *((volatile unsigned int *)0xE010030C)  
10.  
11.void clock_init()  
12.{  
13.    /* 1、设置PLL_LOCK寄存器(这里使用默认值) */  
14.    /* 2、设置PLL_CON寄存器(使用芯片手册推荐的值) */  
15.    APLLCON0    = (1 << 0) | (3 << 8) | (125 << 16) | (1 << 31);    /* FOUTAPLL = 1000MHz */  
16.    MPLLCON     = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);   /* FOUTMPLL = 667MHz */  
17.    EPLLCON0    = (1 << 0) | (12 << 8) | (667 << 16) | (1 << 31);   /* FOUTEPLL = 96MHz */  
18.    VPLLCON     = (3 << 0) | (6 << 8) | (108 << 16) | (1 << 31);    /* FOUTVPLL = 54MHz */  
19.      
20.    /* 3、选择PLL为时钟输出 */  
21.    /* MOUT_MSYS = SCLKAPLL = 1000MHz
22.    ** MOUT_DSYS = SCLKMPLL = 667MHz
23.    ** MOUT_PSYS = SCLKMPLL = 667MHz
24.    */  
25.    CLK_SRC0 = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 12);  
26.      
27.    /* 4、设置系统时钟分频值 */  
28.    /* freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz / (0 + 1) = 1000MHz
29.    ** freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 1000MHz / (4 + 1) = 200MHz
30.    ** freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 200MHz / (1 + 1) = 100MHz
31.    ** freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 667 / (3 + 1) = 166MHz
32.    ** freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 166 / (1 + 1) = 83MHz
33.    ** freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 667 / (4 + 1) = 133MHz
34.    ** freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 133 / (1 + 1) = 66MHz
35.    */  
36.    CLK_DIV0 = (0 << 0) | (4 << 8) | (1 << 12) | (3 << 16) | (1 << 20) | (4 << 24) | (1 << 28);  
37.}  





uart.c





[cpp] view plaincopy
01.#include <stdarg.h>  
02.#include "types.h"  
03.  
04.#define GPA0CON     *((volatile unsigned int *)0xE0200000)  
05.#define ULCON0      *((volatile unsigned int *)0xE2900000)  
06.#define UCON0       *((volatile unsigned int *)0xE2900004)  
07.#define UFCON0      *((volatile unsigned int *)0xE2900008)  
08.#define UTRSTAT0    *((volatile unsigned int *)0xE2900010)  
09.#define UTXH0       *((volatile unsigned int *)0xE2900020)  
10.#define URXH0       *((volatile unsigned int *)0xE2900024)  
11.#define UBRDIV0     *((volatile unsigned int *)0xE2900028)  
12.#define UDIVSLOT0   *((volatile unsigned int *)0xE290002C)  
13.  
14./*
15.** UART0初始化
16.*/  
17.void uart_init()  
18.{  
19.    /*
20.    ** 配置GPA0_0为UART_0_RXD
21.    ** 配置GPA0_1为UART_0_TXD
22.    */  
23.    GPA0CON &= ~0xFF;  
24.    GPA0CON |= 0x22;  
25.  
26.    /* 8-bits/One stop bit/No parity/Normal mode operation */  
27.    ULCON0 = 0x3 | (0 << 2) | (0 << 3) | (0 << 6);  
28.  
29.    /* Interrupt request or polling mode/Normal transmit/Normal operation/PCLK/*/  
30.    UCON0 = 1 | (1 << 2) | (0 << 10);  
31.  
32.    /* 静止FIFO */  
33.    UFCON0 = 0;  
34.  
35.    /*
36.    ** 波特率计算:115200bps
37.    ** PCLK = 66MHz
38.    ** DIV_VAL = (66000000/(115200 x 16))-1 = 35.8 - 1 = 34.8
39.    ** UBRDIV0 = 34(DIV_VAL的整数部分)
40.    ** (num of 1's in UDIVSLOTn)/16 = 0.8
41.    ** (num of 1's in UDIVSLOTn) = 12
42.    ** UDIVSLOT0 = 0xDDDD (查表)
43.    */  
44.    UBRDIV0 = 34;  
45.    UDIVSLOT0 = 0xDDDD;  
46.}  
47.  
48./* 输出一字节的数据到终端 */  
49.void uart_send_byte(u8 byte)  
50.{  
51.    while (!(UTRSTAT0 & (1 << 2)));   /* 等待发送缓冲区为空 */  
52.    UTXH0 = byte;                   /* 发送一字节数据 */         
53.}  
54.  
55./* 从终端接收一字节数据 */  
56.u8 uart_recv_byte()  
57.{  
58.    while (!(UTRSTAT0 & 1));    /* 等待接收缓冲区有数据可读 */  
59.    return URXH0;               /* 接收一字节数据 */         
60.}  
61.  
62./* 打印字符c到终端 */  
63.void putchar(u8 c)  
64.{  
65.    uart_send_byte(c);  
66.    if (c == '\n')  
67.        uart_send_byte('\r');  
68.}  
69.  
70./* 打印字符串s到终端 */  
71.void puts(s8 *s)  
72.{  
73.    s8 *p = s;  
74.    while (*p)  
75.        putchar(*p++);  
76.}  
77.  
78./* 打印整数v到终端 */  
79.void put_int(u32 v)  
80.{  
81.    int i;  
82.    u8 a[10];  
83.    u8 cnt = 0;  
84.  
85.    if (v == 0)  
86.    {  
87.        putchar('0');  
88.        return;  
89.    }  
90.  
91.    while (v)  
92.    {  
93.        a[cnt++] = v % 10;  
94.        v /= 10;   
95.    }  
96.  
97.    for (i = cnt - 1; i >= 0; i--)  
98.        putchar(a + 0x30);  
99.    /*
100.    ** 整数0-9的ASCII分别为0x30-0x39
101.    */  
102.}  
103.  
104./* 将一字节十六进制数按十六进制显示打印到终端 */  
105.void put_hex(u8 v, u8 small)  
106.{  
107.    /* 注意:必须用volatile修饰,否则会出错 */  
108.    u8 h, l;        /* 高4位和第4位(这里按二进制算) */  
109.    char *hex1 = "0123456789abcdef";        /* 这里放在数据段中 */  
110.    char *hex2 = "0123456789ABCDEF";  
111.  
112.    h = v >> 4;  
113.    l = v & 0x0F;  
114.  
115.    if (small)  /* 小写 */  
116.    {  
117.        putchar(hex1[h]);   /* 高4位 */  
118.        putchar(hex1[l]);   /* 低4位 */  
119.    }  
120.    else        /* 大写 */  
121.    {  
122.        putchar(hex2[h]);   /* 高4位 */  
123.        putchar(hex2[l]);   /* 低4位 */  
124.    }  
125.}  
126.  
127./* 将int型整数按16进制打印到终端 */  
128.void put_int_hex(u32 v, u8 small)  
129.{  
130.    if (v >> 24)  
131.    {  
132.        put_hex(v >> 24, small);  
133.        put_hex((v >> 16) & 0xFF, small);  
134.        put_hex((v >> 8) & 0xFF, small);  
135.        put_hex(v & 0xFF, small);  
136.    }  
137.    else if ((v >> 16) & 0xFF)  
138.    {  
139.        put_hex((v >> 16) & 0xFF, small);  
140.        put_hex((v >> 8) & 0xFF, small);  
141.        put_hex(v & 0xFF, small);  
142.    }  
143.    else if ((v >> 8) & 0xFF)  
144.    {  
145.        put_hex((v >> 8) & 0xFF, small);  
146.        put_hex(v & 0xFF, small);  
147.    }  
148.    else  
149.        put_hex(v & 0xFF, small);  
150.}  
151.  
152./* 格式化输出到终端 */  
153.int printf(const char *fmt, ...)  
154.{  
155.    va_list ap;  
156.    s8 c;  
157.    s8 *s;  
158.    u32 d;  
159.    u8 small;  
160.  
161.    va_start(ap, fmt);  
162.    while (*fmt)  
163.    {  
164.        small = 0;  
165.        c = *fmt++;  
166.        if (c == '%')  
167.        {  
168.            switch (*fmt++)  
169.            {  
170.            case 'c':              /* char */  
171.                c = (char) va_arg(ap, int);  
172.                putchar(c);  
173.                break;  
174.            case 's':              /* string */  
175.                s = va_arg(ap, char *);  
176.                puts(s);  
177.                break;  
178.            case 'd':              /* int */  
179.            case 'u':  
180.                d = va_arg(ap, int);  
181.                put_int(d);  
182.                break;  
183.            case 'x':  
184.                small = 1;  // small  
185.            case 'X':  
186.                d = va_arg(ap, int);  
187.                put_int_hex(d, small);  
188.                break;  
189.            }  
190.        }  
191.        else  
192.            putchar(c);  
193.    }  
194.    va_end(ap);  
195.}  

main.c






[cpp] view plaincopy
01.#include "uart.h"  
02.#include "types.h"  
03.  
04.void delay(u32 t)  
05.{  
06.    u32 t2 = 0xFFFF;  
07.    while (t--)  
08.        for (; t2; t2--);  
09.}  
10.  
11.void before_relocate(u32 addr)  
12.{  
13.    char *p = (char *)addr;  
14.    puts(p);  
15.}  
16.  
17.int main()  
18.{  
19.    u32 t = 0;  
20.    printf("\nafter relocate\n\n");  
21.    while (1)  
22.    {  
23.        printf("t = %d\n", t++);  
24.        delay(1000000);  
25.    }  
26.    return 0;  
27.}  

link.lds(链接脚本)





[cpp] view plaincopy
01.SECTIONS  
02.{  
03.    . = 0xD0024000;  
04.      
05.    .text : {  
06.        start.o  
07.        * (.text)  
08.    }  
09.              
10.    .data : {  
11.        * (.data)  
12.    }  
13.      
14.    bss_start = .;   
15.    .bss : {  
16.        * (.bss)  
17.    }  
18.      
19.    bss_end  = .;     
20.}  

Makefile

uart.bin: start.o clock.o uart.o main.o
     arm-linux-ld -Tlink.lds -o uart.elf $^
     arm-linux-objcopy -O binary uart.elf $@
     arm-linux-objdump -D uart.elf > uart.dis
     
%.o : %.c
     arm-linux-gcc -c $< -o $@
%.o : %.S
     arm-linux-gcc -c $< -o $@
     
clean:
     rm *.o *.elf *.bin *.dis

烧写过程见《TQ210裸机编程(5)——系统时钟配置》

转载请注明来源:http://blog.csdn.net/zjhsucceed_329/
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-4-20 21:50 , Processed in 1.031243 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表