IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> GNU汇编器 -> 正文阅读

[嵌入式]GNU汇编器


前言

资料

《ARM Cortex-M0权威指南》
《程序员的自我修养——链接、装载与库》
GNU Assembler官网博客
Cortex-M0官网

什么是启动代码

工作需要,用到arm cortex-m0和m3,系统上电复位后、到进入C程序之前,需要一段启动代码,用于系统最基本的初始化:初始化堆栈指针、设置页表、操作 ARM的协处理器等。这段启动代码就是大名鼎鼎的“boot脚本”,启动代码执行的过程称为“bootloader",这两种称呼也可以混着用。
在这里插入图片描述

这段启动代码通常是汇编语言撰写。

CPU与指令集

CPU分为多种指令集,例如ARM、MIPS、RISC-V,每种指令集又分成多种子集,例如ARM指令集包括:32位ARM指令集、16位Thumb指令集、32位Thumb2指令集等。每款CPU具体用什么指令集需要查询各自的芯片手册。每个指令集对应自己的汇编语言,例如ARM汇编(生态成熟)、MIPS汇编、RISC-V汇编(这个开源),不同的汇编语言,汇编命令不同,例如,cortex-m0对应56条汇编命令:
在这里插入图片描述
在这里插入图片描述

汇编命令与汇编器

同一种汇编语言,用不同的开发工具供应商(例如GNU、ARM)提供的汇编工具语法又不同,例如ARM汇编器下的一段针对Cortex-M0的代码:

NVIC_IRQ_SETEN EQU 0xE000E100
NVIC_IRQ0_ENABLE EQU 0x1
...
LDR R0, = NVIC_IRQ_SETEN ;0xE000E100放到R0
;此处LDR为伪指令
MOVS R1, #NVIC_IRQ0_ENABLE' ;将立即数放到寄存器R1
STR R1, [R0] ;0x1存到0xE000E100,这样会使能外部中断IRQ#0

对应的,基于GNU工具链汇编器的相同功能代码写作:

.equ NVIC_IRQ_SETEN 0xE000E100
.equ NVIC_IRQ0_ENABLE 0x1
...
LDR R0, = NVIC_IRQ_SETEN /*将0xE000E100放到R0*/
/*此处LDR为伪指令*/
MOVS R1, #NVIC_IRQ0_ENABLE' /*将立即数放到寄存器R1*/
STR R1, [R0] /*将0x1存到0xE000E100,这样会使能外部中断IRQ#0*/

可见,GNU工具的操作代码和操作数的语法同ARM汇编器的一致,但标号、注释等语法不同(例如.equ)。

小结

综上所述,为了写好Cortex-M启动代码,必须学会GNU汇编器语法、Cortex-M指令集


0. GNU汇编器简介

GNU汇编器简称as,在我下载的工具链中,它的文件名是“arm-none-eabi-as.exe",其中“eabi”代表用于没有OS的开发。
在这里插入图片描述
下图为产生CPU可执行映像的开发流程,可见我们要用到汇编器(assembler)、C编译器(compiler)、链接器(linker),而在项目实际中,我们采用的是GNU交叉编译工具链。所谓工具链,就是在bin中提供了GNU ARM汇编器、GNU C编译器和GNU链接器等等需要的工具。

本文,仅学习GNU汇编器语法,不包括Cortex-M0汇编命令、C编译器、链接器内容,如有时间,后续再单独开设博客。
在这里插入图片描述

示例:GNU Assembler是TIGCC的一部分,TIGCC可以看作TI+GCC,也就是用于一系列TI产品的允许同时编译GNU汇编代码、C代码的软件开发环境。

1. 命令行

2. 输入输出

3. 基本语法

正如其他汇编器的做法,GNU汇编器采用机器无关(machine-independent)的语法设计。

instruction 指令
directive 汇编指示
pseudo-instruction 伪指令
pseudo-operation 伪操作
operator 操作符

3.1 预处理

as预处理器的作用有且仅有:

  • 调整空格
    保留行首的一个空格或者Tab键,其他位置保留一个空格
  • 删除注释
  • 变换字符常量
    将字符常量(character constant)转换为合适的数值

与你常用的C预处理器不同,as预处理器没有诸如展开宏、include文件等等功能。
如果你需要GNU C compiler进行这种“CPP”风格的预处理,那么就把汇编文件的后缀改成大写的.S;
如果你需要include问加你,那么就在汇编文件中使用.include汇编指示;

-f选项和汇编文件内部的#NO_APP#APP,可以控制空格和注释的保留与否。

3.2 空格

英文中whitespace、blank、tab、space都被翻译成中文,其实从中文没法分清,好在GNU汇编器中这些都跟一个空格键功能相同。至于你用空格还是Tab,主要是方便人类阅读,在GNU汇编器的语法中,他们并无不同。

3.3 注释

GNU汇编器的注释有两种:

  • /*xxx*/
    这种风格的注释可以跨行,也可以单行
  • #后跟非数字
    #后跟数字在GNU汇编器中另有作用,后跟非数字则看作注释;
    强烈不推荐这种注释风格,未来这样用法也可能被丢弃;

3.4 符号

symbol由字母、数字、下划线、点号、美元符号构成,区分大小写,不以数字打头。

3.5 语句

statement以换行符\n或者冒号:结尾,每个汇编文件的最后一行必须是空行。

语句开头可以有0个或者多个标签(label),后面可以再跟上决定这条语句类型的关键symbol。关键symbol决定了该语句剩余部分的语法。

如果关键symbol以点号.打头,那么这条语句是汇编指示(directive);
如果关键symbol后跟冒号:,那么这个符号称为标签(label),注意label和冒号之间不允许有空格;
如果关键symbol以字母打头,那么这条语句是汇编语言的指令(instruction),包括操作符和若干操作数;

label:     .directive    followed by something
another_label:           # This is an empty statement.
           instruction   operand_1, operand_2, ...

3.6 常量

constant分为字符常量和数字常量,常见形如:

.byte  74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value.
.ascii "Ring the bell\7"                  # A string constant.
.octa  0x123456789abcdef0123456789ABCDEF0 # A bignum.
.float 0f-314159265358979323846264338327\
95028841971.693993751E-40                 # - pi, a flonum.

3.6.1 字符常量

字符常量又分为双引号""内的字符串字面值(string literals)和单撇号'后的单字符,支持转义字符。
为了兼容Unix系统,GNU汇编器中\008表示010,\009表示011,所以0112092都表示十进制的74。

3.6.2 数字常量

数字常量支持三种:整数(Integer)对应C语言的整型,大数(Bignum)占内存超过32bit,浮点数(Flonum)对应C语言中的float。

4. 段和重定位

汇编阶段的“段”指section,描述section的结构叫段表section table;
装载阶段的“段”指segment,描述segment的结构叫程序头program header。

粗略的说,section就是一个连续的地址范围,所有此间的数据都被同等看待、同样处理。
链接器ld读入若干目标文件(object file,在linux下后缀.o,在window下后缀.obj),进行一些处理后输出可执行文件(在linux下是ELF格式后缀.elf,在window下是PE/COFF格式后缀.exe)。链接又分静态链接和动态链接,所做的处理有:分配空间和地址、解析符号、重定位等。

as汇编器和C编译器输出的目标文件又可称为partial program,partial指它还不能执行,因为它的首地址是0,也就是还没有分配地址,program指出它是静态文件,而不是动态的进程。

链接器ld将程序中的字节块以section为单位原封不动搬移到运行时的真实位置,不改变字节块内部的大小或者顺序。确定section真实位置的过程称为重定位。有些section专用于汇编阶段,ld对它们不做处理。

as汇编器生成的目标文件至少包含三个段:text、data、bss,不过段内可以是空的。在目标文件中,代码段text的首地址是0,随后是数据段data,再后是bss段。

可以用.section汇编指示指定as生成的段的名字。

as必须在目标文件中写清楚重定位信息,这样ld才知道重定位时哪些数据要修改、要怎么修改。要执行重定位,每次在object文件中提到一个地址,ld必须知道:

  • 在目标文件的这个地址引用的开始在哪
  • 这个引用有多长(以字节为单位)
  • 这个地址指的是哪一部分
  • 地址的引用是“程序计数器相对”的吗

事实上,每一个as使用的地址都表达为(section)+(offset into section),下文中用{secname N}表示secname段内偏移N字节。

as中还有一个重要概念叫做“绝对段”,也就是ld在链接是不会修改absolute段的地址。例如,{absolute 239}表示在重定位到运行时阶段是,地址真的就是239。

任何在汇编时section未知的地址都被定义为{undefined U} -其中U是稍后填写的。生成一个未定义地址的唯一方法就是提到一个未定义的符号,例如对具名common块的引用。

对于C/C++语言来说,有些符号的定义可以被称为弱符号,例如未初始化的全局变量。与强符号相比,链接器允许一个弱符号在多个目标文件中存在,并在实际链接时选择占用空间最大的那个,这就叫common block机制。类似的概念还有弱引用,这些特性在动态链接中非常重要。

4.1 链接器段

ld只处理4种段:

  • data段
    text代码段一般只读,不修改,进程间共享;data数据段每个进程独有一份,可写;
  • bss段
    bss段记录程序中的未经初始化的全局变量和静态变量,目标文件中的bss段不占内存,链接后的bss段占用内存,且全部置零。发明bss段就是为了减少目标文件的大小,消除不必要的0的存储;
  • absolute段
    绝对段不允许重定位(unrelocatable),链接器必须按照原地址放置;
  • undefined段
    这个段是所有找不到的地址引用的全称;

4.2 汇编器内置段

有些段只在汇编阶段有意义,运行时没有意义,也就不需要链接。

4.3 子段

你可能有多组数据,她们在汇编源码中并不连续,但是你希望它们在目标文件中连续,这时as提供了subsection机制。一个section可以有0-4096个subsection,例如:

.text 0     # The default subsection is text 0 anyway.
.ascii "This lives in the first text subsection. *"
.text 1
.ascii "But this lives in the second text subsection."
.data 0
.ascii "This lives in the data section,"
.ascii "in the first data subsection."
.text 0
.ascii "This lives in the first text section,"
.ascii "immediately following the asterisk (*)."

4.4 bss段

.lcomm.comm汇编指示、.section符号可以修改bss段;

5. 符号

symbol是一个核心概念:程序员用symbol命名事物,链接器用symbol连接目标文件,调试器用symbol定位问题。

5.1 标签

label后紧跟冒号,用于表示活动位置计数器(active location counter)的当前值,重复label会告警并覆盖。

5.2 符号赋值

可以用等号表达式=或者汇编指示.set给symbol赋任意值。

5.3 符号名

symbol由字母、数字、下划线、点号、美元符号构成,区分大小写,不以数字打头。
局部符号名
为了快速打标签,支持在作用域内使用local symbol,写符号用N:其中N为正整数,用Nb指代前一个数值相同的标签,用Nf指代下一个数值相同的标签,b-backward, f-forward,例如:

1:        jra 1f
2:        jra 1b
1:        jra 2f
2:        jra 1b

等效于(jra是跳转伪指令):

label_1:  jra label_3
label_2:  jra label_1
label_3:  jra label_4
label_4:  jra label_3

美元局部标签
as支持一种更加局部的局部标签,称为dollar label(以$结尾,而不是:)。一旦定义了非局部标签,这些dollar label就变成未定义的了,生命周期很短。

5.4 特殊点号

.点号特殊symbol表示as汇编的当前地址。给.点号赋值,等同于.org汇编指示。

5.5 符号特性

每个symbol除了名字以外,还有Value和Type两个属性,根据输出格式不同,symbol还可以有其他附加属性。
Value
symbol的Value一般是32bit,text、data、bss和absolute段的symbol值是从段起始为止到标签的偏移地址。当然了,text、data、bss段的symbol值在链接后会改变,因为不同目标文件的同名段的合并和重定位过程地址会被修正。
Type
symbol的type属性包含重定位(节)信息、任何标志设置,以及(可选地)用于连接器和调试器的其他信息。确切的格式取决于所使用的目标代码输出格式。

6. 表达式

Expression指定地址或数值,分为空表达式、整型表达式,整型表达式是由操作符(operator)分割的1或多个argument。
argument
argument可以是symbol、数字、子表达式。在其他情况下,argument有时被称为“算术操作数”。在本手册中,为了避免与机器语言的“指令操作数”混淆,我们使用术语“argument”仅指表达式的部分,保留“operand”一词仅指机器指令操作数。

操作符
操作符就是算术函数,例如:
二进制补码的非号-,按位取反~
高优先级乘号*、除号/、余号%、左移< <<、右移> >>
中优先级按位或|、按位与&、按位异或^、按位或非!
低优先级加、减、判同==、判不同<>、小于、大于、大于等于、小于等于、逻辑与&&、逻辑或||

7. 汇编指示

所有汇编指示都以点号.打头,大约80个。太多了,不介绍了,下面分析一个实例:

7.1 举个栗子

/*
 * Cortex M0 startup code
 */

    .syntax unified
	.arch armv6-m

/* define stack size */
    .section .stack
    .align 3
    .equ    Stack_Size, 0x00000400
    .globl    __StackTop
    .globl    __StackLimit
__StackLimit:
    .space    Stack_Size
    .size __StackLimit, . - __StackLimit
__StackTop:
    .size __StackTop, . - __StackTop

/* define heap size */
    .section .heap
    .align 3
    .equ    Heap_Size, 0x00000400
    .globl    __HeapBase
    .globl    __HeapLimit
__HeapBase:
    .space    Heap_Size
    .size __HeapBase, . - __HeapBase
__HeapLimit:
    .size __HeapLimit, . - __HeapLimit

/* define vector table */
    .section .isr_vector
    .align 2
    .globl __isr_vector
__isr_vector:
    .word    __StackTop   
    .word    Reset_Handler 
    .word    NMI_Handler
    .word    HardFault_Handler
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    SVC_Handler
    .word    0  
    .word    0  
    .word    PendSV_Handler   
    .word    SysTick_Handler  

    /* External Interrupts */
    .word    UART0_Handler
    .word    GPIO0_Handler
    .word    GPIO1_Handler  
    .word    QSPI0_Handler  
    .word    DAP_QSPI0_Handler    
    .word    DAP_SPI0_Handler   
    .word    DAP_QSPI_XIP_Handler   
    .word    DAPLinkFittedn          
    .word    Unused_IRQ8
    .word    Unused_IRQ9
    .word    Unused_IRQ10
    .word    Unused_IRQ11
    .word    Unused_IRQ12
    .word    Unused_IRQ13
    .word    Unused_IRQ14
    .word    Unused_IRQ15
    .word    Unused_IRQ16
    .word    Unused_IRQ17
    .word    Unused_IRQ18
    .word    Unused_IRQ19
    .word    Unused_IRQ20
    .word    Unused_IRQ21
    .word    Unused_IRQ22
    .word    Unused_IRQ23
    .word    Unused_IRQ24
    .word    Unused_IRQ25
    .word    Unused_IRQ26
    .word    Unused_IRQ27
    .word    Unused_IRQ28
    .word    Unused_IRQ29
    .word    Unused_IRQ30
    .word    Unused_IRQ31

    .size    __isr_vector, . - __isr_vector

    .text
    .thumb
    .thumb_func
    .align 2
    .globl   Reset_Handler
    .type    Reset_Handler, %function
Reset_Handler:
    ldr    r1, =__etext
	ldr    r2, =__data_start__
    ldr    r3, =__data_end__

/*copy data to .data section*/
.flash_to_ram_loop:
	ldr    r0, [r1]
	str    r0, [r2]
	adds   r1, r1, #4
	adds   r2, r2, #4
    cmp    r2, r3
	bne    .flash_to_ram_loop

/* clear bss */
    ldr    r0, =0
    ldr    r1, =__bss_start__
    ldr    r2, =__bss_end__

.clear_bss_loop:
	str    r0, [r1]
	adds   r1, r1, #4
	cmp    r1, r2
	bne    .clear_bss_loop

/*call main function*/
    ldr    r0, =SystemInit
    blx    r0
    ldr    r0, =main
    blx     r0

exit_loop:
    nop
    b      exit_loop

    .pool
    .size Reset_Handler, . - Reset_Handler

    .macro    def_default_handler    handler_name
    .align 1
    .thumb_func
    .weak    \handler_name
    .type    \handler_name, %function
\handler_name :
    b    .
    .size    \handler_name, . - \handler_name
    .endm


    def_default_handler    NMI_Handler
    def_default_handler    HardFault_Handler
    def_default_handler    SVC_Handler
    def_default_handler    PendSV_Handler   
    def_default_handler    SysTick_Handler  

    /* External Interrupts */
    def_default_handler    UART0_Handler
    def_default_handler    GPIO0_Handler
    def_default_handler    GPIO1_Handler  
    def_default_handler    QSPI0_Handler  
    def_default_handler    DAP_QSPI0_Handler    
    def_default_handler    DAP_SPI0_Handler   
    def_default_handler    DAP_QSPI_XIP_Handler   
    def_default_handler    DAPLinkFittedn          
    def_default_handler    Unused_IRQ8
    def_default_handler    Unused_IRQ9
    def_default_handler    Unused_IRQ10
    def_default_handler    Unused_IRQ11
    def_default_handler    Unused_IRQ12
    def_default_handler    Unused_IRQ13
    def_default_handler    Unused_IRQ14
    def_default_handler    Unused_IRQ15
    def_default_handler    Unused_IRQ16
    def_default_handler    Unused_IRQ17
    def_default_handler    Unused_IRQ18
    def_default_handler    Unused_IRQ19
    def_default_handler    Unused_IRQ20
    def_default_handler    Unused_IRQ21
    def_default_handler    Unused_IRQ22
    def_default_handler    Unused_IRQ23
    def_default_handler    Unused_IRQ24
    def_default_handler    Unused_IRQ25
    def_default_handler    Unused_IRQ26
    def_default_handler    Unused_IRQ27
    def_default_handler    Unused_IRQ28
    def_default_handler    Unused_IRQ29
    def_default_handler    Unused_IRQ30
    def_default_handler    Unused_IRQ31

7.2 编译它

arm-none-eabi-gcc -c -g -O0 -Wall -mthumb -o start.o start.s编译后产生目标文件start.o,用readelf解析文件头和段表如下:

$ readelf -h start.o 
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              REL (Relocatable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x0
  Start of program headers:          0 (bytes into file)
  Start of section headers:          5288 (bytes into file)
  Flags:                             0x5000000, Version5 EABI
  Size of this header:               52 (bytes)
  Size of program headers:           0 (bytes)
  Number of program headers:         0
  Size of section headers:           40 (bytes)
  Number of section headers:         21
  Section header string table index: 20
$ readelf -S start.o 
There are 21 section headers, starting at offset 0x14a8:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000098 00  AX  0   0  4
  [ 2] .rel.text         REL             00000000 00123c 000038 08   I 18   1  4
  [ 3] .data             PROGBITS        00000000 0000cc 000000 00  WA  0   0  1
  [ 4] .bss              NOBITS          00000000 0000cc 000000 00  WA  0   0  1
  [ 5] .stack            PROGBITS        00000000 0000d0 000400 00      0   0  8
  [ 6] .heap             PROGBITS        00000000 0004d0 000400 00      0   0  8
  [ 7] .isr_vector       PROGBITS        00000000 0008d0 0000c0 00      0   0  4
  [ 8] .rel.isr_vector   REL             00000000 001274 000138 08   I 18   7  4
  [ 9] .debug_line       PROGBITS        00000000 000990 000086 00      0   0  1
  [10] .rel.debug_line   REL             00000000 0013ac 000008 08   I 18   9  4
  [11] .debug_info       PROGBITS        00000000 000a16 000026 00      0   0  1
  [12] .rel.debug_info   REL             00000000 0013b4 000038 08   I 18  11  4
  [13] .debug_abbrev     PROGBITS        00000000 000a3c 000014 00      0   0  1
  [14] .debug_aranges    PROGBITS        00000000 000a50 000020 00      0   0  8
  [15] .rel.debug_arange REL             00000000 0013ec 000010 08   I 18  14  4
  [16] .debug_str        PROGBITS        00000000 000a70 00003b 01  MS  0   0  1
  [17] .ARM.attributes   ARM_ATTRIBUTES  00000000 000aab 00001b 00      0   0  1
  [18] .symtab           SYMTAB          00000000 000ac8 0004a0 10     19  24  4
  [19] .strtab           STRTAB          00000000 000f68 0002d1 00      0   0  1
  [20] .shstrtab         STRTAB          00000000 0013fc 0000a9 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

7.3 语法规则和架构

.syntax unified 命令是ARM架构独有的命令,用法很简单 .syntax [unified | divided] 。 作用是在汇编ARM汇编源时,指定按照怎样的语法规则进行汇编。 如果在编写汇编语言时不使用该命令指定语法规则,那么默认采用 .syntax divided ,此时使用旧的汇编风格。

.arch armv6-m命令指定cortex-m0 CPU的架构。

7.4 栈

/* define stack size */
    .section .stack
    .align 3
    .equ    Stack_Size, 0x00000400
    .globl    __StackTop
    .globl    __StackLimit
__StackLimit:
    .space    Stack_Size
    .size __StackLimit, . - __StackLimit
__StackTop:
    .size __StackTop, . - __StackTop

.section汇编指示的语法是: .section name[, "flags"] or .section name[, subsegment]。双引号内的是权限标识,例如可读、可执行等。
这一句定义了一个名为“.stack”的段。

.align汇编指示的语法是.align alignment[, [fill][, max]],用来指定数据的对齐方式。
这一句使位置计数器前进,直到它是2的3次方(也就是8)的倍数。

.equ汇编指示的语法是.equ symbol, expression,用表达式给符号赋值。
这一句定义了一个符号Stack_Size,并赋值为0x0400。

.global汇编指示的语法是.global symbol,使得链接器可以看到指定符号。

.space汇编指示的语法是.space size[, fill],分配size字节的数据空间,并填充其值为fill,缺省填0。

.size汇编指示的语法是.size expression,设定指定符号的大小。.表示当前地址,减去__StackLimit符号的地址为整个__StackLimit函数的大小。

从readelf -S的结果可以看到,目标文件中的确有一个叫做“.stack"的段,而且size是0x0400。

7.5 堆

/* define heap size */
    .section .heap
    .align 3
    .equ    Heap_Size, 0x00000400
    .globl    __HeapBase
    .globl    __HeapLimit
__HeapBase:
    .space    Heap_Size
    .size __HeapBase, . - __HeapBase
__HeapLimit:
    .size __HeapLimit, . - __HeapLimit

从readelf -S的结果可以看到,目标文件中的确有一个叫做“.heap"的段,而且size是0x0400。

7.6 向量表

/* define vector table */
    .section .isr_vector
    .align 2
    .globl __isr_vector
__isr_vector:
    .word    __StackTop   
    .word    Reset_Handler 
    .word    NMI_Handler
    .word    HardFault_Handler
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    0 
    .word    SVC_Handler
    .word    0  
    .word    0  
    .word    PendSV_Handler   
    .word    SysTick_Handler  

    /* External Interrupts */
    .word    UART0_Handler
    .word    GPIO0_Handler
    .word    GPIO1_Handler  
    .word    QSPI0_Handler  
    .word    DAP_QSPI0_Handler    
    .word    DAP_SPI0_Handler   
    .word    DAP_QSPI_XIP_Handler   
    .word    DAPLinkFittedn          
    .word    Unused_IRQ8
    .word    Unused_IRQ9
    .word    Unused_IRQ10
    .word    Unused_IRQ11
    .word    Unused_IRQ12
    .word    Unused_IRQ13
    .word    Unused_IRQ14
    .word    Unused_IRQ15
    .word    Unused_IRQ16
    .word    Unused_IRQ17
    .word    Unused_IRQ18
    .word    Unused_IRQ19
    .word    Unused_IRQ20
    .word    Unused_IRQ21
    .word    Unused_IRQ22
    .word    Unused_IRQ23
    .word    Unused_IRQ24
    .word    Unused_IRQ25
    .word    Unused_IRQ26
    .word    Unused_IRQ27
    .word    Unused_IRQ28
    .word    Unused_IRQ29
    .word    Unused_IRQ30
    .word    Unused_IRQ31

    .size    __isr_vector, . - __isr_vector

首先定义一个名为.isr_vector的段,对齐方式为4字节,定义了一个链接器可见的全局变量__isr_vector
.word汇编指示的语法为.word expressions,插入一个4字节的数据。
文中将一系列数值塞入向量表,从readelf -S的结果可以看到,目标文件中的确有一个叫做“.isr_vector"的段,而且size是0x00c0=192字节,正好是塞进去的48个4字节数据。

7.7 代码段

    .text
    .thumb
    .thumb_func
    .align 2
    .globl   Reset_Handler
    .type    Reset_Handler, %function
Reset_Handler:
    ldr    r1, =__etext
	ldr    r2, =__data_start__
    ldr    r3, =__data_end__

.text汇编指示的语法是.text [subsection],告诉汇编器as把下列内容放入代码段;
.thumb等同于.code 16, 表明使用Thumb指令;
.thumb_func用来指明一个函数是thumb指令集的函数;


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:38:02  更:2021-08-21 15:38:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:41:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码