实验(6)位置无关跳转bl的深入理解

实验目的:连接地址非零,使用位置无关跳转bl指令,实现函数的顺利跳入,连接地址非零(连接地址为0x00000008),不搬移代码,但能进入主函数和中断。

代码清单:

(1)head.S

@**************************************************************************

@ File:head.S

@功能:初始化,设置中断模式、系统模式的栈,设置好中断处理函数

@**************************************************************************

.extern main

.text

.global _start

_start:

@**************************************************************************

@中断向量,本程序中,除Reset和HandleIRQ外,其他异常都没有使用

@**************************************************************************

@0x00地址处的指令为"b Reset",在系统复位后,这条指令将跳去执行标号"Reset"开始的代码

b Reset

@0x04:未定义指令终止模式的向量地址

HandleUndef:

b HandleUndef

@0x08:管理模式的向量地址,通过SWI指令进入此模式

HandleSWI:

b HandleSWI

@0x0c:指令预取终止导致的异常的向量地址

HandlePrefetchAbort:

b HandlePrefetchAbort

@0x10:数据访问终止导致的异常的向量地址

HandleDataAbort:

b HandleDataAbort

@0x14:保留

HandleNotUsed:

b HandleNotUsed

@0x18:中断模式的向量地址

b HandleIRQ

@0x1c:快中断模式的向量地址

HandleFIQ:

b HandleFIQ

HandleIRQ: @HandleIRQ开始的代码用于处理中断

sub lr,lr,#4 @计算中断处理完毕后的返回地址

stmdb sp!,{r0-r12,lr} @保存使用到的寄存器

bl EINT_Handle @调用中断服务函数,在interrupt.c中

ldmia sp!,{r0-r12,pc}^ @中断返回,^表示将spsr的值复制到cpsr

Reset:

ldr sp,=4096

@设置栈指针,以下都是C函数,调用前需要设好栈。栈是用 @来保存C函数的变量和返回地址

bl disable_watch_dog @关闭WATCHDOG,否则CPU会不断重启

msr cpsr_c, #0xd2@进入中断模式

ldr sp, =3072@设置中断模式栈指针

msr cpsr_c, #0xdf @进入系统模式

ldr sp, =4096@设置系统模式栈指针,

bl init_led@初始化LED的GPIO管脚

bl init_irq@调用中断初始化函数,在init.c中

msr cpsr_c, #0x5f@设置I-bit=0,开IRQ中断

bl main@调用main函数,千万不要用ldr pc,=main,这样会导致找不到main的情况

(2)int.c

#include "s3c24xx.h"

#define GPB5_out (1<<(5*2))

#define GPB6_out (1<<(6*2))

#define GPB7_out (1<<(7*2))

#define GPB8_out (1<<(8*2))

#define GPB0_timer0 (2<<(0*2))

#define GPB5_msk(3<<(5*2))

#define GPB6_msk(3<<(6*2))

#define GPB7_msk(3<<(7*2))

#define GPB8_msk(3<<(8*2))

#define GPF0_eint (0x2<<(0*2))

#define GPF1_eint (0x2<<(1*2))

#define GPF2_eint (0x2<<(2*2))

#define GPF4_eint (0x2<<(4*2))

#define GPF0_msk (3<<(0*2))

#define GPF1_msk (3<<(1*2))

#define GPF2_msk (3<<(2*2))

#define GPF4_msk (3<<(4*2))

#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))

#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))

#define PCLK (50000000)

void disable_watch_dog(void)

{

WTCON = 0;

}

void init_led(void)

{

GPBCON&=~(GPB5_msk|GPB6_msk|GPB7_msk|GPB8_msk);

GPBCON|=GPB5_out|GPB6_out|GPB7_out|GPB8_out;

GPBDAT|=0x0f<<5;

}

void init_irq( )

{

GPFCON&=~(GPF0_msk|GPF1_msk|GPF2_msk|GPF4_msk);

GPFCON|=GPF0_eint|GPF1_eint|GPF2_eint|GPF4_eint;

EINTMASK&=~(1<<4);

PRIORITY&=(~(1<<6))&(~(1<<1))&(~(1<<0));

INTMSK &=(~(1<<0))&(~(1<<1))&(~(1<<2))&(~(1<<4));

}

void memsetup(void)

{

volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

p[0] = 0x22011110;//BWSCON

}

(3)interrupt.c

#include "s3c24xx.h"

int EINT_Handle()

{

unsigned long oft = INTOFFSET;

GPBDAT=~(0x0f<<5);

if( oft == 4 )

EINTPEND = (1<<4); // EINT8_23ºÏÓÃIRQ5

SRCPND = 1<<oft;

INTPND = 1<<oft;

return 0;

}

(4) s3c24xx.h

/* WOTCH DOG register */

#define WTCON (*(volatile unsigned long *)0x53000000)

/* SDRAM regisers */

#define MEM_CTL_BASE 0x48000000

#define SDRAM_BASE 0x30000000

/* NAND Flash registers */

#define NFCONF (*(volatile unsigned int *)0x4e000000)

#define NFCMD (*(volatile unsigned char *)0x4e000004)

#define NFADDR (*(volatile unsigned char *)0x4e000008)

#define NFDATA (*(volatile unsigned char *)0x4e00000c)

#define NFSTAT (*(volatile unsigned char *)0x4e000010)

/*GPIO registers*/

#define GPBCON (*(volatile unsigned long *)0x56000010)

#define GPBDAT (*(volatile unsigned long *)0x56000014)

#define GPFCON (*(volatile unsigned long *)0x56000050)

#define GPFDAT (*(volatile unsigned long *)0x56000054)

#define GPFUP (*(volatile unsigned long *)0x56000058)

#define GPGCON (*(volatile unsigned long *)0x56000060)

#define GPGDAT (*(volatile unsigned long *)0x56000064)

#define GPGUP (*(volatile unsigned long *)0x56000068)

#define GPHCON (*(volatile unsigned long *)0x56000070)

#define GPHDAT (*(volatile unsigned long *)0x56000074)

#define GPHUP (*(volatile unsigned long *)0x56000078)

/*UART registers*/

#define ULCON0 (*(volatile unsigned long *)0x50000000)

#define UCON0 (*(volatile unsigned long *)0x50000004)

#define UFCON0 (*(volatile unsigned long *)0x50000008)

#define UMCON0 (*(volatile unsigned long *)0x5000000c)

#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)

#define UTXH0 (*(volatile unsigned char *)0x50000020)

#define URXH0 (*(volatile unsigned char *)0x50000024)

#define UBRDIV0 (*(volatile unsigned long *)0x50000028)

/*interrupt registes*/

#define SRCPND (*(volatile unsigned long *)0x4A000000)

#define INTMOD (*(volatile unsigned long *)0x4A000004)

#define INTMSK (*(volatile unsigned long *)0x4A000008)

#define PRIORITY (*(volatile unsigned long *)0x4A00000c)

#define INTPND (*(volatile unsigned long *)0x4A000010)

#define INTOFFSET (*(volatile unsigned long *)0x4A000014)

#define SUBSRCPND (*(volatile unsigned long *)0x4A000018)

#define INTSUBMSK (*(volatile unsigned long *)0x4A00001c)

/*external interrupt registers*/

#define EINTMASK(*(volatile unsigned long *)0x560000a4)

#define EINTPEND(*(volatile unsigned long *)0x560000a8)

/*clockregisters*/

#define LOCKTIME (*(volatile unsigned long*)0x4c000000)

#define MPLLCON (*(volatile unsigned long*)0x4c000004)

#define UPLLCON (*(volatile unsigned long*)0x4c000008)

#define CLKCON (*(volatile unsigned long*)0x4c00000c)

#define CLKSLOW (*(volatile unsigned long*)0x4c000010)

#define CLKDIVN (*(volatile unsigned long*)0x4c000014)

/*PWM&Timerregisters*/

#define TCFG0 (*(volatile unsigned long*)0x51000000)

#define TCFG1 (*(volatile unsigned long*)0x51000004)

#define TCON(*(volatile unsigned long*)0x51000008)

#define TCNTB0(*(volatile unsigned long*)0x5100000c)

#define TCMPB0 (*(volatile unsigned long*)0x51000010)

#define TCNTO0 (*(volatile unsigned long*)0x51000014)

#define GSTATUS1(*(volatile unsigned long*)0x560000B0)

#define U16 unsigned short int

(5)makefile:

ARCH = arm

-mcpu=s3c2440

objs := head.o init.o interrupt.o main.o

int.bin: $(objs)

arm-linux-ld -Ttext 0x00000008 -o int_elf $^

arm-linux-objcopy -O binary -S int_elf int.bin

arm-linux-objdump -D -m arm int_elf > int.dis

%.o:%.c

arm-linux-gcc -nostdlib -g -c -o $@ $<

%.o:%.S

arm-linux-gcc -nostdlib -g -c -o $@ $<

clean:

rm -f int.bin int_elf int.dis *.o

Q&A:

实验思考:

(1)为什么没有把代码搬移到对应的运行地址上,却能进入主函数呢?原因在于跳入主函数的时候采取与位置无关的跳转指令bl。

(2)为什么能顺利进入中断响应中断函数,因为代码被自动搬移到SRAM的时候,加载地址就是从0开始的,一旦中断发生,pc直接跳入到0x00000018上,用位置无关跳转指令b HandleIRQ,即可进入中断处理函数中。

(3)如果把b HandleIRQ改成ldr pc,= HandleIRQ,还能否进入中断?

(4)本实验连接地址和加载地址不一致,但是缺能顺利进入主函数,也能顺利进入中断,关键原因是利用与位置无关的跳转,那么什么是与位置无关呢?

(5)请对比实验4和实验5,体会三个实验的区别和联系

(6)查阅网络资源,将所有与位置无关的跳转指令列出来。

e

results matching ""

    No results matching ""

    results matching ""

      No results matching ""