Keil stm32,使用汇编,分散文件和c。如何将c代码入口点导出到程序集?

Posted

技术标签:

【中文标题】Keil stm32,使用汇编,分散文件和c。如何将c代码入口点导出到程序集?【英文标题】:Keil stm32, using assembly, scatter file and c. How to export c code entry point to assembly? 【发布时间】:2019-08-09 05:51:10 【问题描述】:

为了结合 .c 和汇编,我想传递 我的 .c 代码的起始地址,然后对微控制器进行编程以知道其程序从该地址开始.当我在汇编中编写我的启动文件时,我需要将.c代码起始地址传递给汇编,然后将此地址写入微控制器的特定内存区域(所以微控制器可以在RESET之后在这个地址上开始执行)

尝试在 Keil 中为 stm32f103 创建一个具有这种结构的项目:

一些 .c 文件,例如 main.c(用于程序的主要部分)。 汇编语言的启动文件。它获取写入某个 .c 文件中的函数的入口地址,以传递给 Reset_Handler 分散文件,这样写的:

LR_IROM1 0x08000000 0x00010000      ; load region size_region
  ER_IROM1 0x08000000 0x00010000    ; load address = execution address
   *.o (RESET, +First)   ; RESET is code section with I.V.T.
   * (InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  
  RW_IRAM1 0x20000000 0x00005000    ; RW data
   .ANY (+RW +ZI)
  

问题在于将入口点传递给 .c 函数。需要__main传递的.c入口点(起始地址)的Reset_Handler,看起来是这样的:

Reset_Handler PROC

    EXPORT Reset_Handler [WEAK]
    IMPORT __main
    LDR R0, =__main
    BX R0

    ENDP

关于入口点 __main,作为对question 的一个程序集的回答:

__main() 是编译器为您的 C 代码提供的入口点。它不是您编写的 main() 函数,而是为 标准库、静态数据、调用“main()”之前的堆 功能。

那么,如何在我的程序集文件中获取这个入口点?

编辑>> 如果有人对 KEIL 的解决方案感兴趣,就在这里,就是这么简单!

简单程序集startup.s文件:

        AREA STACK, NOINIT, READWRITE
        SPACE 0x400       
Stack_top                 

        AREA RESET, DATA, READONLY
        dcd Stack_top     
        dcd Reset_Handler



        EXPORT _InitMC
        IMPORT notmain

        AREA PROGRAM, CODE, READONLY

Reset_Handler PROC
        bl notmain
        ENDP

_InitMC   PROC          ;start of the assembly procedure
Loop
        b Loop          ;infinite loop
        ENDP

        END

简单的c文件:

extern int _InitMC();
int notmain(void) 
    _InitMC();
    return 0;

链接器与上面提到的相同。 项目构建成功。

【问题讨论】:

您的问题到底是什么?你有什么错误吗?如果有,是什么? 嘿@Jester。我只是不知道如何通过它。当我编译所有内容时,编译器将 .c 代码放在某个地址,在这种特殊情况下,对于 stm32f103c8,它将类似于 0x2000 xxxx。但我事先并不知道,所以我可以将此地址写入 0x0800 0004(这是 RESET 向量的地址)-这意味着在 RESET 上,微控制器将从该地址开始执行。 address orred 准确地说是 1,并且从加电开始,sram 中没有代码,所以你当然不能在那里有“c”代码。备份,并解释你要做什么。制作一个非常简单的程序 main ( ) return 5;或类似的东西,带有最小的链接器脚本,显示反汇编等,然后你不喜欢什么并想要改变...... 如果您正在编写引导代码,则输入您的 C 入口点的地址,然后如果您希望它不必是 main 或 __main() 或其他任何东西,则可以将其称为 pickle()。了解您可能会失去库支持。从我上面描述的程序中检查你正在使用的工具链提供的引导代码,如果你有一个可以为这个目标构建的代码。这应该回答你所有的问题,但如果他们不这样做,如果我们能看到它,它就是一个很好的话题。 你希望工具链用 1 btw 完成 orr... 【参考方案1】:

以gnu工具链为例:

引导:

.cpu cortex-m0
.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset
.word loop
.word loop
.word loop

.thumb_func
reset:
    bl notmain
    b loop
.thumb_func
loop:   b .

.align

.thumb_func
.globl fun
fun:
    bx lr

.end

C 入口点(函数名不相关,有时使用 main() 会添加垃圾,取决于编译器/工具链)

void fun ( unsigned int );
int notmain ( void )

    unsigned int ra;
    for(ra=0;ra<1000;ra++) fun(ra);
    return(0);

链接脚本

MEMORY

    rom : ORIGIN = 0x08000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000


SECTIONS

    .text :  *(.text*)  > rom
    .rodata :  *(.rodata*)  > rom
    .bss :  *(.bss*)  > ram

构建

arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mthumb -mcpu=cortex-m0 -march=armv6-m -c so.c -o so.thumb.o
arm-none-eabi-ld -o so.thumb.elf -T flash.ld flash.o so.thumb.o
arm-none-eabi-objdump -D so.thumb.elf > so.thumb.list
arm-none-eabi-objcopy so.thumb.elf so.thumb.bin -O binary
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding  -mthumb -mcpu=cortex-m3 -march=armv7-m -c so.c -o so.thumb2.o
arm-none-eabi-ld -o so.thumb2.elf -T flash.ld flash.o so.thumb2.o
arm-none-eabi-objdump -D so.thumb2.elf > so.thumb2.list
arm-none-eabi-objcopy so.thumb2.elf so.thumb2.bin -O binary

结果(所有拇指版本)

Disassembly of section .text:

08000000 <_start>:
 8000000:   20001000
 8000004:   08000015
 8000008:   0800001b
 800000c:   0800001b
 8000010:   0800001b

08000014 <reset>:
 8000014:   f000 f804   bl  8000020 <notmain>
 8000018:   e7ff        b.n 800001a <loop>

0800001a <loop>:
 800001a:   e7fe        b.n 800001a <loop>

0800001c <fun>:
 800001c:   4770        bx  lr
 800001e:   46c0        nop         ; (mov r8, r8)

08000020 <notmain>:
 8000020:   b570        push    r4, r5, r6, lr
 8000022:   25fa        movs    r5, #250    ; 0xfa
 8000024:   2400        movs    r4, #0
 8000026:   00ad        lsls    r5, r5, #2
 8000028:   0020        movs    r0, r4
 800002a:   3401        adds    r4, #1
 800002c:   f7ff fff6   bl  800001c <fun>
 8000030:   42ac        cmp r4, r5
 8000032:   d1f9        bne.n   8000028 <notmain+0x8>
 8000034:   2000        movs    r0, #0
 8000036:   bd70        pop r4, r5, r6, pc

当然,这必须用一些工具放在正确的地方。

向量表被逻辑映射到stm32族的0x00000000。

08000000 <_start>:
 8000000:   20001000
 8000004:   08000015 <---- reset ORR 1

在这个最小的代码中,重置处理程序调用 C 代码,C 代码混乱并返回。从技术上讲,对于大多数 stm32s 来说,这是一个功能齐全的程序(对于那些内存较少的人来说,将堆栈初始化更改为较小的值,比如 0x20000400,它应该可以通过单独使用 -mthumb(armv4t)或添加 cortex-m0 在任何地方工作。好吧,不是 armv8ms从技术上讲,他们不能支持所有 armv6m,但我所知道的领域支持。

我没有 Kiel,所以不知道如何翻译,但它不应该是太多的延伸,只是语法。

【讨论】:

谢谢@old_timer。您的回答实际上不仅仅是回答我的问题。我将编辑我的答案以显示 keil 的语法。您能否向我推荐一些有关 gnu 工具链的书籍。我正在尝试从基础上了解 stm32。我现在使用 keil,因为它为调试和编译提供了非常简单的界面。 不知道 gnu 的书籍,它有自己的文档。高比例的人有​​经验。由于相对于其他工具链具有经验的人的百分比,因此更有可能在 SO 和其他地方找到 gnu 工具链帮助而不是其他工具链。与裸机本身一样,您只需投入一些时间并破解/修补/播放您所说的任何内容...... 该代码中唯一真正特别的是thumb_func,其余的很明显,thumb_func 告诉工具链出现的下一个标签被视为函数地址,因此当用作“.word reset”时" 工具链或打开的那个。尝试在 reset: 标签前不带 thumb_func 的情况下,您会看到带有 one 的 orr 消失,并且您的 mcu 将出现故障而不是启动,并且您的故障处理程序也可能会出现故障。 如果您不想自己构建,那么很容易获得用于 arm 的预构建 gnu 交叉编译器。

以上是关于Keil stm32,使用汇编,分散文件和c。如何将c代码入口点导出到程序集?的主要内容,如果未能解决你的问题,请参考以下文章

基于STM32的汇编程序

搭建并配置Keil嵌入式开发环境,完成一个基于STM32汇编程序的编写

keilmdk仿真ctrl+f5会出现的问题

如何查看keil能否支持stm32m0内核

keil怎么把程序烧录进stm32

汗,keil 仿真跳不进main