building minimal piece of assembly code produces empty binary file

3

I'm trying to build a minimal startup code for my MCU (tms570lc4357zwt, ARM Cortex-R5f), but when I build it and convert it to binary format, the size of the produced .bin file is 0.

The structure of test files is:

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

The version of the tools I use are:

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

Here is my minimal piece of assembly code (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       .

and I use the following linker script (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
}

Bellow, the toolchain file (gnu.cmake) and the cmake file (CMakeLists.txt) I use to build it:

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})

The issue can be reproduced by running (in the folder containing all files) mkdir build && cd build && cmake .. -DCMAKE_TOOLCHAIN_FILE=../gnu.cmake

Now comes the issue: When I ask the size of the .elf (invoking the isr.size taget), I get

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

which seems reasonable. now when I produce the .bin file (invoking the isr.bin target), the produced file size is 0. Does anyone have an idea why? Because when I disassemble the .elf file (invoking the isr.asm target), the generated assembly code seems correct:

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.

Thanks in advance.

assembly
linker
arm
elf
bin
asked on Stack Overflow Aug 29, 2019 by Sauci • edited Aug 29, 2019 by Sauci

1 Answer

4

In your assembly code you haven't marked your sections as allocatable so they aren't being output when you produce the binary file. If you had dumped the header files with

arm-none-eabi-objdump -x isr.elf

The output would have looked similar to:

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

The flags are only CONTENTS and READONLY. It is missing the ALLOC (allocatable) flag. Since your sections appear to also be code I'd consider modifying isr.S by adding "ax" attributes with something like:

.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       .

If you rebuild the code the bin file should be non-zero and the ELF headers should now look something like:

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

The .section directive is documented for ELF as:

ELF Version

This is one of the ELF section stack manipulation directives. The others are .subsection (see SubSection), .pushsection (see PushSection), .popsection (see PopSection), and .previous (see Previous).

For ELF targets, the .section directive is used like this:

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

[snip]

a section is allocatable

d section is a GNU_MBIND section

e section is excluded from executable and shared library.

w section is writable

x section is executable

M section is mergeable

S section contains zero terminated strings

G section is a member of a section group

T section is used for thread-local-storage

? section is a member of the previously-current section’s group, if any

[snip]

The optional type argument may contain one of the following constants:

@progbits section contains data

@nobits section does not contain data (i.e., section only occupies space)

[snip]

Note on targets where the @ character is the start of a comment (eg ARM) then another character is used instead. For example the ARM port uses the % character.

answered on Stack Overflow Aug 29, 2019 by Michael Petch • edited Aug 29, 2019 by Michael Petch

User contributions licensed under CC BY-SA 3.0