Вух!!!, вроде все понял. Много вопросов отпало, когда собралась общая картинка. Просто начал я не с того боку и все из за того базового линк. Нужно было начинать с его ковыряния, а не кода Си.
Вот линк:
Код
_eram = 0x20000000 + 0x00020000;
SECTIONS
{
.text :
{
KEEP(*(.isr_vector))
ля-ля-ля
} > rom
.data :
{
ля-ля-ля
} > ram
.bss :
{
ля-ля-ля
} > ram
//Начало моей части где я настраиваю stack & heap
//Стек
_stack_size = 0x200;/*Размер - нужно только мне и для вычисления след. параметров*/
_StackTop = . + _stack_size;/*Вершина стека начало лок. данных + его размер*/
_StackLimit = .;/*Для наглядности - начало лок. данных*/
.stack :/*Это собственно секция стека*/
{
. = . + _stack_size;/*установка размера этой секции*/
} > ram
PROVIDE(_stack = _StackTop);/*значение _stack устанавливаем в _StackTop*/
/*_stack потом помещаем в начало вектора*/
//Куча
_heap_size = 0x100;/*размер кучи*/
_heap_begin = _eram - _heap_size;/*адрес начала кучи*/
_heap_limit = _heap_begin + _heap_size;/*лимит кучи для проверки*/
.heap (_heap_begin):/*секцию под кучу располагаем адреса _heap_begin*/
{
. = . + _heap_size;/*установка размера этой секции*/
} > ram
}
В startup файле устанавливаем только координаты начала стека, больше в нем нет ничего про стек и кучу!
Код
extern unsigned long _stack;//значение задано в линк. файле
__attribute__ ((used,section(".isr_vector")))
void (* const g_pfnVectors[])(void) =
{
/*----------Core Exceptions------------------------------------------------ */
(void *)&_stack, /*!< The initial stack pointer */
Reset_Handler, /*!< Reset Handler */
NMI_Handler, /*!< NMI Handler */
Для проверки переполнения кучи в файле syscalls.c
Код
extern int _heap_begin;
extern int _heap_limit;
caddr_t _sbrk ( int incr )
{
static unsigned char *heap = NULL;
unsigned char *prev_heap;
unsigned char *new_heap;
if (heap == NULL) {
heap = (unsigned char *)&_heap_begin;
}
prev_heap = heap;
new_heap = heap + incr;
if(new_heap > (unsigned char *)&_heap_limit) {
return 0;
}
heap = new_heap;
return (caddr_t) prev_heap;
}
По map файлу (просто для наглядности):
В итоге мы получили стек размером 0x200 который идет с адреса 0x20000a88 к 0x20000888.
Куча которая начинается с адреса 0x2001ff00 и идет до конца памяти с ограничением переполнения.
Код
COMMON 0x20000884
0x20000884 errno
0x20000888 . = ALIGN (0x4)
0x20000888 __bss_end__ = .
0x20000888 _ebss = __bss_end__
0x00000200 _stack_size = 0x200
0x20000a88 _StackTop = (. + _stack_size)
0x20000888 _StackLimit = .
.stack 0x20000888 0x200 load address 0x080014b4
0x20000a88 . = (. + _stack_size)
*fill* 0x20000888 0x200
0x20000a88 PROVIDE (_stack, _StackTop)
0x00000100 _heap_size = 0x100
0x2001ff00 _heap_begin = (_eram - _heap_size)
0x20020000 _heap_limit = (_heap_begin + _heap_size)
.heap 0x2001ff00 0x100 load address 0x08020b2c
0x2001ff00 _end = .
0x20020000 . = (. + _heap_size)
*fill* 0x2001ff00 0x100
Остался один вопрос:
Эти самые секции объявляются для того, чтоб в эти места памяти никто ничего левого не подсунул?
Типа ка в линке MCC18 под ПИК когда нужна секция, в которую линкер ничего не суют?
Цитата
DATABANK NAME=bgpr2 START=0x500 END=0x6FF PROTECTED
Или то-же только для наглядности?
И здесь и так никто ничего не подсунет. Все глобальные переменные по порядочку по секциям data и bss (в PIC они были разбросаны по банкам памяти). Стек от А до В, куча от С до D. Все локальные переменные в стеке.
Тогда может вообще лишнее объявлять эти секции?
Сделать себе
Код
_stack_size = 0x200;
_StackTop = . + _stack_size;
PROVIDE(_stack = _StackTop);
//Куча
_heap_size = 0x100;
_heap_begin = _eram - _heap_size;
_heap_limit = _heap_begin + _heap_size;
И Все?!