Why does using a structure in C program cause Link error - linker

I am writing a C program for a 8051 architecture chip and the SDCC compiler.
I have a structure called FilterStructure;
my code looks like this...
#define NAME_SIZE 8
typedef struct {
char Name[NAME_SIZE];
} FilterStructure;
void ReadFilterName(U8 WheelID, U8 Filter, FilterStructure* NameStructure);
int main (void)
{
FilterStructure testStruct;
ReadFilterName('A', 3, &testFilter);
...
...
return 0;
}
void ReadFilterName(U8 WheelID, U8 Filter, FilterStructure* NameStructure)
{
int StartOfName = 0;
int i = 0;
///... do some stuff...
for(i = 0; i < 8; i++)
{
NameStructure->Name[i] = FLASH_ByteRead(StartOfName + i);
}
return;
}
For some reason I get a link error "?ASlink-Error-Could not get 29 consecutive bytes in internal RAM for area DSEG"
If I comment out the line that says FilterStructure testStruct; the error goes away.
What does this error mean? Do I need to discard the structure when I am done with it?

The message means that your local variable testStruct couldn't be allocated in RAM (or DSEG that should be DATA SEGMENT of your binary), since your memory manager couldn't find 29 consecutive bytes to allocate it.
This is strange since your struct should be 8 bytes long.. but btw it's nothing to do with discarding the structure, this seems a memory management problem.. I don't know 8051 specs so well but it should be quite limited right?
EDIT: looking at 8051 specs it seems it just has 128 bytes of RAM. This can cause the problem because the variable, declared as a local, is allocated in internal RAM while you should try to allocate it on an external RAM chip if it's possible (using the address/data bus of the chip), but I'm not sure since this kind of microcontroller shouldn't be used to do these things.

you've run out of memory....by the looks of it.
try moving it out as a global variable, see if that makes it better.

Just a guess: 8051 has only 128 or 256 bytes of "internal RAM". Not so much... It can use part of it as stack and part for registers. Maybe your "large" (8 bytes!!!) structure on the stack forces the compiler to reserve too much stack space inside the internal memory. I suggest to have a look into the linker map file, maybe you can "rearrange" the memory partition. The massage says "consecutive bytes", so perhaps there is still enough space availabe, but it's fragmented.
Bye

Related

Auto-Allocate to a specific RAM Area in GCC/C

Sorry for my english, its a bit hard for me to explain what exactly i would need.
I'm making some extra code into existing binarys using the GCC compiler.
In this case, its PowerPC, but it should not really matter.
I know, where in the existing binary i have free ram available (i dumped the full RAM to make sure) but i need to define each RAM address manually, currently i am doing it like this:
// #ram.h
//8bit ram
uint8_t* xx1 = (uint8_t*) 0x807F00;
uint8_t* xx2 = (uint8_t*) 0x807F01;
//...and so on
// 16bit ram
uint16_t* xxx1 = (uint16_t*) 0x807F40;
uint16_t* xxx2 = (uint16_t*) 0x807F42;
//...and so on
// 32bit ram
uint32_t* xxxx1 = (uint32_t*) 0x807FA0;
uint32_t* xxxx2 = (uint32_t*) 0x807FA4;
//...and so on
And im accessing my variables like this:
void __attribute__ ((noinline)) silly_demo_function() {
#include "ram.h"
if (*xxx2>*xx1) {
*xxx3 = *xxx3 + *xx1;
}
return;
}
But this gets really boring, if i want to patch my code into another existing binary, where the location of available/free/unused ram can be fully different, or if im replacing/removing some value in the middle. I am using 8, 16 and 32bit variables.
Is there a way, i can define an area like 0x807F00 to 0x00808FFF, and allocate my variables on the fly, and the compiler will allocate it inside my specific location?
I suspect that the big problem here is that those addresses are memory mapped IO (devices) and not RAM; and should not be treated as RAM.
Further, I'd say that you probably should be hiding the "devices that aren't RAM" behind an abstract layer, a little bit like a device driver; partly so that you can make sure that the compiler complies with any constraints caused by it being IO and not RAM (e.g. treated as volatile, possibly honoring any access size restrictions, possibly taking care of any cache coherency management); partly so that you/programmers know what is normal/fast/cached RAM and what isn't; partly so that you can replace the "device" with fake code for testing; and partly so that it's all kept in a single well defined area.
For example; you might have a header file called "src/devices.h" that contains:
#define xx1_address 0x807F00
..and the wrapper code might be a file called "src/devices/xx1.c" that contains something like:
#include "src/devices.h"
static volatile uint8_t * xx1 = (uint8_t*) xx1_address;
uint8_t get_xx1(void) {
return *xx1;
}
void set_xx1(uint8_t x) {
*xx1 = x;
}
However; depending on what these devices actually are, you might need/want some higher level code. For example, maybe xx1 is a temperature sensor and it doesn't make any sense to try to set it, and you want it to scale that raw value so it's "degrees celsius", and the highest bit of the raw value is used to indicate an error condition (and the actual temperature is only 7 bits), so the wrapper might be more like:
#include "src/devices.h"
#define xx1_offset -12.34
#define xx1_scale 1.234
static volatile uint8_t * xx1 = (uint8_t*) xx1_address;
float get_xx1_temperature(void) {
uint8_t raw_temp = *xx1;
if(raw_temp * 0x80 != 0) {
/* Error flag set */
return NAN;
}
/* No error */
return (raw_temp + xx1_offset) * xx1_scale;
}
In the meanwhile, i figured it out.
Its just as easy as defining .data, .bsss and .sbss in the linker directives.
6 Lines of code and its working like a charm.

STM32H7, weird behavior of HAL_FLASH_Program function

For the context, I'm writting a bootloader for my STM32H743XI cause I want to erase and upload code through USB without using pin.
So my bootloader start at 0x08000000, it's size is 21kB (17% of the first sector of 128kB), and I want to read/write data at the end of the sector which will be shared with my App. When I say end of the sector it's the last 10kB of the sector which means I start to R/W at 0x0801D800.
The structure that I want to R/W is 8x32bits cause if I understand well this is the size of a WORD on STM32H74x/5X devices.
This is my struct:
typedef struct
{
int32_t BootLoaderMode;
int32_t StartingPartition;
int32_t AppStartingError;
int32_t temp4;
int32_t temp5;
int32_t temp6;
int32_t temp7;
int32_t temp8;
} ExchangeWord_1;
I've got a pointer to an allocated struct:
ExchangeWord_1* m_ExchangeWord_1 = (ExchangeWord_1*)malloc(sizeof(ExchangeWord_1));
Before writing i unlock memory with:
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();
The write operation looks like (id=0 and the second parameter is my allocated struct):
void writeExchangeWord(uint16_t id, ExchangeWord_1* exchangeWord )
{
//unlock function
uint32_t flash_address = (0x0801D800+id*32);
uint32_t data_address = (uint32_t)exchangeWord;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, flash_address, data_address);
//lock function
}
Then I lock the memory :
HAL_FLASH_Lock();
HAL_FLASH_OB_Lock();
So the first call of this works well and the debugger confirms it when I look at the memory:
[Flash memory on first call][1]:
https://i.stack.imgur.com/cH9fI.png
But on on the next call the memory is filled with 0, more weird at the third call it's mulpiple words starting at 0x0801D800 who are filled with 0.
The adress of my struct is well aligned (m_ExchangeWord_1 = 0x20001D60).
What I am missing? Do I need to clear some flags before/after writting?
Ok it's seems that it is impossible to write two time in a row at the same adress, i've read somewhere that we are only allow to switch a bit from 1 to 0 if we want to write multiple time without erasing. I moved my "shared area" in a specific sector that I have to erase each time I want to write on it.
My problem is solved.

Initialize array starting from specific address in memory - C programming

Do you have idea how to initialize array of structs starting from specific address in memory (not virtual, physical DDR memory). I am working on implementation of TxRx on SoC (ARM-FPGA). Basically ARM (PS) and FPGA (PL) communicate to each other by using shared RAM memory. Currently I am working on transmitter side, so I need to constantly load packets that I get from MAC layer to memory, then my Tx reads data and sends it in air. To achieve this I want to implement circular FIFO buffer on (ARM) side, in way that I can store up to 6 packets into buffer and send them one by one, in same time loading other packets on places of already sent packages. Because I need to use specific memory addresses I am interested is it possible to initialize array of structure that will be stored on specific addresses in memory. For example I want that my array starts at adress 0x400000 and ends at address 0x400000 + MaximumNumberOfPackets x SizeOfPackets I know how to do it for one instantiate of structure for example like this:
buffer_t *tmp = (struct buffer_t *)234881024;
But how to do it for array of structures?
A pointer to a single struct (or int, float, or anything else) is inherently a pointer to an array of them. The pointer type provides the sizeof() value for an array entry, and thus allows pointer arithmetic to work.
Thus, given a struct buffer you can simply do
static struct buffer * const myFIFO = (struct buffer *) 0x40000
and then simply access myFIFO as an array
for (size_t i = 0; i < maxPackets; ++i)
{
buffer[i].someField = initialValue1;
buffer[i].someOtherField = 42;
}
This works just the way you expect.
What you can't do (using pure standard C) is declare an array at a particular address like this:
struct buffer myFIFO[23] # 0x400000;
However, your compiler may have extensions to allow it. Many embedded compilers do (after all, that's often how they declare memory-mapped device registers), but it will be different for every compiler vendor, and possibly for every chip because it is a vendor extension.
GCC does allow it for AVR processors via an attribute, for example
volatile int porta __attribute__((address (0x600)));
But it doesn't seem to support it for an ARM.
Generally #kdopen is right but for arm you should create an entry in MEMORY section linker script that shows to linker where is your memory:
MEMORY
{
...
ExternalDDR (w) : ORIGIN = 0x400000, LENGTH = 4M
}
And than, when you are declaring variable just use the
__attribute__((section("ExternalDDR")))
I found the way how to do it. So could I do it like this. I set this into linker script:
MEMORY {
ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x00100000, LENGTH = 0x1FF00000
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00030000
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x0000FE00
DAC_DMA (w) : ORIGIN = 0xE000000, LENGTH = 64K
}
.dacdma : {
__dacdma_start = .;
*(.data)
__dacdma_end = .;
} > DAC_DMA
And then I set this into code
static buffer_t __attribute__((section("DAC_DMA"))) buf_pool[6];

libopcodes: get the size of a instruction

I have to find out the size of a instruction which I have in memory (actually, I have a small code segment in memory and want to get the size of the first instruction).
It took me some time to find libopcodes and libbfd. I red the headers and tried to come up with a simple solution but it seems like I missunderstood something since the program always crashes:
int main(int argc, char **argv) {
disassemble_info *dis = malloc(sizeof(*dis));
assert(dis != NULL);
dis->arch = bfd_arch_i386;
dis->read_memory_func = buffer_read_memory;
dis->buffer_length = 64;
dis->buffer = malloc(dis->buffer_length);
memset(dis->buffer, 0x90, dis->buffer_length);
disassemble_init_for_target(dis);
int instr_size = print_insn_i386(0, dis);
printf("instruction size is %d\n", instr_size);
return 0;
}
The expected result would be an instruction size of 1 (nop).
EDIT:
sorry guys, I'm a stupid person.
memset(dis, 0, sizeof(*dis));
There is some code in the Linux kernel you can steal. It should work well if copied into a user mode program.
Take a look at arch/x86/lib and arch/x86/tools
There's an opcode map file there, and an awk script that reads it to produce a table in a file named innat.c. There are some other files there that use the table to implement a decoder.
It is sufficient to determine instruction sizes.
This assumes you are ok with GPL, of course.
It looks like the disassemble_info data structure requires more initialization than you have provided. From examples I have been studying, the correct way to initialize is to call init_disassemble_info().
See if that helps. Failing that, compile your program with debug info ('-g') and run gdb to diagnose where the crash occurs.

Heap corruption while using OpenCV datastructure

I am using OpenCV 2.1 with codeblocks (gcc under mingw). Within my code I am trying (for some sane reason) to access the imagedata within IplImage datastructure directly. Kindly refer the code snippet for more details:
int main(void)
{
IplImage* test_image = cvLoadImage("test_image.bmp",CV_LOAD_IMAGE_GRAYSCALE);
int mysize = test_image->height * test_image->widthStep;
char* imagedata_ptr = NULL;
int i = 0;
imagedata_ptr = test_image->imageData;
char* temp_buff = (char *)malloc(sizeof(mysize));
memcpy(temp_buff,imagedata_ptr,mysize);
free(temp_buff);
}
When I run this code it crashes. On running it in the debug mode it generates a SIGTRAP is due to heap corruption. At first I suspected that this might be a compiler related issue and hence tried running the same code in Visual Studio. But it still crashes. Thats the reason I feel it could be an OpenCV related issue.
NOTE: There are no other instances of program open, this is the only code that I am running, no threading etc is being done here.
Awaiting your comments on the same.
Regards,
Saurabh Gandhi
You're not allocating enough memory, this:
char* temp_buff = (char *)malloc(sizeof(mysize))
only allocates sizeof(int) bytes (probably 4) and that's probably a lot less than you need. Then the memcpy right after that will copy test_image->height * test_image->widthStep bytes of data into somewhere that only has space for sizeof(int) bytes and you have now scribbled all over your memory and corrupted your heap.
I'd guess that you really want to say this:
char *temp_buff = malloc(mysize);
And don't cast the return value from malloc, you don't need it and it can hide problems.

Resources