我正在使用gcc-arm-none-eabi 4.9 2014q4为Cortex-M4编写裸机应用程序。当应用程序加载时,对_sbrk
的第一次调用似乎无效。
我已按照以下方式实施_sbrk
:
extern unsigned int _start_of_heap;
extern unsigned int _end_of_heap;
caddr_t heap = (caddr_t)&_start_of_heap;
#include "hardware/uart.h"
// low level bulk memory allocator - used by malloc
caddr_t _sbrk ( int increment ) {
caddr_t prevHeap;
caddr_t nextHeap;
send_str("_sbrk(");
send_dec(increment);
send_str(")\n");
prevHeap = heap;
// Always return data aligned on a 8 byte boundary
nextHeap = (caddr_t)(((unsigned int)(heap + increment) + 7) & ~7);
// get current stack pointer
register caddr_t stackPtr asm ("sp");
send_str("\tstackPtr(");
send_hex((uint32_t)stackPtr);
send_str(")\n");
send_str("\tprevHeap(");
send_hex((uint32_t)prevHeap);
send_str(")\n");
// Check enough space and there is no collision with stack coming the other way
// if stack is above start of heap
if((nextHeap < stackPtr) && (nextHeap >= (caddr_t)&_start_of_heap) && (nextHeap < (caddr_t)&_end_of_heap)) {
heap = nextHeap;
return (caddr_t) prevHeap;
}
send_str("*\n");
return NULL; // error - no more memory
}
链接器定义堆限制如下:
MEMORY
{
SRAM_L (rwx) : ORIGIN = 0x00000000, LENGTH = 32K
SRAM_U (rwx) : ORIGIN = 0x20000000, LENGTH = 32K
}
SECTIONS
{
.vectors 0x00000000 :
{
*o(.vectors_)
} >SRAM_L
.text :
{
. = ALIGN (4);
*(.text);
} >SRAM_L
. = . ;
_datai = . ;
.data :
{
. = ALIGN (4);
_data = . ; *(.data .data.*); _edata = . ;
} >SRAM_U AT >SRAM_L
.data_init :
{
_edatai = .;
} >SRAM_L
.bss :
{
. = ALIGN (4);
_bss = . ; *(.bss) *(COMMON); _ebss = . ;
} >SRAM_U
. = ALIGN (4);
. += 8;
free_memory_start = .;
_end_of_stack = .;
end = .;
_start_of_heap = .;
. = 0x20007000;
_start_of_stack = .;
_end_of_heap = .;
}
程序代码运行快速堆栈和堆测试:
extern unsigned int _start_of_heap;
extern unsigned int _end_of_heap;
extern caddr_t heap;
void foo(uint8_t i)
{
unsigned long blah = 0;
unsigned long * halb;
halb = malloc(sizeof(unsigned long));
iprintf("blah(%08x) halb(%08x) heap(%08x)\n", &blah, halb, heap);
if(i)
foo(i - 1);
free(halb);
}
int main(int argc, char ** argv)
{
init_uart((void*)UART2_IPS_BASE_ADDR, 115200);
iprintf("Heap test (%08x - %08x)\n", &_start_of_heap, &_end_of_heap);
foo(10);
return 0;
}
生成以下输出:
_sbrk(1040965006) <----- Note large size
stackPtr(20006E18)
prevHeap(2000089C)
* <----- '*' indicates out of range
_sbrk(626)
stackPtr(20006E18)
prevHeap(2000089C)
Heap test (2000089c - 20007000)
blah(20006fb8) halb(00000410) heap(20000b10)
blah(20006fa0) halb(00000420) heap(20000b10)
blah(20006f88) halb(00000430) heap(20000b10)
blah(20006f70) halb(00000440) heap(20000b10)
blah(20006f58) halb(00000450) heap(20000b10)
blah(20006f40) halb(00000460) heap(20000b10)
blah(20006f28) halb(00000470) heap(20000b10)
blah(20006f10) halb(00000480) heap(20000b10)
blah(20006ef8) halb(00000490) heap(20000b10)
blah(20006ee0) halb(000004a0) heap(20000b10)
blah(20006ec8) halb(000004b0) heap(20000b10)
第一个分配是1040965006个字节,这似乎不正确,它失败了。在此之后我假设malloc
继续分配626个字节。对malloc
的{{1}}的每次后续调用似乎都会返回超出我的堆栈范围的地址。这第一次调用看起来像是错误,还是应该被忽略?如果是,那么halb
返回的地址是什么?
谢谢, 德万
答案 0 :(得分:0)
似乎某些变量可能未正确初始化。我更新了我的链接器脚本,如下所示:
SECTIONS
{
. = ORIGIN(SRAM_L);
.vectors :
{
KEEP(*o(.vectors_))
} >SRAM_L
.text :
{
. = ALIGN(4);
_start_text = .;
*(.text)
*(.text*)
*(.rodata)
*(.rodata*)
_end_text = .;
} >SRAM_L
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > SRAM_L
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > SRAM_L
__exidx_end = .;
_end_text = .;
. = . ;
_datai = . ;
.data :
{
. = ALIGN (4);
_data = . ;
*(.data)
*(.data*)
. = ALIGN (4);
_edata = . ;
} >SRAM_U AT >SRAM_L
.data_init :
{
_edatai = .;
} >SRAM_L
.bss :
{
. = ALIGN (4);
_bss = . ;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
} >SRAM_U
. = ALIGN (4);
. += 8;
free_memory_start = .;
_end_of_stack = .;
PROVIDE(end = .);
_start_of_heap = .;
. = 0x20007000;
_start_of_stack = .;
_end_of_heap = .;
}
感谢sushihangover博文。
答案 1 :(得分:-1)
我遇到了GNU工具ARM嵌入式arm-none-eabi 4.9 2015q1以及与CodeSourcery的arm-none-eabi 4.5.2配合良好的_sbrk的问题。我以为我会尝试更新的版本。
然后我用4.7 2013q1和4.8 2014q1尝试了它,mallocs也给了sbrk的初始请求的负值。
我必须调整我的_sbrk以忽略负值,以使其与两个版本的编译器一起正常工作。如果我错了,请纠正我,但我知道不应该用负值调用_sbrk,但只有重入版本_sbrk_r(对于操作系统)应该使用否定值。
如果有人有兴趣,这是我的实施
extern char __heap_start__; // defined by the linker script
extern char __heap_end__; // defined by the linker script
unsigned char * HeapSize;
unsigned char * _sbrk ( int incr )
{
unsigned char *prev_heap;
if (HeapSize == 0)
HeapSize = (unsigned char *)&__heap_start__; // initialize the Heap to the start
prev_heap = HeapSize; // store the start of this block of memmory
if(incr > 0)
{ // only allow increments to the heap allocation
// check that we don't run out of memory
// could try using the stack pointer to maximise memmory use
if(((unsigned long)HeapSize + incr) >= (unsigned long)&__heap_end__)
return (unsigned char *) -1; // out of memmory
HeapSize += incr; // increase the heap
}
return prev_heap; // return the start of the next block of memory
}