概述
一、mips架构通用寄存器命名
二、mips汇编指令操作
1、指令集
2、实例:
#example
.data
array1: .space 12 # declare 12 bytes of storage
# to hold array of 3 integers
.text
__start:
la $t0, array1 # load base address of array
# into register
$t0 li $t1, 5 # $t1 = 5 ("load immediate")
sw $t1, ($t0) # first array element set to 5
# indirect addressing
li $t1, 13 # $t1 = 13
sw $t1, 4($t0) # second array element set to 13
li $t1, -7 # $t1 = -7
sw $t1, 8($t0) # third array element set to -7
start.s汇编分析
mtc0 zero, CP0_WATCHLO
mtc0 zero, CP0_WATCHHI 清除硬件数据断点,防止产生调试断点,导致程序停止。
芯片在复位后,某些寄存器的内容也许是你想要的结果,但是谁知道呢,为了保证准确无误,最好还是重新进行手动初始化
mfc0 k0, CP0_STATUS
li k1, ~ST0_IE
and k0, k1
mtc0 k0, CP0_STATUS 禁止全局中断
mtc0 zero, CP0_CAUSE 初始化异常寄存器,清除异常原因指示
mtc0 zero, CP0_COUNT
mtc0 zero, CP0_COMPARE
初始化时钟寄存器,防止产生计数器中断
li t0, CONF_CM_UNCACHED
mtc0 t0, CP0_CONFIG
设置kseg0区不经过cache。cache需要先初始化才能使用。
bal 1f
nop
.word _gp
1:
lw gp, 0(ra)
bal分支调用,ra返回地址指向下下一条指令,即.word _gp
把.word _gp的存储位置载入gp寄存器,即设置GOT表的起始位置
la t9, lowlevel_init
jalr t9
nop
根据CPU rate初始化外部时钟、内存。
lowlevel_init函数定义见lowlevel_init.S
la t9, mips_cache_reset
jalr t9
nop
初始化高速缓存cache。
mips_cache_reset函数定义见cache.S
li t0, CONF_CM_CACHABLE_NONCOHERENT
mtc0 t0, CP0_CONFIG
设置kseg0区经过cache
li a0, CFG_INIT_SP_OFFSET
la t9, mips_cache_lock
jalr t9
nop
li t0, CFG_SDRAM_BASE +
CFG_INIT_SP_OFFSET
la sp, 0(t0)
C语言程序(接下来的函数board_init_f)调用需要栈,而ram还没有初始化不能使用,所以用CACHE_LOCK_SIZE大小的L1 Dcache锁定作为临时栈使用
以sp开始,CACHE_LOCK_SIZE大小的堆栈,使用
D-cache临时替代
la t9, board_init_f 初始化
j t9
nop
board_init_f函数定义见board
relocate_code: 对应board.c里的relocate_code (addr_sp, id, addr),此时a0=addr_sp,a1=id,a3=addr。
move sp, a0 设置新的sp = addr_sp
li t0, CFG_MONITOR_BASE board/xxx/config.mk #define CFG_MONITOR_BASE TEXT_BASE
board/xxx/config.mk #define CFG_MONITOR_BASE TEXT_BASE
la t3, in_ram t0 = uboot程序在flash的超始地址,t1 = 准备把uboot程序移到ram中的起始地址
lw t2, -12(t3) t2 = uboot程序的结束地址
move t1, a2
move t6, gp
sub gp, CFG_MONITOR_BASE 计算旧的gp与相对于TEXT_BASE的偏移
add gp, a2 计算新的gp在移动目的地内存中的地址
sub t6, gp, t6 t6 = 新gp(内存中)与旧gp(flash中)的地址偏移量,这个值也是整个uboot从flash移到内存的偏移量。等同于(Destination Address - CFG_MONITOR_BASE)
1:
lw t3, 0(t0)
sw t3, 0(t1)
addu t0, 4
ble t0, t2, 1b
addu t1, 4
按字拷贝,把uboot bin的内容从源地址(flash)拷贝到目的地址(内存),拷贝的长度是从uboot开始到uboot_end_data为止,uboot_end_data后面是bss段,详见uboot.lds
addi t0, a2, in_ram - _start
j t0
nop
计算in_ram在内存中的新地址保存到t0,然后跳转到内存中运行in_ram。从此开始,uboot的代码将在ram中运行了
.gpword_GLOBAL_OFFSET_TABLE
.word uboot_end_data
.word uboot_end
.word num_got_entries
in_ram:
t3 = num_got_entries,t4 = 新的GOT[2]
li t2, 2
1:
lw t1, 0(t4)
beqz t1, 2f
add t1, t6
sw t1, 0(t4)
2:
addi t2, 1
blt t2, t3, 1b
addi t4, 4
这里是一个循环,从GOT[2]开始,判断如果GOT表项有内容,则把内容从旧的GOT表拷贝到新的GOT表里。为什么要做拷贝呢?上面的程序已经把uboot整个程序从
flash拷贝到了ram里,注意,只是内容拷贝,GOT里的地址还是老地址,所以要做重定位(如果是静态编译且属于模块内相对偏移,就不需要这个步骤了)。手工重定位
的方法就是把旧GOT里的内容读取,然后加上偏移(uboot在flash与ram的偏移)赋值给新GOT里的对应表项
程序构建过程(编译和生成程序时的链接)为每个链接单元(构成动态链接程序的二进制文件,如.o、.a、.so)至少定义一个GOT,每个函数都可以找到自己的GOT,因为
GOT的位置离链接单元的入口点的偏移量是固定已知的。链接单元作为一个整体载入内存,所以GOT的内部偏移量与编译时是一样的。
u-boot在编译时使用-fpic,会生成一个.got段来存储绝对地址符号。
lw t1, -12(t0)
lw t2, -8(t0)
add t1, t6
add t2, t6
sub t1, 4
1:
addi t1, 4
bltl t1, t2, 1b
sw zero, 0(t1)
t1 = uboot_end_data, t2 = uboot_end
进行BSS段的清零,此时还没有操作系统,动态链接器,加载器等这些东东都还没有,所以要手动执行清零
move a0, a1
la t9, board_init_r
j t9
move a1, a2
跳转到ram中的board_init_r执行,根据MIPS ABI规范,a0、a1分别是board_init_r的第一个、第二个参数,即board_init_r (gd_t *id, ulong dest_addr)中id = a0,
dest_addr = a2
t0 = uboot程序在flash的超始地址,t1 = 准备把uboot程序移到ram中的起始地址
lw t2, -12(t3) t2 = uboot程序的结束地址
move t1, a2
move t6, gp
sub gp, CFG_MONITOR_BASE 计算旧的gp与相对于TEXT_BASE的偏移
add gp, a2 计算新的gp在移动目的地内存中的地址
sub t6, gp, t6 t6 = 新gp(内存中)与旧gp(flash中)的地址偏移量,这个值也是整个uboot从flash移到内存的偏移量。等同于(Destination Address - CFG_MONITOR_BASE)
1:
lw t3, 0(t0)
sw t3, 0(t1)
addu t0, 4
ble t0, t2, 1b
addu t1, 4
按字拷贝,把uboot bin的内容从源地址(flash)拷贝到目的地址(内存),拷贝的长度是从uboot开始到uboot_end_data为止,uboot_end_data后面是bss段,详见uboot.lds
addi t0, a2, in_ram - _start
j t0
nop
计算in_ram在内存中的新地址保存到t0,然后跳转到内存中运行in_ram。从此开始,uboot的代码将在ram中运行了
.gpword_GLOBAL_OFFSET_TABLE
.word uboot_end_data
.word uboot_end
.word num_got_entries
in_ram:
t3 = num_got_entries,t4 = 新的GOT[2]
li t2, 2
1:
lw t1, 0(t4)
beqz t1, 2f
add t1, t6
sw t1, 0(t4)
2:
addi t2, 1
blt t2, t3, 1b
addi t4, 4
这里是一个循环,从GOT[2]开始,判断如果GOT表项有内容,则把内容从旧的GOT表拷贝到新的GOT表里。为什么要做拷贝呢?上面的程序已经把uboot整个程序从
flash拷贝到了ram里,注意,只是内容拷贝,GOT里的地址还是老地址,所以要做重定位(如果是静态编译且属于模块内相对偏移,就不需要这个步骤了)。手工重定位
的方法就是把旧GOT里的内容读取,然后加上偏移(uboot在flash与ram的偏移)赋值给新GOT里的对应表项
程序构建过程(编译和生成程序时的链接)为每个链接单元(构成动态链接程序的二进制文件,如.o、.a、.so)至少定义一个GOT,每个函数都可以找到自己的GOT,因为
GOT的位置离链接单元的入口点的偏移量是固定已知的。链接单元作为一个整体载入内存,所以GOT的内部偏移量与编译时是一样的。
u-boot在编译时使用-fpic,会生成一个.got段来存储绝对地址符号。
lw t1, -12(t0)
lw t2, -8(t0)
add t1, t6
add t2, t6
sub t1, 4
1:
addi t1, 4
bltl t1, t2, 1b
sw zero, 0(t1)
t1 = uboot_end_data, t2 = uboot_end
进行BSS段的清零,此时还没有操作系统,动态链接器,加载器等这些东东都还没有,所以要手动执行清零
move a0, a1
la t9, board_init_r
j t9
move a1, a2
跳转到ram中的board_init_r执行,根据MIPS ABI规范,a0、a1分别是board_init_r的第一个、第二个参数,即board_init_r (gd_t *id, ulong dest_addr)中id = a0,
dest_addr = a2
最后
以上就是踏实芝麻为你收集整理的MIPS架构之start.s汇编分析的全部内容,希望文章能够帮你解决MIPS架构之start.s汇编分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复