Microblaze ELF: A small look inside

This post was written by eli on July 30, 2011
Posted Under: FPGA,Microblaze

This is a small reverse-engineering of the ELF file, as generated by Xilinx’ SDK for a simple standalone application targeted for the SP605 board.

ELF headers

Looking into the ELF file, we have something like this:

> mb-objdump --headers sdk/peripheral_tests_1/Debug/peripheral_tests_1.elf

sdk/peripheral_tests_1/Debug/peripheral_tests_1.elf:     file format elf32-microblazele

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
 0 .vectors.reset 00000008  00000000  00000000  000000b4  2**2
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 1 .vectors.sw_exception 00000008  00000008  00000008  000000bc  2**2
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 2 .vectors.interrupt 00000008  00000010  00000010  000000c4  2**2
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 3 .vectors.hw_exception 00000008  00000020  00000020  000000cc  2**2
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 4 .text         0000653c  c0000000  c0000000  000000d4  2**2
 CONTENTS, ALLOC, LOAD, CODE
 5 .init         0000003c  c000653c  c000653c  00006610  2**2
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 6 .fini         0000001c  c0006578  c0006578  0000664c  2**2
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 7 .ctors        00000008  c0006594  c0006594  00006668  2**2
 CONTENTS, ALLOC, LOAD, DATA
 8 .dtors        00000008  c000659c  c000659c  00006670  2**2
 CONTENTS, ALLOC, LOAD, DATA
 9 .rodata       00000986  c00065a4  c00065a4  00006678  2**2
 CONTENTS, ALLOC, LOAD, READONLY, DATA
 10 .sdata2       00000006  c0006f2a  c0006f2a  00006ffe  2**0
 ALLOC
 11 .sbss2        00000000  c0006f30  c0006f30  000071d8  2**0
 CONTENTS
 12 .data         000001d0  c0006f30  c0006f30  00007000  2**2
 CONTENTS, ALLOC, LOAD, DATA
 13 .eh_frame     00000004  c0007100  c0007100  000071d0  2**2
 CONTENTS, ALLOC, LOAD, DATA
 14 .jcr          00000004  c0007104  c0007104  000071d4  2**2
 CONTENTS, ALLOC, LOAD, DATA
 15 .sdata        00000000  c0007108  c0007108  000071d8  2**0
 CONTENTS
 16 .sbss         00000000  c0007108  c0007108  000071d8  2**0
 CONTENTS
 17 .tdata        00000000  c0007108  c0007108  000071d8  2**0
 CONTENTS
 18 .tbss         00000000  c0007108  c0007108  000071d8  2**0

 19 .bss          00000d78  c0007108  c0007108  000071d8  2**2
 ALLOC
 20 .heap         00000400  c0007e80  c0007e80  000071d8  2**0
 ALLOC
 21 .stack        00000400  c0008280  c0008280  000071d8  2**0
 ALLOC
 22 .debug_line   0000779f  00000000  00000000  000071d8  2**0
 CONTENTS, READONLY, DEBUGGING
 23 .debug_info   00008b11  00000000  00000000  0000e977  2**0
 CONTENTS, READONLY, DEBUGGING
 24 .debug_abbrev 000028e7  00000000  00000000  00017488  2**0
 CONTENTS, READONLY, DEBUGGING
 25 .debug_aranges 000006c0  00000000  00000000  00019d70  2**3
 CONTENTS, READONLY, DEBUGGING
 26 .debug_macinfo 0007f541  00000000  00000000  0001a430  2**0
 CONTENTS, READONLY, DEBUGGING
 27 .debug_frame  00000f10  00000000  00000000  00099974  2**2
 CONTENTS, READONLY, DEBUGGING
 28 .debug_loc    00003f80  00000000  00000000  0009a884  2**0
 CONTENTS, READONLY, DEBUGGING
 29 .debug_pubnames 00000fbe  00000000  00000000  0009e804  2**0
 CONTENTS, READONLY, DEBUGGING
 30 .debug_str    000018d5  00000000  00000000  0009f7c2  2**0
 CONTENTS, READONLY, DEBUGGING
 31 .debug_ranges 00000078  00000000  00000000  000a1097  2**0
 CONTENTS, READONLY, DEBUGGING

Even though this is a lot of mumbo-jumbo, there are three main parts. The reset and interrupt vectors, around address zero, the main parts of the ELF (.text, .data and such) at Oxc0000000 and on, and the debug parts which have no memory allocation at all.

The reset branch to application

This is interesting to compare with the Microblaze’s memory map. It can be deduced from the .mhs file, but hey, the log file (with .log suffix) has this segment:

Address Map for Processor microblaze_0
 (0000000000-0x00001fff) microblaze_0_d_bram_ctrl    microblaze_0_dlmb
 (0000000000-0x00001fff) microblaze_0_i_bram_ctrl    microblaze_0_ilmb
 (0x40000000-0x4000ffff) Push_Buttons_4Bits    axi4lite_0
 (0x40020000-0x4002ffff) LEDs_4Bits    axi4lite_0
 (0x40040000-0x4004ffff) DIP_Switches_4Bits    axi4lite_0
 (0x40600000-0x4060ffff) RS232_Uart_1    axi4lite_0
 (0x40800000-0x4080ffff) IIC_SFP    axi4lite_0
 (0x40820000-0x4082ffff) IIC_EEPROM    axi4lite_0
 (0x40840000-0x4084ffff) IIC_DVI    axi4lite_0
 (0x40a00000-0x40a0ffff) SPI_FLASH    axi4lite_0
 (0x40e00000-0x40e0ffff) Ethernet_Lite    axi4lite_0
 (0x41800000-0x4180ffff) SysACE_CompactFlash    axi4lite_0
 (0x74800000-0x7480ffff) debug_module    axi4lite_0
 (0xc0000000-0xc7ffffff) MCB_DDR3    axi4_0

So obviously all the main ELF parts go directly to the DDR memory (that isn’t much of a surprise), and the reset/interrupt go to the internal block ram.

A quick disassembly reveals the gory details:

> mb-objdump --disassemble sdk/peripheral_tests_1/Debug/peripheral_tests_1.elf
sdk/peripheral_tests_1/Debug/peripheral_tests_1.elf:     file format elf32-microblazele

Disassembly of section .vectors.reset:

00000000 <_start>:
 0:    b000c000     imm    -16384
 4:    b8080000     brai    0
Disassembly of section .vectors.sw_exception:

00000008 <_vector_sw_exception>:
 8:    b000c000     imm    -16384
 c:    b8081858     brai    6232
Disassembly of section .vectors.interrupt:

00000010 <_vector_interrupt>:
 10:    b000c000     imm    -16384
 14:    b80818a4     brai    6308
Disassembly of section .vectors.hw_exception:

00000020 <_vector_hw_exception>:
 20:    b000c000     imm    -16384
 24:    b8081870     brai    6256
Disassembly of section .text:

c0000000 <_start1>:
c0000000:    b000c000     imm    -16384
c0000004:    31a07108     addik    r13, r0, 28936
c0000008:    b000c000     imm    -16384
c000000c:    30406f30     addik    r2, r0, 28464
(... and it goes on and on ...)

So let’s look at the reset vector at address zero. The first IMM opcode loads C000 as the upper 16 bits for the command following, which is a branch immediate command. Together, they make a jump to Oxc000000. Likewise, the software exception jumps to Oxc0001858 and so on.

Since only the block RAM part can be included in the download.bit bitfile, only these jump vectors depend on the ELF file during the “Update bitfile” process. That’s why one gets away with not running this process, even when the ELF has been modified with a plain recompilation.

And now to the bootloop ELF

So what is the bootloop code doing? The headers are no more impressive than

> mb-objdump --headers bootloops/microblaze_0.elf

bootloops/microblaze_0.elf:     file format elf32-microblazele

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
 0 .boot         00000004  00000000  00000000  00000074  2**0
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 1 .text         00000000  00000000  00000000  00000074  2**0
 CONTENTS, ALLOC, LOAD, READONLY, CODE
 2 .data         00000000  00000000  00000000  00000074  2**0
 CONTENTS, ALLOC, LOAD, DATA
 3 .bss          00000000  00000000  00000000  00000078  2**0
 ALLOC

Note the Size column: All entries are empty, except for the .boot section, which is four bytes small (one single instruction). That doesn’t leave room for sophisticated software, and the disassembly is indeed

> mb-objdump --disassemble bootloops/microblaze_0.elf

bootloops/microblaze_0.elf:     file format elf32-microblazele

Disassembly of section .boot:

00000000 <_boot>:
 0:    b8000000     bri    0        // 0

Which is simply an endless loop. So they called it bootloop for a reason.

 

Reader Comments

Thanks quite helpful :)

#1 
Written By Mostafa on July 22nd, 2013 @ 09:06

Bill I am looking for an example to load the .elf via PCIe. I assume this would be via the registers within the Microblaze debug module that could be accessed via a PCIe BAR . This would be similar to Tandem configuration via the PCIe link but for the Microblaze . The other issue is how to load the various sections of the .elf into execution memory and how to initialize the data segments. I like your blog, can you say what WEB tools you use. Best Regards, Bob.

#2 
Written By Bob Dixon on August 20th, 2018 @ 21:54

Add a Comment

required, use real name
required, will not be published
optional, your blog address