我的英语水平很差,因为我不是以英语为母语的人。敬请谅解。
我用 LLVM infra 编译了一些在 IAR 中运行良好的测试代码,但生成的代码没有在我的测试板上运行。详情如下。
测试目标
我想看看使用 LLVM 生成的汇编代码的操作。
测试环境
- 单片机:STM32L152VD(Cortex M3)
- IDE:IAR 8.2
- 调试器:Segger JLink
- LLVM 网站:http ://ellcc.org/demo/index.cgi
测试步骤(总结)
- 创建在 IAR 中可以正常运行的测试代码。
- 将测试代码移至http://ellcc.org/demo/index.cgi并选择 Target 后编译。
- 使用生成的汇编代码创建 test.s 文件。
- 创建 makefile 生成 bin 文件并使用 make 程序执行 makefile。
- 使用 JLink 程序将 bin 文件加载到目标板。
第1步
我编写了没有库的简单代码,如下所示。此代码简单地打开 LED。
volatile int* _RCC = (int*)(0x40023800);
volatile int* _RCC_AHBENR = (int*)(0x4002381c);
volatile int* _GPIOE = (int*)0x40021000;
volatile int* _GPIOE_BSRR = (int*)(0x40021000 + 0x18);
void InitPort()
{
const int _RCC_AHBENR_GPIOEEN = (0x00000010);
int SetOutput = 0x00000600;
*_RCC_AHBENR = _RCC_AHBENR_GPIOEEN;
*_GPIOE = SetOutput; // set mode to output
*_GPIOE_BSRR = 0x00000020; // set
}
int main()
{
InitPort();
*_GPIOE_BSRR = 0x00200000; // reset
while(1);
}
上面的代码在 IAR 中是正确的。
第2步
我将创建的测试代码移至http://ellcc.org/demo/index.cgi并在选择选项后按下编译按钮,如下所示。
第 3 步
我使用在站点中生成的汇编代码创建了 test.s 文件,如下所示。
.text
.syntax unified
.eabi_attribute 67, "2.09"
.cpu cortex-m3
.eabi_attribute 6, 10
.eabi_attribute 7, 77
.eabi_attribute 8, 0
.eabi_attribute 9, 2
.eabi_attribute 34, 1
.eabi_attribute 17, 1
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 38, 1
.eabi_attribute 18, 4
.eabi_attribute 26, 2
.eabi_attribute 14, 0
.file "_2376_0.c"
.globl InitPort
.p2align 1
.type InitPort,%function
.code 16
.thumb_func
InitPort:
.fnstart
sub sp, #8
movs r0, #16
str r0, [sp, #4]
mov.w r1, #1536
str r1, [sp]
movw r1, :lower16:_RCC_AHBENR
movt r1, :upper16:_RCC_AHBENR
ldr r1, [r1]
str r0, [r1]
ldr r0, [sp]
movw r1, :lower16:_GPIOE
movt r1, :upper16:_GPIOE
ldr r1, [r1]
str r0, [r1]
movw r0, :lower16:_GPIOE_BSRR
movt r0, :upper16:_GPIOE_BSRR
ldr r0, [r0]
movs r1, #32
str r1, [r0]
add sp, #8
bx lr
.Lfunc_end0:
.size InitPort, .Lfunc_end0-InitPort
.cantunwind
.fnend
.globl main
.p2align 1
.type main,%function
.code 16
.thumb_func
main:
.fnstart
push {r7, lr}
mov r7, sp
sub sp, #8
movs r0, #0
str r0, [sp, #4]
bl InitPort
movw r0, :lower16:_GPIOE_BSRR
movt r0, :upper16:_GPIOE_BSRR
ldr r0, [r0]
mov.w lr, #2097152
str.w lr, [r0]
b .LBB1_1
.LBB1_1:
b .LBB1_1
.Lfunc_end1:
.size main, .Lfunc_end1-main
.cantunwind
.fnend
.type _RCC,%object
.data
.globl _RCC
.p2align 2
_RCC:
.long 1073887232
.size _RCC, 4
.type _RCC_AHBENR,%object
.globl _RCC_AHBENR
.p2align 2
_RCC_AHBENR:
.long 1073887260
.size _RCC_AHBENR, 4
.type _GPIOE,%object
.globl _GPIOE
.p2align 2
_GPIOE:
.long 1073876992
.size _GPIOE, 4
.type _GPIOE_BSRR,%object
.globl _GPIOE_BSRR
.p2align 2
_GPIOE_BSRR:
.long 1073877016
.size _GPIOE_BSRR, 4
.ident "ecc version 2017-08-23 (http://ellcc.org) based on clang version 6.0.0 (trunk 311547)"
.section ".note.GNU-stack","",%progbits
第4步
我创建了makefile来生成bin文件,如下所示。这是makefile的内容。
bin: test.s
@echo "Running target all"
arm-none-eabi-as c:/backend/files/test.s -o c:/backend/files/test.o
arm-none-eabi-ld -Ttext=0x08000000 c:/backend/files/test.o -o c:/backend/files/test.elf
arm-none-eabi-objdump -D c:/backend/files/test.elf
arm-none-eabi-objcopy c:/backend/files/test.elf -O binary c:/backend/files/test.bin
clean:
@echo "Running target clean"
rm -f *.o
rm -f *.elf
rm -f *.bin
我用make程序执行了上面的makefile,我得到了一个test.o、test.elf、test.bin文件。
第 5 步
我用 JLink.exe (seggar) 加载了 bin 文件并使用 go 命令执行,但注意到发生在船上。(我在加载 bin 文件时使用的命令是“loadbin C:\backend\files\test.bin, 0x08000000”)
结论
到这里就是我所做的一切。我按照上面的方法做了,但是 LLVM infra 生成的汇编代码与 IAR 生成的代码不同。我想知道我做错了什么以及如何解决以实现目标。任何帮助将不胜感激。
谢谢。
添加信息
船上没有像 RTOS 这样的软件。下图是我用来测试的整个结构。 只有 main.cpp 文件是源代码。其他文件由 EWARM IDE 生成。
地图文件的内容如下。
###############################################################################
#
# IAR ELF Linker V8.22.2.15995/W32 for ARM 24/Oct/2020 19:22:32
# Copyright 2007-2018 IAR Systems AB.
#
# Output file = C:\Users\jjw\Desktop\hobby\Test\Debug\Exe\Test.out
# Map file = C:\Users\jjw\Desktop\hobby\Test\Debug\List\Test.map
# Command line =
# -f C:\Users\jjw\AppData\Local\Temp\EW7E50.tmp
# (C:\Users\jjw\Desktop\hobby\Test\Debug\Obj\main.o -o
# C:\Users\jjw\Desktop\hobby\Test\Debug\Exe\Test.out --redirect
# _Printf=_PrintfFullNoMb --redirect _Scanf=_ScanfFullNoMb --map
# C:\Users\jjw\Desktop\hobby\Test\Debug\List\Test.map --config
# "C:\Program Files (x86)\IAR Systems\Embedded Workbench
# 8.0\arm\CONFIG\generic_cortex.icf" --semihosting --entry
# __iar_program_start --redirect __iar_sh_stdout=__iar_sh_stdout_swo
# --vfe --text_out locale)
#
###############################################################################
*******************************************************************************
*** RUNTIME MODEL ATTRIBUTES
***
CppFlavor = *
__CPP_Exceptions = Disabled
__CPP_Language = C++14
__SystemLibrary = DLib
__dlib_version = 6
*******************************************************************************
*** HEAP SELECTION
***
The basic heap was selected because no calls to memory allocation
functions were found in the application outside of system library
functions, and there are calls to deallocation functions in the
application.
*******************************************************************************
*** PLACEMENT SUMMARY
***
"A0": place at 0x00000000 { ro section .intvec };
"P1": place in [from 0x00000000 to 0x0007ffff] { ro };
define block CSTACK with size = 1K, alignment = 8 { };
define block PROC_STACK with size = 0M, alignment = 8 { };
define block HEAP with size = 2K, alignment = 8 { };
"P2": place in [from 0x20000000 to 0x2000ffff] {
rw, block CSTACK, block PROC_STACK, block HEAP };
initialize by copy { rw };
Section Kind Address Size Object
------- ---- ------- ---- ------
"A0": 0x40
.intvec ro code 0x00000000 0x40 vector_table_M.o [4]
- 0x00000040 0x40
"P1": 0x104
.text ro code 0x00000040 0x3c main.o [1]
.text ro code 0x0000007c 0x2c copy_init3.o [4]
.text ro code 0x000000a8 0x28 data_init.o [4]
.iar.init_table const 0x000000d0 0x14 - Linker created -
.text ro code 0x000000e4 0x1e cmain.o [4]
.text ro code 0x00000102 0x4 low_level_init.o [3]
.text ro code 0x00000106 0x4 exit.o [3]
.text ro code 0x0000010a 0x2 vector_table_M.o [4]
.text ro code 0x0000010c 0xa cexit.o [4]
.rodata const 0x00000116 0x1 unwind_debug.o [5]
.text ro code 0x00000118 0x14 exit.o [5]
.text ro code 0x0000012c 0xc cstartup_M.o [4]
Initializer bytes const 0x00000138 0xc <for P2-1>
.rodata const 0x00000144 0x0 copy_init3.o [4]
- 0x00000144 0x104
"P2", part 1 of 2: 0xc
P2-1 0x20000000 0xc <Init block>
.data inited 0x20000000 0x4 main.o [1]
.data inited 0x20000004 0x4 main.o [1]
.data inited 0x20000008 0x4 main.o [1]
- 0x2000000c 0xc
"P2", part 2 of 2: 0x400
CSTACK 0x20000010 0x400 <Block>
CSTACK uninit 0x20000010 0x400 <Block tail>
- 0x20000410 0x400
*******************************************************************************
*** INIT TABLE
***
Address Size
------- ----
Copy (__iar_copy_init3)
1 source range, total size 0xc:
0x00000138 0xc
1 destination range, total size 0xc:
0x20000000 0xc
*******************************************************************************
*** MODULE SUMMARY
***
Module ro code ro data rw data
------ ------- ------- -------
C:\Users\jjw\Desktop\hobby\Test\Debug\Obj: [1]
main.o 60 12 12
-------------------------------------------
Total: 60 12 12
command line: [2]
-------------------------------------------
Total:
dl7M_tln.a: [3]
exit.o 4
low_level_init.o 4
-------------------------------------------
Total: 8
rt7M_tl.a: [4]
cexit.o 10
cmain.o 30
copy_init3.o 44
cstartup_M.o 12
data_init.o 40
vector_table_M.o 66
-------------------------------------------
Total: 202
shb_l.a: [5]
exit.o 20
unwind_debug.o 1
-------------------------------------------
Total: 20 1
Gaps 1
Linker created 20 1 024
-----------------------------------------------
Grand Total: 291 33 1 036
*******************************************************************************
*** ENTRY LIST
***
Entry Address Size Type Object
----- ------- ---- ---- ------
.iar.init_table$$Base 0x000000d0 -- Gb - Linker created -
.iar.init_table$$Limit 0x000000e4 -- Gb - Linker created -
?main 0x000000e5 Code Gb cmain.o [4]
CSTACK$$Base 0x20000010 -- Gb - Linker created -
CSTACK$$Limit 0x20000410 -- Gb - Linker created -
InitPort() 0x00000041 0x1e Code Gb main.o [1]
Region$$Table$$Base 0x000000d0 -- Gb - Linker created -
Region$$Table$$Limit 0x000000e4 -- Gb - Linker created -
_GPIOE 0x20000004 0x4 Data Gb main.o [1]
_GPIOE_BSRR 0x20000008 0x4 Data Gb main.o [1]
_RCC_AHBENR 0x20000000 0x4 Data Gb main.o [1]
__cmain 0x000000e5 Code Gb cmain.o [4]
__exit 0x00000119 0x14 Code Gb exit.o [5]
__iar_copy_init3 0x0000007d 0x2c Code Gb copy_init3.o [4]
__iar_data_init3 0x000000a9 0x28 Code Gb data_init.o [4]
__iar_debug_exceptions 0x00000116 0x1 Data Gb unwind_debug.o [5]
__iar_program_start 0x0000012d Code Gb cstartup_M.o [4]
__iar_systems$$module {Abs}
0x00000001 Data Gb command line/config [2]
__low_level_init 0x00000103 0x4 Code Gb low_level_init.o [3]
__vector_table 0x00000000 Data Gb vector_table_M.o [4]
_call_main 0x000000f1 Code Gb cmain.o [4]
_exit 0x0000010d Code Gb cexit.o [4]
_main 0x000000ff Code Gb cmain.o [4]
exit 0x00000107 0x4 Code Gb exit.o [3]
main 0x0000005f 0x12 Code Gb main.o [1]
[1] = C:\Users\jjw\Desktop\hobby\Test\Debug\Obj
[2] = command line
[3] = dl7M_tln.a
[4] = rt7M_tl.a
[5] = shb_l.a
291 bytes of readonly code memory
33 bytes of readonly data memory
1 036 bytes of readwrite data memory
Errors: none
Warnings: none
icf文件的内容如下。
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_4.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x00000000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_IROM1_start__ = 0x00000000;
define symbol __ICFEDIT_region_IROM1_end__ = 0x0007FFFF;
define symbol __ICFEDIT_region_IROM2_start__ = 0x0;
define symbol __ICFEDIT_region_IROM2_end__ = 0x0;
define symbol __ICFEDIT_region_EROM1_start__ = 0x0;
define symbol __ICFEDIT_region_EROM1_end__ = 0x0;
define symbol __ICFEDIT_region_EROM2_start__ = 0x0;
define symbol __ICFEDIT_region_EROM2_end__ = 0x0;
define symbol __ICFEDIT_region_EROM3_start__ = 0x0;
define symbol __ICFEDIT_region_EROM3_end__ = 0x0;
define symbol __ICFEDIT_region_IRAM1_start__ = 0x20000000;
define symbol __ICFEDIT_region_IRAM1_end__ = 0x2000FFFF;
define symbol __ICFEDIT_region_IRAM2_start__ = 0x0;
define symbol __ICFEDIT_region_IRAM2_end__ = 0x0;
define symbol __ICFEDIT_region_ERAM1_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM1_end__ = 0x0;
define symbol __ICFEDIT_region_ERAM2_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM2_end__ = 0x0;
define symbol __ICFEDIT_region_ERAM3_start__ = 0x0;
define symbol __ICFEDIT_region_ERAM3_end__ = 0x0;
/*-Sizes-*/
define symbol __ICFEDIT_size_cstack__ = 0x400;
define symbol __ICFEDIT_size_proc_stack__ = 0x0;
define symbol __ICFEDIT_size_heap__ = 0x800;
/**** End of ICF editor section. ###ICF###*/
define memory mem with size = 4G;
define symbol use_IROM1 = (__ICFEDIT_region_IROM1_start__ != 0x0 || __ICFEDIT_region_IROM1_end__ != 0x0);
define symbol use_IROM2 = (__ICFEDIT_region_IROM2_start__ != 0x0 || __ICFEDIT_region_IROM2_end__ != 0x0);
define symbol use_EROM1 = (__ICFEDIT_region_EROM1_start__ != 0x0 || __ICFEDIT_region_EROM1_end__ != 0x0);
define symbol use_EROM2 = (__ICFEDIT_region_EROM2_start__ != 0x0 || __ICFEDIT_region_EROM2_end__ != 0x0);
define symbol use_EROM3 = (__ICFEDIT_region_EROM3_start__ != 0x0 || __ICFEDIT_region_EROM3_end__ != 0x0);
define symbol use_IRAM1 = (__ICFEDIT_region_IRAM1_start__ != 0x0 || __ICFEDIT_region_IRAM1_end__ != 0x0);
define symbol use_IRAM2 = (__ICFEDIT_region_IRAM2_start__ != 0x0 || __ICFEDIT_region_IRAM2_end__ != 0x0);
define symbol use_ERAM1 = (__ICFEDIT_region_ERAM1_start__ != 0x0 || __ICFEDIT_region_ERAM1_end__ != 0x0);
define symbol use_ERAM2 = (__ICFEDIT_region_ERAM2_start__ != 0x0 || __ICFEDIT_region_ERAM2_end__ != 0x0);
define symbol use_ERAM3 = (__ICFEDIT_region_ERAM3_start__ != 0x0 || __ICFEDIT_region_ERAM3_end__ != 0x0);
if (use_IROM1)
{
define region IROM1_region = mem:[from __ICFEDIT_region_IROM1_start__ to __ICFEDIT_region_IROM1_end__];
}
else
{
define region IROM1_region = [];
}
if (use_IROM2)
{
define region IROM2_region = mem:[from __ICFEDIT_region_IROM2_start__ to __ICFEDIT_region_IROM2_end__];
}
else
{
define region IROM2_region = [];
}
define region IROM_region = IROM1_region | IROM2_region;
if (use_EROM1)
{
define region EROM1_region = mem:[from __ICFEDIT_region_EROM1_start__ to __ICFEDIT_region_EROM1_end__];
}
else
{
define region EROM1_region = [];
}
if (use_EROM2)
{
define region EROM2_region = mem:[from __ICFEDIT_region_EROM2_start__ to __ICFEDIT_region_EROM2_end__];
}
else
{
define region EROM2_region = [];
}
if (use_EROM3)
{
define region EROM3_region = mem:[from __ICFEDIT_region_EROM3_start__ to __ICFEDIT_region_EROM3_end__];
}
else
{
define region EROM3_region = [];
}
define region EROM_region = EROM1_region | EROM2_region | EROM3_region;
if (use_IRAM1)
{
define region IRAM1_region = mem:[from __ICFEDIT_region_IRAM1_start__ to __ICFEDIT_region_IRAM1_end__];
}
else
{
define region IRAM1_region = [];
}
if (use_IRAM2)
{
define region IRAM2_region = mem:[from __ICFEDIT_region_IRAM2_start__ to __ICFEDIT_region_IRAM2_end__];
}
else
{
define region IRAM2_region = [];
}
define region IRAM_region = IRAM1_region | IRAM2_region;
if (use_ERAM1)
{
define region ERAM1_region = mem:[from __ICFEDIT_region_ERAM1_start__ to __ICFEDIT_region_ERAM1_end__];
}
else
{
define region ERAM1_region = [];
}
if (use_ERAM2)
{
define region ERAM2_region = mem:[from __ICFEDIT_region_ERAM2_start__ to __ICFEDIT_region_ERAM2_end__];
}
else
{
define region ERAM2_region = [];
}
if (use_ERAM3)
{
define region ERAM3_region = mem:[from __ICFEDIT_region_ERAM3_start__ to __ICFEDIT_region_ERAM3_end__];
}
else
{
define region ERAM3_region = [];
}
define region ERAM_region = ERAM1_region | ERAM2_region | ERAM3_region;
do not initialize { section .noinit };
initialize by copy { readwrite };
if (isdefinedsymbol(__USE_DLIB_PERTHREAD))
{
// Required in a multi-threaded application
initialize by copy with packing = none { section __DLIB_PERTHREAD };
}
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
if (!isempty(IROM_region))
{
place in IROM_region { readonly };
}
if (!isempty(EROM_region))
{
place in EROM_region { readonly section application_specific_ro };
}
if (!isempty(IRAM_region))
{
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block PROC_STACK with alignment = 8, size = __ICFEDIT_size_proc_stack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
place in IRAM_region { readwrite, block CSTACK, block PROC_STACK, block HEAP };
}
if (!isempty(ERAM_region))
{
place in ERAM_region { readwrite section application_specific_rw };
}
在 EWARM 工具中,我使用 JLink 调试器上传了上述源代码。JLink 调试器和我的板子的连接如图。
我还尝试手动上传由 EWARM 工具生成的 bin 文件(不使用 EWARM 功能),如下所示。
以下方法与 LLVM 生成的上传 bin 文件的方法相同。结果,EWARM bin 文件是 LED 亮起,但 llvm 文件不是。
我在上传 EWARM bin 文件和上传 LLVM bin 文件时检查了不同的寄存器值。(PC、SP、MSP)
以下是上传 EWARM bin 文件后起始点的寄存器值。(这是操作)
以下是上传 LLVM bin 文件后起始点的寄存器值。(这个不操作)
我认为这个问题的原因是程序计数器(主)堆栈指针的值不正确。如果这个推断是对的,那么如何配置第一次的寄存器值呢?
如果需要其他信息,请告诉我。我要认真解决这个问题。