参考ARM的arm汇编指令令,分析下面的代码,并添加适当的中文注释说明。

Boot中执行下面两句话之后,进入uclinux;theKernel=(void(*)(int,i;1start_kernel之前的汇编代码分析;首先来到0x处,此时携带有三个参;①@后面的内容标示是注释语句;②ARM或者THUMB指令的选取,在\\incl;③偏移量#PROC_INFO_SZ等,在\\in;1.1head-mommu.S;文
Boot中执行下面两句话之后,进入uclinux内核。 theKernel = (void (*)(int, int, unsigned int))((uint32_t)0x); theKernel(0, 2189, ((uint32_t)0x)); 1 start_kernel之前的汇编代码分析 首先来到0x处,此时携带有三个参数,R0、R1、R2,分别是0,0 0 3000对应着下面stext的汇编代码。 代码阅读说明: ① @后面的内容标示是注释语句 ② ARM或者THUMB指令的选取,在\\include\\asm-arm\%unified.h中,定义了使用ARM,THUMB为空 ③ 偏移量#PROC_INFO_SZ等,在\\include\\asm\\asm-offset.h中宏定义 1.1
head-mommu.S 文件在arch\\arm\\kernel\\head-nommu.S,text.head段,有stext、__after_proc_init两段组成,内核从这里开始启动,然后通过各种调用,最终进入C语言的start_kernel函数,这段代码执行流程如下: (1) 调用__lookup_processor_type,传入R9(CPU基址寄存器的值),成功后获得当前的proc_info结构体信息,地址放入R10; (2) 调用__lookup_machine_type,BootLoader传给内核的R1值,成功后获得当前的machine_desc结构体信息,地址放入R8; (3) 执行__v7m_setup,进行必要的初始化; (4) 执行__switch_data,并最终跳转到C语言的start_kernel函数。
.section \ENTRY(stext)
@ disable interrupts //cortex-M3特殊指令,关闭所有中断
ldr r9, =0xe000ed00
@ CPUID register address
ldr r9, [r9]
//CPUID基址寄存器,参考手册(周立功)-P80
bl __lookup_processor_type
@ r5=procinfo r9=cupid
//head-common.S
movs r10, r5
@ invalid processor (r5=0)?
beq __error_p
@ yes, error 'p'
bl __lookup_machine_type
@ r5=machinfo
movs r8, r5
@ invalid machine (r5=0)?
beq __error_a
@ yes, error 'a'
badr lr, __after_proc_init
@ return (PIC) address
//提前暂存lr的值
ARM( add pc, r10, #PROCINFO_INITFUNC ) //R10处偏移16个字节,然后赋给PC
//相当于跳转到下面的__v7m_setup ENDPROC(stext)
__after_proc_init:
ldr pc,__switch_data
ENDPROC(__after_proc_init)
.ltorg #include \
//将PC 指针赋值到__switch_data标号地址处,实际执行的 //是在__mmap_switched这个标号处 //末尾包含下面的文件 1.2
head-common.S 文件在arch\\arm\\kernel\\head-common.S,有__switch_data、__mmap_switched、__error_p、__error_a、__error、__lookup_processor_type、C语言的lookup_processor_type、__lookup_machine_type 、C语言的lookup_machine_type、__vet_atags等组成,这里只列出上面调用要使用的查找处理器类型和查找机器类型。
_lookup_processor_type:
//r9是刚从CPU基址寄存器中取出的值
ARM( adr r3, 3f
) //执行此句后,r3的地址是后面标号3处的地址
ARM( ldmda r3, {r5 - r7} )//r5,r6,r7依次变为,__proc_info_begin,end,以及
//标号3处的末尾链接地址
sub r3, r3, r7
@ get offset between virt&phys //这三行执行虚实地址转换
add r5, r5, r3
@ convert virt addresses to//r5是proc_info_list结构体地址
add r6, r6, r3
@ physical address space //__proc_info_end的自己 1: ldmia r5, {r3, r4}
@ value, mask
//r3是结构体的val变量
and r4, r4, r9
@ mask wanted bits
//r4是结构体的mask变量
teq r3, r4
//相等转到后面的2标号处
add r5, r5, #PROC_INFO_SZ
@ sizeof(proc_info_list) //宏定义在asm-offset.h
cmp r5, r6
//结构体可能是个数组,需要全部查找,若r5的地址没有超出end
//的地址,则继续转到1处理,若最后没找到,r5变为空
mov r5, #0
@ unknown processor 2: mov pc, lr ENDPROC(__lookup_processor_type)
ENTRY(lookup_processor_type)
stmfd sp!, {r4 - r7, r9, lr}
mov r9, r0
//提供C语言的API结构,r0是传入的参数
bl __lookup_processor_type
mov r0, r5
//此处的R0是函数的返回值,即传出的参数
ldmfd sp!, {r4 - r7, r9, pc} ENDPROC(lookup_processor_type)
.long __proc_info_begin
//arch/arm/kernel/vmlinux.lds.s中定义
.long __proc_info_end 3: .long .
.long __arch_info_begin
.long __arch_info_end
* Lookup machine architecture in the linker-build list of architectures.
* Note that we can't use the absolute addresses for the __arch_info
* lists since we aren't running with the MMU on (and therefore, we are
* not in the correct address space).
We have to calculate the offset.
r1 = machine architecture number
* Returns:
r3, r4, r6 corrupted
r5 = mach_info pointer in physical address space
*/ __lookup_machine_type:
adr r3, 3b
ldmia r3, {r4, r5, r6} //r5是__arch_info_begin,r6是end
sub r3, r3, r4
@ get offset between virt&phys //虚实地址转换
add r5, r5, r3
@ convert virt addresses to
add r6, r6, r3
@ physical address space 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type //结构体偏移字节数,见上面的注释
teq r3, r1
@ matches loader number? //与传递给内核的r1相同
//r3就是结构体中第一个变量nr
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
mov r5, #0
@ unknown machine 2: mov pc, lr ENDPROC(__lookup_machine_type)
* This provides a C-API version of the above function.
*/ ENTRY(lookup_machine_type)
stmfd sp!, {r4 - r6, lr}
mov r1, r0
//提供C语言的API结构,r0是传入的参数
bl __lookup_machine_type
mov r0, r5
//此处的R0是函数的返回值,即传出的参数
ldmfd sp!, {r4 - r6, pc} ENDPROC(lookup_machine_type) 1.2.1 lookup_processor_type (1)vmlinux.lds.s 文件在arch\\arm\\kernel\\ vmlinux.lds.s __proc_info_begin = .;
//include/asm-arm/procinfo.h中定义
__proc_info_end = .;
__arch_info_begin = .;
*(..init) __arch_info_end = .;
//include/asm-arm/mach/arch.h 中定义 (2)procinfo.h 文件在include/asm-arm/procinfo.h struct proc_info_list {
// pro-v7m.S对其实例化
unsigned int
unsigned int
unsigned long
__cpu_mm_mmu_ /* used by head.S */
unsigned long
__cpu_io_mmu_ /* used by head.S */
unsigned long
/* used by head.S */
const char
const char
unsigned int
const char
struct processor *
struct cpu_tlb_fns *
struct cpu_user_fns *
struct cpu_cache_fns * }; (3)pro-v7m.S 文件在arch\\arm\\mm\\ pro-v7m.S,内容很多,核心就是.section \,其它的都是它这个结构体中得成员,如__v7m_setup、cpu_arch_name、cpu_elf_name、cpu_v7m_name、v7m_processor_functions等。 cpu_v7m_name:
.ascii \ .align
.section \ .type v7m_processor_functions, #object ENTRY(v7m_processor_functions)
.word v7m_early_abort
.word cpu_v7m_proc_init
.word cpu_v7m_proc_fin
.word cpu_v7m_reset
.word cpu_v7m_do_idle
.word cpu_v7m_dcache_clean_area
.word cpu_v7m_switch_mm
.word cpu_v7m_set_pte_ext
.word pabort_noifar
.size v7m_processor_functions, . - v7m_processor_functions
.type cpu_arch_name, #object cpu_arch_name:
.asciz \ .size cpu_arch_name, . - cpu_arch_name
.type cpu_elf_name, #object cpu_elf_name:
.asciz \ .size cpu_elf_name, . - cpu_elf_name
.section \ /*
* Match any ARMv7-M processor core.
.type __v7m_proc_info, #object __v7m_proc_info:
//E000ED00是CPUID基址寄存器,其中[19:16]读作常量F
.long 0x000f0000
@ Required ID value
.long 0x000f0000
@ Mask for ID
@ proc_info_list.__cpu_mm_mmu_flags
@ proc_info_list.__cpu_io_mmu_flags
b __v7m_setup
@ proc_info_list.__cpu_flush
.long cpu_arch_name
.long cpu_elf_name
HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
.long cpu_v7m_name
.long v7m_processor_functions @ proc_info_list.proc
@ proc_info_list.tlb
@ proc_info_list.user
@ proc_info_list.cache
.size __v7m_proc_info, . - __v7m_proc_info 1.2.2 lookup_machine_type (1)arch.h 文件在include/asm-arm/mach/arch.h
struct machine_desc {
//在stm3210e_eval.c中实例化
* Note! The first four elements are used
* by assembler code in head.S, head-common.S
/* architecture number */
unsigned int
phys_ /* start of physical io */
unsigned int
io_pg_ /* byte offset for io
三亿文库包含各类专业文献、高等教育、幼儿教育、小学教育、中学教育、生活休闲娱乐、专业论文、stm32-uclinux-startkernel之前的汇编代码分析95等内容。 
 stm32-uclinux-startkernel之前的汇编代码分析_计算机软件及应用_IT/计算机_专业资料。STM32F103是大容量型,内部有512KB的Flash,64KB的RAM。 ucLinux操作系统是针对...【图文】ARM汇编语言的语法知识_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
ARM汇编语言的语法知识
大小:790.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢ARM汇编语言学习笔记(一)---ARM汇编的程序结构 - CSDN博客
ARM汇编语言学习笔记(一)---ARM汇编的程序结构
0x00 用到的书籍
《Android软件安全与逆向分析》第六章
0x01 原生程序的生成过程
笔者是在Linux环境下测试的,详细过程见书中说明
需要编译的C语言代码
#include &stdio.h&
int main(int argc, char* argv[]){
printf("Hello ARM!\n");
预处理,生成hello.i文件
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
汇编,生成二进制目标文件
gcc -c hello.s -o hello.o
链接,生成hello可执行文件
gcc hello.o -o hello
0x02 完整ARM汇编结构
下面打开生成的.文件
.arch armv5te
@处理器架构
.fpu softvfp
@浮点协处理器类型
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
@声明只读数据
@声明对齐方式2^2=4字节
"Hello ARM!\000"@声明字符串
@声明代码段
@声明对齐方式4字节
.global main
@全局符号main
main, %function @main类型为函数
@ args = 0, pretend = 0, frame = 8
@ frame_needed = 1, uses_anonymous_args = 0
sp!, {fp, lr}
@将fp,lr压入堆栈
add fp, sp, #4
@初始化fp寄存器,设置栈帧,用于访问局部变量
sub sp, sp, #8
@开辟栈空间
str r0, [fp, #-8]
@保存第一个参数
str r1, [fp, #-12]
@保存第二个参数
ldr r3, .L3
@取标号.L3处的内容,
add r3, pc, r3
mov r0, r3
mov r3, #0
mov r0, r3
sub sp, fp, #4
sp!, {fp, pc}
.LC0-(.LPIC0+8)
main, .-main
"GCC: (GNU) 4.4.3"
.note.GNU-stack,"",%progbits
0x03 处理器架构定义
.arch armv5te
@处理器架构
.fpu softvfp
@浮点协处理器类型
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 6
.eabi_attribute 18, 4
0x04 段定义
本例子中定义了三个段
@声明只读数据
@定义了代码段
.note.GNU-stack,"",%progbits
@保护代码,禁止生成可执行堆栈。
0x05 注释与标号
单行注释用@表示,例如
@声明只读数据
多行注释用/*
0x06 汇编器指令
程序中所有以点开头的都是汇编器指令,就是给汇编器读的指令,不属于ARM指令集
.flie:指定了源文件名。手写可忽略
.align:指定了代码对齐方式你后面跟的是2的次方
.ascii:声明字符串
.global:声明全局符号。全局符号是指在本程序外可访问的符号。
.type:指定符号的类型,“.type main,%function”表示main为函数
.word: 用来存放地址。
.size:设定指定符号的大小。“.size main,.-main”中的”.”表示当前地址,减去main符号的地址为整个main函数的大小。
.ident:编译器标识,无实际意义。
0x07 子程序与参数传递
函数声明方法
.global 函数名
函数名,“%function”
.global MyAdd
.type MyAdd,%function
ADD r0,r0,r1
@两个数相加
@ 函数返回
ARM参数传递规定(重要)
R0-R3这4个寄存器用来传递函数调用的第1到4个参数,超出的通过堆栈来传递,R0同时用来存放函数调用的返回值。由函数调用方来平衡堆栈。
本文已收录于以下专栏:
相关文章推荐
首先,我们先看一个简单的汇编程序:
area ff,code,readonly ;声明代码段
code32 ;声明为32位ARM指令
entry ;声明程序入口
(一) -- ARM CPU寄存器
本系列文章节选自本人所著《深入浅出嵌入式底层软件开发》。
本系列文章,所需代码请从以下地址下载:
http://download.csdn...
1. GNU ARM 汇编快速入门
任何汇编行都是如下结构:
[:] [} @ comment
[:] [} @ 注释
GNU ARM 汇编中,任何以冒号结尾的都被认为是一个...
常用ARM源程序文件类型
汇编语言程序的结构1
汇编语言程序的结构2
汇编语言程序的结构3
在 ARM ( Thumb )汇编语言程序中,以程序段为单位组织代码。段是相对独立的指令或数据序列,具有特定的名称。段可以分为代码段和数据段,代码段的内容为执行代码,数据段存放代码运行时需要用到的数据...
一.汇编语言的基本语法
/************************汇编指令的基本结构*****************************/
操作数1,操作数2,....
如何编写ARM汇编程序---------------------------------------------------------Author
:tiger-johnWe...
ARM处理器一共有37个寄存器
包括31个通用寄存器,包括PC,都是32位的寄存器,6个状态寄存器,也都是32位寄存器
有其中不同的模式,用户模式,快速中断模式,普通中断模式,管理模式,数据访问终...
常用ARM汇编指令及ATPCS规则
分类: 嵌入式|举报|字号 订阅
在嵌入式开发中,汇编程序常常用于非常关键的地方...
Arm上函数调用的规则在ARM System Developer's Guide文档中的ATPCS部分有详细的定义,这里主要通过函数调用过程中函数栈的情况来说明fp和sp等寄存器的作用。有关ATPCS...
他的最新文章
讲师:钟钦成
讲师:宋宝华
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 arm汇编 的文章

 

随机推荐