构建最少的汇编代码会产生空的二进制文件

时间:2019-08-29 08:19:23

标签: assembly linker arm elf bin

我正在尝试为我的MCU(tms570lc4357zwt,ARM Cortex-R5f)构建一个最小的启动代码,但是当我将其构建并将其转换为二进制格式时,所生成的 .bin 文件为0。

测试文件的结构为:

test
  +--CMakeLists.txt
  +--gnu.cmake
  +--isr.S
  +--linker.ld

我使用的工具版本为:

  • arm-none-eabi-gcc:8-2018-q4-major
  • cmake:3.15.2

这是我最小的汇编代码(isr.S):

.arm

.global isr_vector
.global bootloader

.section .flash_code_isr_vector
isr_vector:
    LDR     pc, = bootloader /* reset. */
    LDR     pc, = 0x08000004 /* undefined instruction. */
    LDR     pc, = 0x08000008 /* system call. */
    LDR     pc, = 0x0800000C /* prefetch abort. */
    LDR     pc, = 0x08000010 /* data abort. */
    LDR     pc, = 0x08000014 /* reserved. */
    LDR     pc, = 0x08000018 /* IRQ. */
    LDR     pc, = 0x0800001C /* FIQ. */

.section .flash_code_bootloader
bootloader:
    B       .

并且我使用以下链接描述文件(linker.ld):

MEMORY
{
    FLASH_TCM (rx) : ORIGIN = 0x00000000, LENGTH = 4M
    RAM_TCM (rwx) : ORIGIN = 0x08000000, LENGTH = 512K
    RAM_ECC (rwx) : ORIGIN = 0x08400000, LENGTH = 512K
}

ENTRY(isr_vector)

SECTIONS
{
    .flash_code_isr_vector 0x00000000 :
    {
        KEEP(*(.flash_code_isr_vector))
    } > FLASH_TCM

    .flash_code_bootloader 0x00000100 :
    {
        *(.flash_code_bootloader)
    } > FLASH_TCM
}

下面是我用来构建它的工具链文件(gnu.cmake)和cmake文件(CMakeLists.txt):

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_C_COMPILER_WORKS TRUE)

set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

find_program(ASM_COMPILER arm-none-eabi-gcc)
find_program(C_COMPILER arm-none-eabi-gcc)
find_program(LINKER arm-none-eabi-gcc)
find_program(ARCHIVER arm-none-eabi-ar)
find_program(RANLIB arm-none-eabi-ranlib)

set(CMAKE_ASM_COMPILER ${ASM_COMPILER})
set(CMAKE_C_COMPILER ${C_COMPILER})
set(CMAKE_C_LINK_EXECUTABLE ${LINKER})
set(CMAKE_AR ${ARCHIVER})
set(CMAKE_RANLIB ${RANLIB})

add_compile_options(-mbig-endian
    -march=armv7-r
    -Wall
    -Wextra)

add_link_options(-mbig-endian
    -nostdlib
    -Wall
    -Wextra)
cmake_minimum_required(VERSION 3.0)

project(test VERSION 0.0.1 LANGUAGES ASM)

add_executable(isr.elf isr.S)
add_compile_options(isr.elf PRIVATE -O0 -g)
set_target_properties(isr.elf PROPERTIES
    LINK_FLAGS "-T ${CMAKE_CURRENT_SOURCE_DIR}/linker.ld")

add_custom_target(isr.bin
    DEPENDS isr.elf
    COMMAND arm-none-eabi-objcopy -O binary isr.elf isr.bin
    WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

add_custom_target(isr.asm
    DEPENDS isr.elf
    COMMAND arm-none-eabi-objdump -D isr.elf > isr.asm
    WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

add_custom_target(isr.size
    DEPENDS isr.elf
    COMMAND arm-none-eabi-size isr.elf -A -t -x
    WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

可以通过运行(在包含所有文件的文件夹中)mkdir build && cd build && cmake .. -DCMAKE_TOOLCHAIN_FILE=../gnu.cmake

重现该问题。

现在出现问题: 当我问 .elf 的大小(调用isr.size标签时),我得到

isr.elf  :
section                  size    addr
.flash_code_isr_vector   0x40     0x0
.flash_code_bootloader    0x4   0x100
.ARM.attributes          0x1d     0x0
Total                    0x61

这似乎是合理的。现在,当我生成 .bin 文件(调用isr.bin目标)时,生成的文件大小为0。有人知道为什么吗?因为当我反汇编 .elf 文件(调用isr.asm目标)时,生成的汇编代码似乎是正确的:

isr.elf:     file format elf32-bigarm


Disassembly of section .flash_code_isr_vector:

00000000 <isr_vector>:
   0:   e59ff018    ldr pc, [pc, #24]   ; 20 <isr_vector+0x20>
   4:   e59ff018    ldr pc, [pc, #24]   ; 24 <isr_vector+0x24>
   8:   e59ff018    ldr pc, [pc, #24]   ; 28 <isr_vector+0x28>
   c:   e59ff018    ldr pc, [pc, #24]   ; 2c <isr_vector+0x2c>
  10:   e59ff018    ldr pc, [pc, #24]   ; 30 <isr_vector+0x30>
  14:   e59ff018    ldr pc, [pc, #24]   ; 34 <isr_vector+0x34>
  18:   e59ff018    ldr pc, [pc, #24]   ; 38 <isr_vector+0x38>
  1c:   e59ff018    ldr pc, [pc, #24]   ; 3c <isr_vector+0x3c>
  20:   00000100    andeq   r0, r0, r0, lsl #2
  24:   08000004    stmdaeq r0, {r2}
  28:   08000008    stmdaeq r0, {r3}
  2c:   0800000c    stmdaeq r0, {r2, r3}
  30:   08000010    stmdaeq r0, {r4}
  34:   08000014    stmdaeq r0, {r2, r4}
  38:   08000018    stmdaeq r0, {r3, r4}
  3c:   0800001c    stmdaeq r0, {r2, r3, r4}

Disassembly of section .flash_code_bootloader:

00000100 <bootloader>:
 100:   eafffffe    b   100 <bootloader>

Disassembly of section .ARM.attributes:

00000000 <.ARM.attributes>:
   0:   41000000    mrsmi   r0, (UNDEF: 0)
   4:   1c616561    cfstr64ne   mvdx6, [r1], #-388  ; 0xfffffe7c
   8:   62690001    rsbvs   r0, r9, #1, 0
   c:   00000012    andeq   r0, r0, r2, lsl r0
  10:   05372d52    ldreq   r2, [r7, #-3410]!   ; 0xfffff2ae
  14:   00060a07    andeq   r0, r6, r7, lsl #20
  18:   52080109    andpl   r0, r8, #1073741826 ; 0x40000002
  1c:   Address 0x000000000000001c is out of bounds.

谢谢。

1 个答案:

答案 0 :(得分:4)

在汇编代码中,您没有将节标记为可分配的,因此在生成二进制文件时不会输出这些节。如果您已经用

转储了头文件
arm-none-eabi-objdump -x isr.elf

输出看起来类似于:

isr.elf:     file format elf32-bigarm
isr.elf
architecture: arm, flags 0x00000012:
EXEC_P, HAS_SYMS
start address 0x00000000
private flags = 5000200: [Version5 EABI] [soft-float ABI]

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .flash_code_isr_vector 00000040  00000000  00000000  00000034  2**2
                  CONTENTS, READONLY
  1 .flash_code_bootloadery 00000004  00000000  00000000  00000074  2**2
                  CONTENTS, READONLY
  2 .ARM.attributes 0000001d  00000000  00000000  00000078  2**0
                  CONTENTS, READONLY

标志仅为CONTENTSREADONLY。它缺少ALLOC(可分配)标志。由于您的部分似乎也是代码,因此我考虑通过添加isr.S属性,例如:

来修改"ax"
.arm

.global isr_vector
.global bootloader

.section .flash_code_isr_vector,"ax",%progbits
isr_vector:
    LDR     pc, = bootloader /* reset. */
    LDR     pc, = 0x08000004 /* undefined instruction. */
    LDR     pc, = 0x08000008 /* system call. */
    LDR     pc, = 0x0800000C /* prefetch abort. */
    LDR     pc, = 0x08000010 /* data abort. */
    LDR     pc, = 0x08000014 /* reserved. */
    LDR     pc, = 0x08000018 /* IRQ. */
    LDR     pc, = 0x0800001C /* FIQ. */

.section .flash_code_bootloader,"ax",%progbits
bootloader:
    B       .

如果您重建代码,则bin文件应为非零值,并且ELF标头现在应类似于:

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .flash_code_isr_vector 00000040  00000000  00000000  00010000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .flash_code_bootloader 00000004  00000100  00000100  00010100  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .ARM.attributes 0000001d  00000000  00000000  00010104  2**0
                  CONTENTS, READONLY

.section伪指令是documented for ELF,如下所示:

  

ELF版本

     

这是ELF节堆栈操作之一   指令。其他是.subsection(请参阅SubSection),.pushsection   (请参阅PushSection)、. popsection(请参阅PopSection)和.previous(请参阅   上一个)。

     

对于ELF目标,.section指令的用法如下:

.section name [, "flags"[, @type[,flag_specific_arguments]]]
     

[snip]

     

可分配的部分

     

d部分是GNU_MBIND部分

     

e部分从可执行文件和共享库中排除。

     

w部分可写

     

x部分是可执行的

     

M部分是可合并的

     

S部分包含零个终止的字符串

     

G部门是部门组的成员

     

T部分用于线程本地存储

     

?该部分是先前当前部分的组的成员,如果   任何

     

[snip]

     

可选的type参数可以包含以下常量之一:

     

@progbits部分包含数据

     

@nobits部分不包含数据(即,该部分仅占用   空格)

     

[snip]

     

关于目标的注释,其中@字符是注释的开头(例如   然后使用另一个字符代替。例如ARM端口   使用%字符。