IAR EW51: Large CONST array location - linker

In CC2541 (IAR EW51/7.20) project I need to store few large const arrays (~30KB each).
I define the first array:
const uint8 demo_signal_1[30000] = {
0X00,
0X01,
0X10,
// rest of the data
};
It links in XDATA_ROM_C segment and runs just fine.
Then I add another 30KB array in another segment to overcome 32KB limitation:
const uint8 demo_signal_2[30000] = {
0X22,
0X33,
0X44,
// rest of data
}
The linker throws an error:
Error[e104]: Failed to fit all segments into specified ranges. Problem discovered in segment XDATA_ROM_C. Unable to place 96 block(s) (0xe37e byte(s) total) in 0x8000 byte(s) of memory.
Can anyone guide how to locate the second array on its own segment so linking should pass ?
I tried to follow the documentation and the forum but I seem to fail grasp something.
many thanks for any support
Thanks.
UPDATE (pretty long but please bear with me):
I played a little with segments definitions -
I've added two new (CONST)segments to the xcl file:
// Define segments for const data in flash.
// First the segment with addresses as used by the program (flash mapped as XDATA)
-P(CONST)XDATA_ROM_C=0x8000-0xFFFF
-Z(CONST)XDATA_ROM_C2=0x28000-0x2FFFF // Added
-Z(CONST)XDATA_ROM_C3=0x38000-0x3FFFF // Added
//
And defined the arrays to locate in these segments
// Array 1 in it own segment
const uint8 demo_signal_1[28800] # "XDATA_ROM_C2"= {
0X00,
0X00,
0X01,
0X01,
// ...rest of initialization data
}
// Array 2 in it own segment
const uint8 demo_signal_2[28800] # "XDATA_ROM_C3" = {
0X00,
0X00,
0X02,
0X02,
// ...rest of initialization data
}
This time it does link fine and generate the following map file
****************************************
* *
* SEGMENTS IN ADDRESS ORDER *
* *
****************************************
SEGMENT SPACE START ADDRESS END ADDRESS SIZE TYPE ALIGN
======= ===== ============= =========== ==== ==== =====
INTVEC CODE 00000000 - 00000085 86 com 0
CSTART CODE 00000086 - 00000136 B1 rel 0
BIT_ID CODE 00000137 dse 0
BDATA_ID CODE 00000137 dse 0
IDATA_ID CODE 00000137 dse 0
IXDATA_ID CODE 00000137 dse 0
PDATA_ID CODE 00000137 dse 0
DATA_ID CODE 00000137 dse 0
XDATA_ID CODE 00000137 - 0000057A 444 rel 0
BANK_RELAYS CODE 0000057B - 0000151C FA2 rel 0
RCODE CODE 0000151D - 00001C4F 733 rel 0
CODE_N CODE 00001C50 dse 0
DIFUNCT CODE 00001C50 dse 0
NEAR_CODE CODE 00001C50 - 00002C14 FC5 rel 2
<BANKED_CODE> 1 CODE 00002C15 - 00002C17 3 rel 0
<BANKED_CODE,CODE_C> 1
CODE 00002C18 - 00007FFB 53E4 rel 2
<BANKED_CODE,XDATA_ROM_C_FLASH> 1
CODE 00008000 - 0000FFFD 7FFE rel 2
<BANKED_CODE> 2 CODE 00010000 - 00017FF9 7FFA rel 0
<BANKED_CODE> 3 CODE 00018000 - 0001DE08 5E09 rel 0
BLENV_ADDRESS_SPACE
CODE 0003E800 - 0003F7FF 1000 rel 0
REGISTERS DATA 00000000 - 00000007 8 rel 0
VREG DATA 00000008 - 00000017 10 rel 0
PSP DATA 00000018 dse 0
XSP DATA 00000018 - 00000019 2 rel 0
DATA_I DATA 0000001A dse 0
BREG BIT 00000020.0 - 00000020.7 8 rel 0
DATA_Z DATA 00000021 - 00000028 8 rel 0
SFR_AN DATA 00000080 - 00000080 1 rel 0
DATA 00000086 - 0000008A 5
DATA 0000008C - 0000008D 2
DATA 00000090 - 00000091 2
DATA 00000094 - 00000097 4
DATA 0000009A - 000000A9 10
DATA 000000AB - 000000AF 5
DATA 000000B3 - 000000B4 2
DATA 000000B6 - 000000B6 1
DATA 000000B8 - 000000B9 2
DATA 000000BB - 000000C7 D
DATA 000000C9 - 000000C9 1
DATA 000000D1 - 000000DB B
DATA 000000E1 - 000000E9 9
DATA 000000F1 - 000000F5 5
DATA 000000F8 - 000000FA 3
DATA 000000FC - 000000FF 4
XSTACK XDATA 00000001 - 00000280 280 rel 0
XDATA_Z XDATA 00000281 - 00000BE4 964 rel 0
XDATA_I XDATA 00000BE5 - 00001028 444 rel 0
<XDATA_N> 1 XDATA 00001029 - 00001C2A C02 rel 0
XDATA_AN XDATA 0000780E - 00007813 6 rel 0
<XDATA_ROM_C> 1 CONST 00008000 - 00008805 806 rel 2
XDATA_ROM_C2 XDATA 00028000 - 0002F07F 7080 rel 0
XDATA_ROM_C3 XDATA 00038000 - 0003F07F 7080 rel 0
IDATA_I IDATA 00000029 dse 0
IDATA_Z IDATA 00000029 - 0000002A 2 rel 0
ISTACK IDATA 00000040 - 000000FF C0 rel 0
****************************************
* *
* END OF CROSS REFERENCE *
* *
****************************************
126 461 bytes of CODE memory
34 bytes of DATA memory (+ 86 absolute )
7 210 bytes of XDATA memory (+ 6 absolute )
194 bytes of IDATA memory
8 bits of BIT memory
59 654 bytes of CONST memory
Errors: none
Warnings: none
Two observations (scroll to the bottom of the map file):
The CODE size reduced by the 28803 bytes as the size of the original
array located in the original segment, similarly
segment size reduced by same 28803 bytes. and;
Newly added CONST segment (in xcl file) appear as XDATA in the map file
This all would be fine if I could download the generated binary into the chip, but when I try to 'download and debug' I receive the following message:
Fatal Error: Everything you want to place in flash memory must be placed with Xlink CODE memory segment type.
I tried to circumvent and generate intel-extended hex file to flash it standalone but the IDE returns the following error:
Error[e133]: The output format intel-extended cannot handle multiple address spaces. Use format variants (-y -O) to specify which address space is wanted
Reaching so far I tried one more thing and changed the new segments definition to (CODE) as advised by the error message.
// Define segments for const data in flash.
// First the segment with addresses as used by the program (flash mapped as XDATA)
-P(CONST)XDATA_ROM_C=0x8000-0xFFFF
-Z(CODE)XDATA_ROM_C2=0x28000-0x2FFFF // Modified to (CODE)
-Z(CODE)XDATA_ROM_C3=0x38000-0x3FFFF // Modified to (CODE)
Once again it links fine and the map file shows (scroll to the bottom):
****************************************
* *
* SEGMENTS IN ADDRESS ORDER *
* *
****************************************
SEGMENT SPACE START ADDRESS END ADDRESS SIZE TYPE ALIGN
======= ===== ============= =========== ==== ==== =====
INTVEC CODE 00000000 - 00000085 86 com 0
CSTART CODE 00000086 - 00000136 B1 rel 0
DATA_ID CODE 00000137 dse 0
BDATA_ID CODE 00000137 dse 0
BIT_ID CODE 00000137 dse 0
IDATA_ID CODE 00000137 dse 0
IXDATA_ID CODE 00000137 dse 0
PDATA_ID CODE 00000137 dse 0
XDATA_ID CODE 00000137 - 0000057A 444 rel 0
BANK_RELAYS CODE 0000057B - 0000151C FA2 rel 0
RCODE CODE 0000151D - 00001C4F 733 rel 0
DIFUNCT CODE 00001C50 dse 0
CODE_N CODE 00001C50 dse 0
NEAR_CODE CODE 00001C50 - 00002C14 FC5 rel 2
<BANKED_CODE> 1 CODE 00002C15 - 00002C17 3 rel 0
<BANKED_CODE,CODE_C> 1
CODE 00002C18 - 00007FFB 53E4 rel 2
<BANKED_CODE,XDATA_ROM_C_FLASH> 1
CODE 00008000 - 0000FFFD 7FFE rel 2
XDATA_ROM_C2 CODE 00010000 - 0001707F 7080 rel 0
<BANKED_CODE> 2 CODE 00017080 - 00017FF3 F74 rel 0
XDATA_ROM_C3 CODE 00018000 - 0001F07F 7080 rel 0
<BANKED_CODE> 3 CODE 0001F080 - 0001FFF0 F71 rel 0
<BANKED_CODE> 4 CODE 00020000 - 00027FF9 7FFA rel 0
<BANKED_CODE> 5 CODE 00028000 - 0002BF23 3F24 rel 0
BLENV_ADDRESS_SPACE
CODE 0003E800 - 0003F7FF 1000 rel 0
REGISTERS DATA 00000000 - 00000007 8 rel 0
VREG DATA 00000008 - 00000017 10 rel 0
PSP DATA 00000018 dse 0
XSP DATA 00000018 - 00000019 2 rel 0
DATA_I DATA 0000001A dse 0
BREG BIT 00000020.0 - 00000020.7 8 rel 0
DATA_Z DATA 00000021 - 00000028 8 rel 0
SFR_AN DATA 00000080 - 00000080 1 rel 0
DATA 00000086 - 0000008A 5
DATA 0000008C - 0000008D 2
DATA 00000090 - 00000091 2
DATA 00000094 - 00000097 4
DATA 0000009A - 000000A9 10
DATA 000000AB - 000000AF 5
DATA 000000B3 - 000000B4 2
DATA 000000B6 - 000000B6 1
DATA 000000B8 - 000000B9 2
DATA 000000BB - 000000C7 D
DATA 000000C9 - 000000C9 1
DATA 000000D1 - 000000DB B
DATA 000000E1 - 000000E9 9
DATA 000000F1 - 000000F5 5
DATA 000000F8 - 000000FA 3
DATA 000000FC - 000000FF 4
XSTACK XDATA 00000001 - 00000280 280 rel 0
XDATA_Z XDATA 00000281 - 00000BE4 964 rel 0
XDATA_I XDATA 00000BE5 - 00001028 444 rel 0
<XDATA_N> 1 XDATA 00001029 - 00001C2A C02 rel 0
XDATA_AN XDATA 0000780E - 00007813 6 rel 0
<XDATA_ROM_C> 1 CONST 00008000 - 00008805 806 rel 2
IDATA_I IDATA 00000029 dse 0
IDATA_Z IDATA 00000029 - 0000002A 2 rel 0
ISTACK IDATA 00000040 - 000000FF C0 rel 0
****************************************
* *
* END OF CROSS REFERENCE *
* *
****************************************
184 061 bytes of CODE memory
34 bytes of DATA memory (+ 86 absolute )
7 210 bytes of XDATA memory (+ 6 absolute )
194 bytes of IDATA memory
8 bits of BIT memory
2 054 bytes of CONST memory
Errors: none
Warnings: none
Voilla, CONST has shrunk and CODE expanded by exactly 57600 bytes as expected.
It even download and debug and generates hex file.
BUT when debugging the code it appears that instead of accessing 0x28000/0x38000, the memory controller access the data at 0x8000 which is the 'original' (CONST)XDATA_ROM_C segment.
To summarize:
when defining the two new segments as (CONST), the code links but can not debug nor generate hex file and
when defining the two new segments as (CODE), the code links, loads and run but the memory is not accessed correclty.
phew, this was long description. Any ideas someone ????
Note that this thread is duplicated at TI e2e forum as well here

I have the same problem. Seems all data constants need to be in a single 32K segment that gets mapped into the Xdata region. I did a weak work around by using the -Z(CODE)XDATA_ROM_C2=0x38000-0x3FFFF declaration in your second attempt to map my 2nd array of 32K data into BANK6. In my code access routine I cheated by using the HalFlashRead routine to pull 32 bytes chunks into a local array and then index into the local array -- lots of bits missing, but the HaFlash routine expects a 2k page number, offset into page, buffer to place the data, and byte count. This is hardly a solid portable solution but allowed me to move forward. -- hope it helps or gives you more insight
rd_addr = 0x38000 + offset;
HalFlashRead((rd_addr>>0x11)&0xff), (rd_addr & 0x7ff), *ptr32bytes, 32);
realdata = ptr[0]; // offset == [0], offset+1= [1], ....

Related

Cortex M33 missing vector table

I want to test my ARM project within QEMU using semihosting. Initially I built for Cortex A7 and A9 processors and had no issues running my code, however now that I switched to CM33 (and a CM33 board), it breaks immediately:
C:\Program Files\qemu>qemu-system-aarch64.exe -nographic -machine musca-a -cpu cortex-m33 -monitor none -serial stdio
-kernel app -m 512 -semihosting
qemu: fatal: Lockup: can't escalate 3 to HardFault (current priority -1)
R00=00000000 R01=00000000 R02=00000000 R03=00000000
R04=00000000 R05=00000000 R06=00000000 R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=ffffffe0 R14=fffffff9 R15=00000000
XPSR=40000003 -Z-- A S handler
FPSCR: 00000000
If I understand it right, PC=00000000 indicates reset handler issues. I thought maybe this musca-a board expects the table to be somewhere else, but looks like it's missing completely:
psykana#psykana-lap:~$ readelf app -S
There are 26 section headers, starting at offset 0xb1520:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .init PROGBITS 00008000 008000 00000c 00 AX 0 0 4
[ 2] .text PROGBITS 00008010 008010 01d5b4 00 AX 0 0 8
[ 3] .fini PROGBITS 000255c4 0255c4 00000c 00 AX 0 0 4
[ 4] .rodata PROGBITS 000255d0 0255d0 003448 00 A 0 0 8
[ 5] .ARM.exidx ARM_EXIDX 00028a18 028a18 000008 00 AL 2 0 4
[ 6] .eh_frame PROGBITS 00028a20 028a20 000004 00 A 0 0 4
[ 7] .init_array INIT_ARRAY 00038a24 028a24 000008 04 WA 0 0 4
[ 8] .fini_array FINI_ARRAY 00038a2c 028a2c 000004 04 WA 0 0 4
[ 9] .data PROGBITS 00038a30 028a30 000ad8 00 WA 0 0 8
[10] .persistent PROGBITS 00039508 029508 000000 00 WA 0 0 1
[11] .bss NOBITS 00039508 029508 0001c4 00 WA 0 0 4
[12] .noinit NOBITS 000396cc 000000 000000 00 WA 0 0 1
[13] .comment PROGBITS 00000000 029508 000049 01 MS 0 0 1
[14] .debug_aranges PROGBITS 00000000 029551 000408 00 0 0 1
[15] .debug_info PROGBITS 00000000 029959 02e397 00 0 0 1
[16] .debug_abbrev PROGBITS 00000000 057cf0 005b3e 00 0 0 1
[17] .debug_line PROGBITS 00000000 05d82e 01629f 00 0 0 1
[18] .debug_frame PROGBITS 00000000 073ad0 004bf4 00 0 0 4
[19] .debug_str PROGBITS 00000000 0786c4 006a87 01 MS 0 0 1
[20] .debug_loc PROGBITS 00000000 07f14b 01f27e 00 0 0 1
[21] .debug_ranges PROGBITS 00000000 09e3c9 009838 00 0 0 1
[22] .ARM.attributes ARM_ATTRIBUTES 00000000 0a7c01 000036 00 0 0 1
[23] .symtab SYMTAB 00000000 0a7c38 006ec0 10 24 1282 4
[24] .strtab STRTAB 00000000 0aeaf8 002927 00 0 0 1
[25] .shstrtab STRTAB 00000000 0b141f 000100 00 0 0 1
I'm building with the following options (modified toolchain file from my previous question):
add_compile_options(
-mcpu=cortex-m33
-specs=rdimon.specs
-O0
-g
-mfpu=fpv5-sp-d16
-mfloat-abi=hard
)
add_link_options(-specs=rdimon.specs -mcpu=cortex-m33 -mfpu=fpv5-sp-d16 -mfloat-abi=hard)
Again, this worked fine for all A processors I've tried, but breaks for CM33. In fact, it breaks for any M core and M core QEMU board.
For the record:
- arm-none-eabi-gcc (GNU Arm Embedded Toolchain 10.3-2021.10)
- QEMU emulator version 7.0.0 (v7.0.0-11902-g1d935f4a02-dirty)
- Microsoft Windows [Version 10.0.19044.1645]
- cmake version 3.22.
Your guest code has crashed on startup, which is almost always because of problems with your exception vector table. If you use QEMU's -d options (eg -d cpu,int,guest_errors,unimp,in_asm) this will generally give a bit more detail on what exactly happened.
Looking at your ELF headers, it looks like you've not put a vector table into your binary. QEMU requires this (as does real hardware). The usual way to do this is to have a little assembly source file that lays out the data table with the addresses of the various exception entry points, though there are other ways to do this. (This is one example.)
The reason you don't see this on A-profile CPUs is that A-profile exception handling is completely different: on A-profile reset starts execution at address 0x0, and similarly exceptions are taken by setting the PC to a fixed low address. On M-profile reset works by reading the initial PC and SP values from the vector table, and exception handlers start at addresses also read from the vector table. (That is, on A-profile, the thing at the magic low addresses is code, and on M-profile, it is data, effectively function pointers).
Note also that the behaviour of the QEMU -kernel option is different between A-profile and M-profile: on A-profile it will load the ELF file into memory and honour the ELF entry point (execution will start from there). On M-profile it will load the ELF file but then start the CPU from reset in the hardware-specified manner, ie without setting PC to the ELF entry point. (This variation is essentially for historical/back-compat reasons.) If you want "just load my ELF file and set PC to its ELF entry point" you should use QEMU's generic loader device, which behaves the same way on all targets, and not -kernel, which generally means "I am a Linux kernel, please load me in whatever random target-specific plus combination of do-what-I-mean behaviour seems best". -kernel is generally best avoided if you're trying to load a bare-metal binary rather than an actual Linux kernel.
This similar question about getting a working M-profile binary running on QEMU might also be helpful.

Warning: Loadable section "my_section" outside of ELF segments

I have built a axf (elf) file using Arm Compiler v6.9 for Cortex-R4. However when I load this to the target using Arm MCU Eclipse J-link GDB plugins it fails to load the initialisation data for my segments. If I load the axf using Segger Ozone and J-Link it loads the init data correctly.
If I run the arm-none-eabi-gdb.exe on the axf file I get "Warning: Loadable section "my_section" outside of ELF segments" for all my initialised segments.
Looking at the image the initialisation data should be loaded after the image to the addresses specified by the table in Region$$Table$$Base.
We don't have this problem if we link with gcc as the initialised data is done differently.
Any ideas?
I've faced the same issue today and observed the same problem that you described:
"Looking at the image the initialisation data should be loaded after the image to the addresses specified by the table in Region$$Table$$Base."
It seems that although very similar, the ELF file generated by armlink is a bit different than the ELF generated by GCC.
Anyway, I've found a workaround for that.
Checking my main.elf, I noticed that armlinker stored the initialization data into the ER_RW section:
arm-none-eabi-readelf.exe" -S main.elf
There are 16 section headers, starting at offset 0x122b0:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] ER_RO PROGBITS 20000000 000034 001358 00 AX 0 0 4
[ 2] ER_RW PROGBITS 20002000 00138c 0000cc 00 WA 0 0 4
[ 3] ER_ZI NOBITS 200020cc 001458 0004e8 00 WA 0 0 4
[ 4] .debug_abbrev PROGBITS 00000000 001458 0005c4 00 0 0 1
[ 5] .debug_frame PROGBITS 00000000 001a1c 000dc4 00 0 0 1
...
I noticed that the issue happens because GDB loaded ER_RW at addr=0x20002000 but, in fact, I needed it to be loaded just after the of ER_RO section (i.e. at addr=0x20001358)
The workaround for that is:
1- Use fromelf to dump all sections into a binary file main.bin. Fromelf will append ER_RW just after ER_RO, as it is supposed to be:
fromelf.exe --bin -o main.bin main.elf
2- Use objcopy to replace the contents of the ER_RO section with the data from main.bin.
Please notice that we can remove the ER_RW section now since it was already merged with ER_RO into main.bin:
arm-none-eabi-objcopy.exe main.elf --update-section ER_RO=main.bin --remove-section=ER_RW main.gdb.elf
The new main.gdb.elf file can now be loaded by arm-none-eabi-gdb.exe
This is how it looks:
arm-none-eabi-readelf.exe" -S main.gdb2.elf
There are 15 section headers, starting at offset 0x11c0c:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] ER_RO PROGBITS 20000000 000054 001424 00 AX 0 0 4
[ 2] ER_ZI NOBITS 200020cc 000000 0004e8 00 WA 0 0 4
[ 3] .debug_abbrev PROGBITS 00000000 001478 0005c4 00 0 0 1
...
Happy debugging with GDB!! ;-)

Information about Section Index field (st_shndx) in Section SHT_DYNSYM & SHT_SYMTAB

Toolchain:
Product: ARM Compiler 5.04
Component: ARM Compiler 5.04 update 1 (build 49)
From ELF Portable Formats Specification, Version 1.1,
Section Index field (st_shndx) contains:
Every symbol table entry is ‘‘defined’’ in relation to some section; this member holds the relevant section header table index.
I am compiling a simple object (exports one global data & routine) to understand various fields of ELF
Source code (test.c):
__declspec(dllexport) int x21 = 0x100;
__declspec(dllexport) void bar21(void)
{
x21++;
}
Build script used (build.bat)
armcc -c test.c
armlink --bpabi --dll -o test.dll test.o
fromelf -cdrsy -o test.txt test.dll
My query is about usage of st_shndx field of DYNSYM section & SYMTAB section.
Output file
(Removed few sections to keep it short)
** Section #1 'ER_RO' (SHT_PROGBITS) [SHF_ALLOC + SHF_EXECINSTR]
Size : 24 bytes (alignment 4)
Address: 0x00008000
$a
.text
bar21
0x00008000: e59f000c .... LDR r0,[pc,#12] ; [0x8014] = 0
0x00008004: e5901000 .... LDR r1,[r0,#0]
0x00008008: e2811001 .... ADD r1,r1,#1
0x0000800c: e5801000 .... STR r1,[r0,#0]
0x00008010: e12fff1e ../. BX lr
$d
0x00008014: 00000000 .... DCD 0
** Section #2 'ER_RW' (SHT_PROGBITS) [SHF_ALLOC + SHF_WRITE]
Size : 4 bytes (alignment 4)
Address: 0x00000000
0x000000: 00 01 00 00 ....
** Section #3 '.dynstr' (SHT_STRTAB)
Size : 32 bytes
** Section #4 '.dynsym' (SHT_DYNSYM)
Size : 80 bytes (alignment 4)
String table #3 '.dynstr'
Last local symbol no. 1
Symbol table .dynsym (4 symbols, 1 local)
# Symbol Name Value Bind Sec Type Vis Size
========================================================================
1 .data 0x00000000 Lc 1 Sect De 0x4
2 shared_2.dll 0x00000000 Gb Abs Data De
3 x21 0x00000000 Gb 1 Data Pr 0x4
4 bar21 0x00008000 Gb 2 Code Pr 0x14
** Section #5 '.hash' (SHT_HASH)
Size : 40 bytes (alignment 4)
Symbol table #4 '.dynsym'
<Section Truncated>
** Section #7 '.version' (SHT_GNU_versym)
Size : 10 bytes (alignment 4)
Symbol table #4 '.dynsym'
<Section Truncated>
** Section #8 '.version_d' (SHT_GNU_verdef)
Size : 56 bytes (alignment 4)
String table #3 '.dynstr'
<Section Truncated>
** Section #9 '.dynamic' (SHT_DYNAMIC)
Size : 120 bytes (alignment 4)
String table #3 '.dynstr'
<Section Truncated>
** Section #10 '.debug_frame' (SHT_PROGBITS)
Size : 68 bytes
** Section #11 '.symtab' (SHT_SYMTAB)
Size : 176 bytes (alignment 4)
String table #12 '.strtab'
Last local symbol no. 6
Symbol table .symtab (10 symbols, 6 local)
# Symbol Name Value Bind Sec Type Vis Size
========================================================================
1 $a 0x00008000 Lc 1 -- De
2 $d 0x00008014 Lc 1 -- De
3 $d.realdata 0x00000000 Lc 2 -- De
4 shared_2.c 0x00000000 Lc Abs File De
5 .text 0x00008000 Lc 1 Sect De
6 .data 0x00000000 Lc 2 Sect De 0x4
7 BuildAttributes$$ARM_ISAv4$S$PE$A:L22$X:L11$S22$IEEE1$~IW$USESV6$~STKCKD$USESV7$~SHL$OSPACE$EBA8$STANDARDLIB$REQ8$PRES8$EABIv2
0x00000000 Gb Abs -- Hi
8 shared_2.dll 0x00000000 Gb Abs Data De
9 x21 0x00000000 Gb 2 Data Pr 0x4
10 bar21 0x00008000 Gb 1 Code Pr 0x14
Section 1 is Code area (bar21 routine is present here)
Section 2 is RW area (x21 variable is present here)
Now, if we see st_shndx (section index -- marked as "Sec" in output above) field in DYNSYM section & SYMTAB section for these two variables is different.
For Example:
x21 in DYNSYM points to section 1 (code area) & in SYMTAB, it points to section 2 (RW area)
Can someone help me understand why? Or guide me to resource where I can get more information on this.
Regards,
Raju Udava

Link error between C and assembly

I'm compiling a c file foo.c:
#include <stdlib.h>
extern void *memcpy_optimized(void* __restrict, void* __restrict, size_t);
void foo() {
[blah blah blah]
memcpy_optimized((void *)a, (void *)b, 123);
}
then I have the assembly file memcpy_optimized.S:
.text
.fpu neon
.global memcpy_optimized
.type memcpy_optimized, %function
.align 4
memcpy_optimized:
.fnstart
mov ip, r0
cmp r2, #16
blt 4f # Have less than 16 bytes to copy
# First ensure 16 byte alignment for the destination buffer
tst r0, #0xF
beq 2f
tst r0, #1
ldrneb r3, [r1], #1
[blah blah blah]
.fnend
Both files compile fine with: gcc $< -o $# -c
but when I link the application with both resulting objects, I get the following error:
foo.c:(.text+0x380): undefined reference to `memcpy_optimized(void*, void *, unsigned int)'
Any idea what I'm doing wrong?
readelf -a obj/memcpy_optimized.o
ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: REL (Relocatable file)
Machine: ARM
Version: 0x1
Entry point address: 0x0
Start of program headers: 0 (bytes into file)
Start of section headers: 436 (bytes into file)
Flags: 0x5000000, Version5 EABI
Size of this header: 52 (bytes)
Size of program headers: 0 (bytes)
Number of program headers: 0
Size of section headers: 40 (bytes)
Number of section headers: 11
Section header string table index: 8
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 00000000 000040 0000f0 00 AX 0 0 16
[ 2] .data PROGBITS 00000000 000130 000000 00 WA 0 0 1
[ 3] .bss NOBITS 00000000 000130 000000 00 WA 0 0 1
[ 4] .ARM.extab PROGBITS 00000000 000130 000000 00 A 0 0 1
[ 5] .ARM.exidx ARM_EXIDX 00000000 000130 000008 00 AL 1 0 4
[ 6] .rel.ARM.exidx REL 00000000 00044c 000010 08 9 5 4
[ 7] .ARM.attributes ARM_ATTRIBUTES 00000000 000138 000023 00 0 0 1
[ 8] .shstrtab STRTAB 00000000 00015b 000056 00 0 0 1
[ 9] .symtab SYMTAB 00000000 00036c 0000b0 10 10 9 4
[10] .strtab STRTAB 00000000 00041c 00002f 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
There are no program headers in this file.
Relocation section '.rel.ARM.exidx' at offset 0x44c contains 2 entries:
Offset Info Type Sym.Value Sym. Name
00000000 0000012a R_ARM_PREL31 00000000 .text
00000000 00000a00 R_ARM_NONE 00000000 __aeabi_unwind_cpp_pr0
Unwind table index '.ARM.exidx' at offset 0x130 contains 1 entries:
0x0 <memcpy_optimized>: 0x80b0b0b0
Compact model 0
0xb0 finish
0xb0 finish
0xb0 finish
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00000000 0 SECTION LOCAL DEFAULT 1
2: 00000000 0 SECTION LOCAL DEFAULT 2
3: 00000000 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 NOTYPE LOCAL DEFAULT 1 $a
5: 00000000 0 SECTION LOCAL DEFAULT 4
6: 00000000 0 SECTION LOCAL DEFAULT 5
7: 00000000 0 NOTYPE LOCAL DEFAULT 5 $d
8: 00000000 0 SECTION LOCAL DEFAULT 7
9: 00000000 0 FUNC GLOBAL DEFAULT 1 memcpy_optimized
10: 00000000 0 NOTYPE GLOBAL DEFAULT UND __aeabi_unwind_cpp_pr0
No version information found in this file.
Attribute Section: aeabi
File Attributes
Tag_CPU_name: "7-A"
Tag_CPU_arch: v7
Tag_CPU_arch_profile: Application
Tag_ARM_ISA_use: Yes
Tag_THUMB_ISA_use: Thumb-2
Tag_FP_arch: VFPv3
Tag_Advanced_SIMD_arch: NEONv1
Tag_DIV_use: Not allowed
It seems to me that you compiled your foo.c as C++, hence the linking error. What made me say that is that the linker reported the full prototype of the missing function. C functions do not have their full prototype as their symbol (just the name of function), however the C++ mangled names represent the full prototype of the function.
In many Unix and GCC C implementations, names in C are decorated with an initial underscore in object code. So, to call memcpy_optimized in C, you must use the name _memcpy_optimized in assembly.

What address does the text section start?

I read in a book (can't recollect the name) that in a 32 bit system text section always starts at 0x0848000. But when I do readelf -S example_executable it does not reflect the same information. Why is that? Do other sections (bss,data,rodata etc) also start at fixed addresses? How can I find the alignment boundary for these sections?
There is a good explanation here of how Linux virtual memory works when allocating storage for a particular program.
ua alberta - linux memory allocation
The designers of the compiler/linker tool chain need to allocate an arbitary address for particular blocks of memory. In order to make it easier for other components of the tool chain like debuggers and profilers they always allocatate the same block to the same addresses. The actual addresses chosen are completely arbitrary.
When the program is loaded the virtual address will be mapped to some random piece of free memory (this is mostly done in hardware). This mapping is done on a per process basis to several programs can address virtual address x'0848000' but be pointed at different "real" memory addresses.
It all depends on the implementation on the particular machine.For a linux machine the behaviour will be different than that from windows machine.
Note however that the virtual memory addresses need to start at some fixed address in order to make life easier for debuggers.However the real addresses will be different depending on the pages available in RAM.
If you look the output of readelf -S more carefully you will notice you will notice subtracting the offset from the address indeed gives you 0x0848000.
As i had mentioned earlier this magic number 0x0848000 will depend on the type of executable format.
here is the output i get on my ubuntu 32 bit machine:
readelf -S ~/a.out
There are 29 section headers, starting at offset 0x1130:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048134 000134 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048148 000148 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048168 000168 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 0804818c 00018c 000020 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481ac 0001ac 000050 10 A 6 1 4
[ 6] .dynstr STRTAB 080481fc 0001fc 00004c 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048248 000248 00000a 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048254 000254 000020 00 A 6 1 4
[ 9] .rel.dyn REL 08048274 000274 000008 08 A 5 0 4
[10] .rel.plt REL 0804827c 00027c 000018 08 A 5 12 4
[11] .init PROGBITS 08048294 000294 000030 00 AX 0 0 4
[12] .plt PROGBITS 080482c4 0002c4 000040 04 AX 0 0 4
[13] .text PROGBITS 08048310 000310 00018c 00 AX 0 0 16
[14] .fini PROGBITS 0804849c 00049c 00001c 00 AX 0 0 4
There is no consistent address between operating systems and architectures for the text section or any other section. Additionally position independent code and address space layout randomizations make these values even inconsistent on the same machine for some systems.

Resources