AREA Field in ARM Assembly - arm

Hi I'm using the Keil uVision compiler for ARM assembly. I'm just starting out learning this and I have the following code in my program.
AREA PROGRAM, CODE, READONLY
EXPORT SYSTEMINIT
EXPORT __MAIN
SYSTEMINIT
__MAIN
MOV R1, #0X25
MOV R2, #0X23
END
When I build the target it says
test.s(1): error: A1163E: Unknown opcode PROGRAM, , expecting opcode or Macro
I'm not sure why that is. The code above s the code I was given to run as a sample to make sure its working. Shouldn't I be able to put anything in for AREA? Any help is appreciated.

That error message is informative, if a little hard to decipher: anything that starts in the first column is considered to be a label, so the assembler sees a label named "AREA", then tries to interpret "PROGRAM," as a mnemonic, macro, or directive, which obviously fails since it isn't.
In short, directives need to be indented, just like instructions; this assembles just fine:
AREA PROGRAM, CODE, READONLY
EXPORT SYSTEMINIT
EXPORT __MAIN
SYSTEMINIT
__MAIN
MOV R1, #0X25
MOV R2, #0X23
END

The AREA directive instructs the assembler to assemble a new code or data section. Sections are independent, named, indivisible chunks of code or data that are manipulated by the linker.
Syntax
AREA sectionname{,attr}{,attr}...
where:
sectionname s the name to give to the section. You can choose any name for your sections.
So check you have the same name in both places: right after the AREA directive and somewhere in your code.
Further reading about directives you can find here.

Related

GCC startup code _start does not end in main()

I could only find bits and pieces of information on the symbol _start, which is called from the target startup code in order to establish the C runtime environment. This would be necessary to ensure that all initialized global/static variables are properly loaded prior to branching to main().
In my case, I am using an MCU with an ARM Cortex-R4F core CPU. When the device resets, I implement all of the steps recommended by the MCU manufacturer then attempt to branch to the symbol _start using the following lines of code:
extern void _start(void);
_start();
I am using something similar to the following to link the program:
armeb-eabi-gcc-7.5.0" -marm -fno-exceptions -Og -ffunction-sections -fdata-sections -g -gdwarf-3 -gstrict-dwarf -Wall -mbig-endian -mcpu=cortex-r4 -Wl,-Map,"app_tms570_dev.map" --entry main -static -Wl,--gc-sections -Wl,--build-id=none -specs="nosys.specs" -o[OUTPUT FILE NAME HERE] [ALL OBJECT FILES HERE] -Wl,-T[LINKER COMMAND FILE NAME HERE]
My toolchain in this case is gcc-linaro-7.5.0-2019.12-i686-mingw32_armeb-eabi, which is being used since my MCU device is big-endian.
As I trace through the call to symbol _start, I can see my program branch to symbol _start then a few unexpected things happen.
First, there are a couple of places where the following instruction is called:
EF123456 svc #0x123456
This basically generates a software interrupt, which causes the program to branch to the software interrupt handler that I have configured for the device.
Secondly, the device eventually branches to __libc_init_array then _init. However, symbol _init does not contain any branch instruction and allows the program to flow into _fini, which also does not contain any branch instruction and allows the program to flow into whatever code was placed next in memory. This eventually causes some type of abort exception, as would be expected.
The disassembly associated with _init and _fini:
_init():
00003b00: E1A0C00D mov r12, r13
00003b04: E92DDFF8 push {r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r14, pc}
00003b08: E24CB004 sub r11, r12, #4
_fini():
00003b0c: E1A0C00D mov r12, r13
00003b10: E92DDFF8 push {r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r14, pc}
00003b14: E24CB004 sub r11, r12, #4
Based on some other documentation I read, I also attempted to call main() directly, but this just caused the program to jump to main() without initializing anything. I also tried to call symbol __main() similar to what is done when using the ARM Compiler in order to execute startup code, but this symbol is not found.
Note that this is for a bare-metal-ish system that does not use semihosting.
My question is: Is there a way to set up the system and call a function that will establish the C runtime environment automatically and branch to main() using the GCC linker?
For the time being, I have implemented my own function to initialize .data sections and the .bss sections are already being zeroed at reset using a built in feature of the MCU device.
Adding some more details here:
The specific MCU that I am using should not be relevant, particularly taking the following discussion into consideration.
First, I have already set up the exception vectors for the device in an assembler file:
.section .excvecs,"ax",%progbits
.type Exc_Vects, %object
.size Exc_Vects, .-Exc_Vects
// See DDI0363G, Table 3-6
Exc_Vects:
b c_int00 // Reset vector
b exc_undef // Undefined instruction
b exc_software // Software
b exc_prefetch // Pre-fetch abort
b exc_data // Data abort
b exc_invalid // Invalid vector
There are two instructions that follow for the IRQ and FIQ interrupts as well, but they are set according to the MCU datasheet. I have defined handlers for the undefined instruction, prefetch abort, data abort and invalid vector exceptions. For the software exception I use some assembly to jump to an address that can be changed at runtime. My startup sequence begins at c_int00. These have all been tested and work with no problems.
My reset handler takes care of all of the steps needed for initializing the MCU in accordance with the MCU datasheet. This include initializing CPU registers and the stack pointers, which are loaded using symbols from the linker file.
The toolchain that I am using, noted above, includes the C standard libraries and other libraries needed to compile and link my program with no problems. This includes the symbol _start that I mentioned previously.
From what I understand, the function _start typically wraps main(). Before it calls main() it initializes .bss and .data sections, configures the heap, as well as performing some other tasks to set up the environment. When main() returns, it performs some clean up tasks and branches to a designated exit() function. (Side note: _start is defined in newlib based on the source code that I downloaded from linaro).
There is some detail regarding this in a separate response here:
What is the use of _start() in C?
I have been using the ARM Compiler as an alternative for the same project. There, __main performs these functions. For the stack initialization, I basically provide it an empty hook function and for exit I provide it with a function that safely terminates the program should main() return for some reason. I am not sure if something like this is needed for GCC.
I would note that I have included option -specs="nosys.specs" without option -nostartfiles. My understanding is that this avoids implementing some of the functions that do not want to use in my application, such as I/O operations, but links the startup code.
I am not using the heap in my project as dynamic memory use is frowned upon, but I was hoping to be able to use the startup code primarily in order to avoid having to remember to initialize .data sections manually. Above I noted that my application is baremetal-ish. I am actually using an RTOS and have the memory partitioned into blocks so that I can use the device MPU.

What is __0sprintf in Keil's C library? How to use it to save code size vs. full sprintf?

I am trying to use sprintf standard C function in ARM assembler code, in Keil uVision, for STM32.
Looking in example C project disassembly, I can see this:
54: sprintf( test_string, format_string, num);
0x080028C2 F1000110 ADD r1,r0,#0x10
0x080028C6 E9D02302 LDRD r2,r3,[r0,#0x08]
0x080028CA 4810 LDR r0,[pc,#64] ; #0x0800290C
0x080028CC F7FFFB66 BL.W __0sprintf (0x08001F9C)
C code disassembly calls function __0sprintf.
In my assembly program, I write such code:
LDR r0, =Data_string
LDR r1, =Format_str
;r2 & r3 loaded above
BL sprintf
And it works well, but takes up to 11 kB.
If I call __0sprintf function in my code:
LDR r0, =Data_string
LDR r1, =Format_str
;r2 & r3 loaded above
BL __0sprintf
it takes up much less, about 5 kB - but do not work.
I can not find in Google any information about __0sprintf function or something about it. Where can I read about these functions? May be I can understand why it is not working?
I can not find in Google any information about __0sprintf function or something about it.
Names beginning with two underscores are reserved for the implementation.
That means you're not allowed to use them in your code, but it also means that if you see one, it's probably an internal implementation detail.
Where can I read about these functions?
If it's an implementation detail, all you can do is check the documentation for that implementation, ask the vendor or examine the source if it's available, or search to see if someone else has already investigated or decompiled this function.
May be I can understand why it is not working?
You can always try disassembling that function from your vendor's runtime library (assuming that doesn't breach some license), or try instruction-stepping into it if the platform has an interactive debugger.
Otherwise, your best bet is to figure out how to write some regular C code that calls the same implementation, and compare the call sites.

ARM Assembly - Why does my app crash when zeroing r7?

I'm currently having a weird issue when trying to run a C program that calls a very simple ARM assembly function. Here's my C code:
#include <stdio.h>
#include <stdlib.h>
extern void getNumber(int* pointer);
int main()
{
int* pointer = malloc(sizeof(int));
getNumber(pointer);
printf("%d\n", *pointer);
return 0;
}
And here's my assembly code:
.section .text
.align 4
.arm
.global getNumber
.type getNumber STT_FUNC
getNumber:
mov r1, #0
str r1, [r0]
bx lr
So far so good. However, if I add a line with mov r7, #0 at the top of getNumber, the program segfaults when trying to access pointer. After inspecting it with gdb I noticed now the pointer itself is stored at a very low address, such as 0xa.
Now, I did a bit of research and apparently r7 is the frame pointer for THUMB code (according to this). However, I'm clearly stating I don't want to use THUMB instructions in the .arm line in my assembly code. Why on earth is it failing?
I'm compiling both the .c and .s files using arm-linux-gnueabihf-gcc, and I'm running the program on a Cortex-A8 based board running Arch Linux.
Edit: The program runs fine if I compile using the -fomit-frame-pointer flag. However, I still want to know why is it using r7 as the frame pointer.
Edit 2: It's still failing even if I use .code 32 instead of .arm.
The ARM Procedure Call Standard specifies the following:
A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variants that designate r9 as v6).
So your assembly language subroutine must save & restore r7 if it uses it.
You might be avoiding the problem with your small test program by by not compiling for Thumb mode, but you're just accidentally avoiding the problem. Anything that links to your assembly routine is entitled to expect that r7 will be preserved.
You're crashing the program because your are corrupting the frame pointer, like you mentioned. There is really no rhyme or reason to the convention. Just that ARM reserves certain registers for certain things. Kinda like in x86 esp is the stack pointer.
Here's a pretty good reference for registers to avoid:
http://msdn.microsoft.com/en-us/library/ms253599(v=vs.80).aspx
I finally got it: doing $ arm-linux-gnueabihf-gcc -v showed me the default options my compiler is using. Among those is: --with-mode=thumb.
Compiling with -marm fixed it. Now it's working as intended!
Edit: Upon reading the comments here I realize I was mistaken. I should've saved/restored r7 so it wouldn't screw up the rest of my program. Good thing I learned this now with a toy project and not while working on something real!

ARM + gcc: don't use one big .rodata section

I want to compile a program with gcc with link time optimization for an ARM processor. When I compile without LTO, the system gets compiled. When I enable LTO
(with -flto), I get the following assembler-error:
Error: invalid literal constant: pool needs to be closer
Looking around the web I found out that this has something to do with the constants in my system, which are placed in a special section called .rodata, which is called a constant pool and is placed right after the .text section in my system. It seems that when compiling with LTO because of inlining and other optimizations this .rodata section gets too far away from the instructions, so that the addressing of the constants is not possible anymore. Is it possible to place the constants right after the function that uses them? Or is it possible to use another addressing mode so the .rodata section can still be addressed? Thanks.
This is an assembler message, not a linker message, so this happens before sections are generated.
The assembler has a pseudo instruction for loading constants into registers:
ldr r0, =0x12345678
this is expanded into
ldr r0, [constant_12345678, r15]
...
bx lr
constant_12345678:
dw 0x12345678
The constant pool usually follows the return instruction. With function inlining, the function can get long enough that the return instruction is too far away; unfortunately, the compiler has no idea of the distance between memory addresses, and the assembler has no idea of control flow other than "flow does not pass beyond the return instruction, so it is safe to emit the constant pool here".
Unfortunately, there is no good solution at the moment.
You could try an asm block containing
b 1f
.ltorg
1:
This will force-emit the constant pool at this point, at the cost of an extra branch instruction.
It may be possible to instruct the assembler to omit the branch if the constant pool is empty, but I cannot test that at the moment, so this is probably not valid:
.if (2f - 1f)
.b 2f
.endif
1:
.ltorg
2:
"This is an assembler message, not a linker message, so this happens before sections are generated" - I am not sure but I think it is a little bit more complicated with LTO. Compiling (including assembling) of the individual c-files with LTO enabled works fine and does not cause any problems. The problem occurs when I try to link them together with LTO enabled. I don't know how LTO is exactly done, but apparently this also includes calling the assembler again and then I get this error message. When linking without LTO, everything is fine and when I look at the disassemly I can see that my constants are not placed after a function. Instead all constants are placed in the .rodata section. With LTO enabled because of inlining, my functions probably get to large to reach the constant pool...

What is the role of .s files in a C project?

I am working with an ARM Cortex M3 chip (STM32F2) and ST provides a "standard peripheral library". It has some useful .c and .h files. It also has .s files.
What is the purpose of these .s files in the context of a C project? How do I get my compiler/linker/? to take them into account?
The .s extension is the convention used by GNU and many other tool-chains for assembler files.
Last I looked the STM32 Standard Peripheral Library itself contains no assembler files, however the CMSIS library contains start-up code for various STM32 parts, for example startup_stm32f2xx.s is start-up code for all STM32F2xx series devices. There are different implementations for different tool-chains; you need to build and link the file associated with your specific part and tool-chain. If you are using an example project that builds and runs or an IDE that creates part-specific projects for you, this will probably already have been done - if you have code that runs it certainly has.
How you build and link the code will depend on what tool-chain you are using. Most IDE based tools will automatically recognise the extension and invoke the assembler to generate an object file that will be linked like any other. The exact content differs slightly between tool-chain versions, but primarily creates the C runtime environment (stack and heap), initialises the processor, defines an initial interrupt/exception vector table, initialises static data and jumps to main().
The core of the file for the Keil/ARM RealView version for example looks like this:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
Reset_Handler is the address Program Counter (PC) register will be set to after a processor reset.
SystemInit is an external C code function that does the bulk of the initialisation - this may need customisation for your hardware. Cortex-M is unusual in that it can start running C code immediately after reset because the vector table includes both the reset address and the initial stack pointer address, which is automatically loaded to the SP register on reset. As a result you do not need much assembler knowledge to get one running.
__main() is the compiler supplied entry point for your C code. It is not the main() function you write, but performs initialisation for the standard library, static data, the heap before calling your `main()' function.
The GCC version is somewhat more involved since it does much of the work done by __main() in the Keil/ARM RealView version, but essentially it performs the same function.
Note that in the CMSIS SystemInit() is defined in system_stm32f2xx.c, and may need customisation for your board (correct crystal frequency, PLL setup, external SRAM configuration etc.). Because this is C code, and well commented, you will probably be more comfortable with it.
They usually contain assembly code. The assembler turns them into object files which are later linked by the linker with the main stuff. But I imagine it does depend on the compiler, toolchain etc.
The .s files usually contain the Vector tables. It defines what should the system do when an interrupt occurs. This table (code) is placed in a memory address defined by you in linker file. For example, every time a reset occurs what or rather where should your processor begin from , what code should it run. similarly, there are other handlers ( interrupt vectors). In STM32 , usually the controller loops on particular handlers.
As given in the below example:See this link for detailed explanation
.section INTERRUPT_VECTOR, "x"
.global _Reset
_Reset:
B Reset_Handler /* Reset */
B . /* Undefined */
B . /* SWI */
B . /* Prefetch Abort */
B . /* Data Abort */
B . /* reserved */
B . /* IRQ */
B . /* FIQ */
Reset_Handler:
LDR sp, =stack_top
BL c_entry
B .
This assembly code later is converted to object files and linked with your .c files and .ld to create a .elf or .bin files.
You've probably got a Keil-based development environment for your ST kit. Depending on the version of your compiler, the project file should have different sections for C, C++, and assembler code. In your IDE, open your project and look for "Project Properties" or something like it.
You can import and export symbols to and from the assembler code so that it and the C/C++ code will link. With Keil it all integrates reasonably well.
The EXPORT directive tells the assembler to make the specified symbol public so that your C/C++ code can link to it.
The IMPORT directive tells the assembler that the specified symbol is defined elsewhere and will be resolved at link time.

Resources