Linker script: mixing memory regions and location assignments - embedded

I have been looking at some linker scripts for embedded ARM processors. In one of them, there's something like this (minimal example):
MEMORY {
REGION : ORIGIN = 0x1000, LENGTH = 0x1000
}
SECTIONS {
.text : {
/* ... */
. = 0x20;
/* ... */
} > MEMORY
}
This linker script states that the section .text should go in the memory region REGION, which starts at 0x1000. However, within the section contents, the location is explicitly set to 0x20.
Is this location assignment relative to the start of the region that the section is in? Or absolute? In general, how do regions and location assignments work together?

I did a test. I created an assembly file with the following contents:
.text
.word 0x1234
Then I wrote a basic linker script as detailed in the question:
MEMORY {
REGION : ORIGIN = 0x100, LENGTH = 0x100
}
SECTIONS {
.text : {
. = 0x20;
*(.text);
} > REGION
}
I compiled the assembly file to an object file with GCC, then linked the object file into an "executable" with ld. Running objdump -s on the result, I found that 0x1234 was at address 0x120. This means that the location assignment is relative to the start of the memory region.

Related

problem with sprint/printf with freeRTOS on stm32f7

Since two days I am trying to make printf\sprintf working in my project...
MCU: STM32F722RETx
I tried to use newLib, heap3, heap4, etc, etc. nothing works. HardFault_Handler is run evry time.
Now I am trying to use simple implementation from this link and still the same problem. I suppose my device has some problem with double numbers, becouse program run HardFault_Handler from this line if (value != value) in _ftoa function.( what is strange because this stm32 support FPU)
Do you guys have any idea? (Now I am using heap_4.c)
My compiller options:
target_compile_options(${PROJ_NAME} PUBLIC
$<$<COMPILE_LANGUAGE:CXX>:
-std=c++14
>
-mcpu=cortex-m7
-mthumb
-mfpu=fpv5-d16
-mfloat-abi=hard
-Wall
-ffunction-sections
-fdata-sections
-O1 -g
-DLV_CONF_INCLUDE_SIMPLE
)
Linker options:
target_link_options(${PROJ_NAME} PUBLIC
${LINKER_OPTION} ${LINKER_SCRIPT}
-mcpu=cortex-m7
-mthumb
-mfloat-abi=hard
-mfpu=fpv5-sp-d16
-specs=nosys.specs
-specs=nano.specs
# -Wl,--wrap,malloc
# -Wl,--wrap,_malloc_r
-u_printf_float
-u_sprintf_float
)
Linker script:
/* Highest address of the user mode stack */
_estack = 0x20040000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 256K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}
UPDATE:
I don't think so it is stack problem, I have set configCHECK_FOR_STACK_OVERFLOW to 2, but hook function is never called. I found strange think: This soulution works:
float d = 23.5f;
char buffer[20];
sprintf(buffer, "temp %f", 23.5f);
but this solution not:
float d = 23.5f;
char buffer[20];
sprintf(buffer, "temp %f",d);
No idea why passing variable by copy, generate a HardFault_Handler...
You can implement a hard fault handler that at least will provide you with the SP location to where the issue is occurring. This should provide more insight.
https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html
It should let you know if your issue is due to a floating point error within the MCU or if it is due to a branching error possibly caused by some linking problem
I also had error with printf when using FreeRTOS for my SiFive HiFive Rev B.
To solve it, I rewrite _fstat and _write functions to change output function of printf
/*
* Retarget functions for printf()
*/
#include <errno.h>
#include <sys/stat.h>
int _fstat (int file, struct stat * st) {
errno = -ENOSYS;
return -1;
}
int _write (int file, char * ptr, int len) {
extern int uart_putc(int c);
int i;
/* Turn character to capital letter and output to UART port */
for (i = 0; i < len; i++) uart_putc((int)*ptr++);
return 0;
}
And create another uart_putc function for UART0 of SiFive HiFive Rev B hardware:
void uart_putc(int c)
{
#define uart0_txdata (*(volatile uint32_t*)(0x10013000)) // uart0 txdata register
#define UART_TXFULL (1 << 31) // uart0 txdata flag
while ((uart0_txdata & UART_TXFULL) != 0) { }
uart0_txdata = c;
}
The newlib C-runtime library (used in many embedded tool chains) internally uses it's own malloc-family routines. newlib maintains some internal buffers and requires some support for thread-safety:
http://www.nadler.com/embedded/newlibAndFreeRTOS.html
hard fault can caused by unaligned Memory Access:
https://www.keil.com/support/docs/3777.htm

STM32F303VCT6 external interrupt with PA0 button won't toggle LED

I want to use a button connected to PA0 as an external interrupt to toggle LED on PE14 on button press. However calling the configure_PA0 function doesn't seem to work.
I did a simple blinking instruction in while loop to test and it turns out when I call configure_PA0 the LED stays ON all the time.
Without calling it, the LED will blink just fine so I think it must be something wrong with this function.
#include "stm32f30x.h"
void delay(volatile uint32_t count){
while(count > 0 )
count--;
}
void init_LED(){ //init led on PE14
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE,&GPIO_InitStructure);
}
void configure_PA0(void) {
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//PA0 as button init
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
//EXTI init
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource0);
EXTI_InitStruct.EXTI_Line = EXTI_Line0;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_Init(&EXTI_InitStruct);
//NVIC init
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x00;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
}
void toggle_PE14(){
if(GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_14) == 0)
GPIO_SetBits(GPIOE,GPIO_Pin_14);
else
GPIO_ResetBits(GPIOE,GPIO_Pin_14);
}
//handle pa0 interrupt
void EXTI0_IRQHandler(void) {
if(EXTI_GetITStatus(EXTI_Line0) != RESET){
toggle_PE14();
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
int main(void) {
init_LED();
configure_PA0();
while (1) {
delay(400);
}
return 0;
}
UPDATE
I fixed it by putting handler definition into extern "C" { .. } brackets. Apparently you have to do that if you code in C++.
UPDATE ...
First, thanks for letting other readers know!
Let me explain the causal relationship of these findings:
... I fixed it by putting handler definition into extern "C" { /* .. */ }
brackets.
Apparently you have to do that if you code in C++.
When programming in C++ (i.e., for those language features that are both valid in C and C++, when using a C++ compiler to build the program) there is a difference between C++ symbols and C symbols in the object code used by the linker.
In a nutshell, this is done because C++ identifiers must be extended by some type information in order to support polymorphism.
Details are explained
here.
Any C++ function which is defined without extern C qualifiers will get an extended ("mangled") symbol.
This also applies to "ambiguous" functions fed into the C++ compiler like in the present case.
Any extern C function (and any function translated by a C compiler, if one mixes compilers) will turn into a linker symbol with an unmangled name (usually only extended by some underscores, depending on the toolchain used).
The point is: Assembler functions behave mostly like C functions - function symbols referenced/defined in assembler code will be passed to the linker just as they are.
Usually (and in the present example), this is also the case for the definition of the STM32 interrupt vector table
(both following code snippets are taken from startup_stm32l476xx.s):
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
/*...*/
.word PendSV_Handler
.word SysTick_Handler
/*...*/
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
/*...*/
and for the weak function definition linking to the DefaultHandler in default STM32CubeF3 / STM32CubeMX code
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
/*...*/
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
/*...*/
This means that the linker found
a reference to C symbol EXTI0_IRQHandler in the vector table,
a (weak but unique) definition of C symbol EXTI0_IRQHandler
a (non-weak but mismatching) definition of a mangled C++ symbol based on EXTI0_IRQHandler.
It matched (1.) with (2.) and discarded (3.) for not being referenced, so the first interrupt produced at the external pin threw the MCU into the endless loop DefaultHandler and the LED stopped blinking.

Linker script :: Dynamic Memory section

I would like to have a dynamic Memory map, like example to have flash spliced in 5 sections and according to a define in some file .h to set a proper memory map. But have some problems to do it :)
So this region would be dynamic allocated by defines in some .h
MEMORY
{
if SOME_DEFINE == PART0
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash, 256K */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00006000 /* sram, 24K */
else
rom (rx) : ORIGIN = 0x00400000, LENGTH = 0x00040000 /* flash, 256K */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00006000 /* sram, 24K */
endif
}
I've addressed a similar need before using variables:
Define a master linker script, looking something like this:
$ head common_layout.ld
/* You can do something like this for optional sections */
CCFG_ORIGIN = DEFINED(CCFG_ORIGIN) ? CCFG_ORIGIN : 0;
CCFG_LENGTH = DEFINED(CCFG_LENGTH) ? CCFG_LENGTH : 0;
MEMORY
{
rom (rx) : ORIGIN = ROM_ORIGIN, LENGTH = ROM_LENGTH
ccfg (rx) : ORIGIN = CCFG_ORIGIN, LENGTH = CCFG_LENGTH
ram (rwx) : ORIGIN = RAM_ORIGIN, LENGTH = RAM_LENGTH
}
Then, for each chip you're dealing with, you can create a file with specifics for that chip (or have your build system create a temp file on the fly if it's really that dynamic):
$ cat chip_layout.ld
/* Memory Spaces Definitions */
ROM_ORIGIN = 0x00010000; /* Bootloader is at 0x0000 */
ROM_LENGTH = 0x00020000;
RAM_ORIGIN = 0x20000000;
RAM_LENGTH = 0x00020000;
Then point your build tool to something that stitches them together, i.e. gcc -Tlayout.ld ...
$ cat layout.ld
INCLUDE ./chip_layout.ld
INCLUDE ../kernel_layout.ld

How to make a pass that can read LLVM IR and parse it

I had read this page , http://llvm.org/docs/WritingAnLLVMPass.html
And i can do the example of the Hello.so completely.
Now i just want to make a .so file that can be called by opt and read my IR file name as input argument. And after i commit it , it will output the name of the file.
I had tried several methods before , but i still don't know how to do it....
I hope i can do it like this.
opt -load ../Debug+Asserts/lib/xxxx.so -flag < llvm.ll > /dev/null
when i press ENTER , it will output the name of the file -> "llvm.ll"
Can anyone help me write this simple program , i am going to optimize the llvm IR as my semester project , and now i stuck here ... help me , thanks ~
Can you tell me the code in detail , this doesn't work for me
using namespace llvm;
namespace {
struct Hello : public ModulePass {
static char ID;
Hello() : ModulePass(ID) {}
virtual bool runOnModule(Module &M) {
dbgs() << M.getModuleIdentifier() << "\n";
return false;
}
};
}
char Hello::ID = 0;
static RegisterPass<Hello> X("hello", "Hello World Pass", false, false);
~
Your question could really be simplified to "how can I access the name of the current .ll file from within an LLVM pass". You don't need to "parse LLVM IR" or anything like that - when an LLVM pass is being ran it is already way past the parsing phase.
In any case, I'm not aware of any surefire way to get the filename from an LLVM module, but you can encode that information when you prepare the .ll file. For example, set the module id to be the filename via ; ModuleID = 'llvm.ll', then retrieve it by writing a module pass and invoking getModuleIdentifier to get the string. Then you could just print it out, e.g.
bool runOnModule(Module& M) {
dbgs() << M.getModuleIdentifier() << "\n";
return false;
}
Alternatively, use metadata.

gnokii: API error?

I have issues with the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnokii.h>
#define CONFIG_FILE "config"
struct gn_statemachine *state;
void terminate(void) {
gn_lib_phone_close(state);
gn_lib_phoneprofile_free(&state);
gn_lib_library_free();
}
int main() {
gn_data data;
gn_error error;
gn_sms_folder_list folderlist;
atexit(terminate);
if((error = gn_lib_phoneprofile_load(CONFIG_FILE,&state))
!= GN_ERR_NONE)
{
fprintf(stderr,"%s\n",gn_error_print(error));
exit(1);
}
memset(&folderlist,0,sizeof(gn_sms_folder_list));
gn_data_clear(&data);
data.sms_folder_list = &folderlist;
error = gn_sm_functions(GN_OP_GetSMSFolders, &data, state);
printf("ada %d sms dun\n",folderlist.number);
return 0;
}
I'm compiling it with gcc -o main main.c -lgnokii, but when it's executed it generates errors when looking for config file:
# ./gnokiitest
No phone_config section in the config file.
Either global or given phone section cannot be found.
Segmentation fault
because I included the config file within one folder of main output:
$ cat config
[global]
connection = bluetooth
port = 24:22:AB:AB:C1:F8
model = AT
rfcomm_channel = 2
Whats wrong then?
For starters, the following will cause issues:
if((error = gn_lib_phoneprofile_load(CONFIG_FILE,&state))
state variable is not initialized here. That will cause random pointer being passed and most likely segfault.
Next, the first argument to gn_lib_phoneprofile_load() is not the config file name, but the phone section in the config where the connection details are provided. Given that you pass config as this parameter you'd need:
[phone_config]
connection = bluetooth
port = 24:22:AB:AB:C1:F8
model = AT
rfcomm_channel = 2
but placed in the standard gnokii config file location. To use different location use:
gn_lib_phoneprofile_load_from_file(CONFIG_FILE, NULL, &state);
Second argument is the phone section name. If NULL, then [global] would be used.
Additionally gn_lib_phoneprofile_load() just reads the config file. You need to run gn_lib_phone_open() to initialize the connection.
Finally, there is similar code already written, no need to reinvent the wheel: http://git.savannah.gnu.org/cgit/gnokii/gnokii-extras.git/tree/snippets/sms/sms_status.c