На додаток до інших відповідей, я хотів би додати, що під час збирання оперативної пам’яті між стеком та купою простору вам також потрібно враховувати простір для статичних непостійних даних (наприклад, файлові глобали, статистика функцій та загальна програма глобалістів з точки зору С та, ймовірно, інших для С ++).
Як працює розподіл стека / купи
Варто зазначити, що файл збірки запуску - це один із способів визначення регіону; ланцюжок інструментів (як середовище збирання, так і середовище виконання) в основному дбають про символи, що визначають початок простору стека (використовується для зберігання початкового вказівника стека у векторній таблиці) та початок і кінець простору купи (використовується динамічним розподільник пам'яті, як правило, надається вашим libc)
У прикладі ОП визначено лише 2 символи, розмір стека в 1кіБ та розмір купи в 0В. Ці значення звикають в іншому місці, щоб фактично створити простір стека та купи
У прикладі @Gilles розміри визначаються та використовуються у складальному файлі для встановлення місця стеку, починаючи звідки і триваючи розмір, ідентифікований символом Stack_Mem та встановлює мітку __initial_sp в кінці. Так само і для купи, де пробілом є символ Heap_Mem (розміром 0,5кіБ), але з мітками на початку та в кінці (__heap_base та __heap_limit).
Вони обробляються лінкером, який не виділяє нічого в просторі стека та купі, оскільки ця пам'ять зайнята (символами Stack_Mem та Heap_Mem), але вона може розмістити ці пам’яті та всі глобальні місця, де це потрібно. Мітки в кінцевому підсумку є символами без довжини за вказаними адресами. __Initial_sp використовується безпосередньо для векторної таблиці під час посилання, а __heap_base та __heap_limit за вашим кодом виконання. Фактичні адреси символів присвоює лінкер залежно від місця їх розміщення.
Як я вже згадував вище, ці символи насправді не повинні надходити з файлу startup.s. Вони можуть виходити з конфігурації вашого лінкера (файл Scatter Load у Keil, linkerscript у GNU), а також у тих, у кого ви можете мати більш тонкий контроль над розміщенням. Наприклад, ви можете змусити стек бути на початку або в кінці оперативної пам’яті, або тримати ваш глобус подалі від купи, або чого завгодно. Ви навіть можете вказати, що HEAP або STACK просто займають будь-яку оперативну пам'ять, що залишилася після розміщення глобальних точок. Зауважте, що вам потрібно бути обережними, якщо додавати більше статичних змінних, що зменшиться у вашій іншій пам'яті.
Однак, кожен ланцюжок інструментів відрізняється, і те, як записати файл конфігурації та які символи використовуватиме ваш динамічний розподільник пам'яті, має виходити з документації вашого конкретного середовища.
Розміщення стека
Щодо того, як визначити розмір стека, багато ланцюжків інструментів можуть дати вам максимальну глибину стека, проаналізувавши дерева функцій викликів вашої програми, ЯКЩО ви не використовуєте рекурсії чи покажчики функцій. Якщо ви користуєтесь ними, оцінюючи розмір стека та попередньо заповнюючи його кардинальними значеннями (можливо, за допомогою функції введення перед головним), а потім перевіряйте, чи не запустилася програма на деякий час там, де була максимальна глибина (де де знаходяться кардинальні значення) кінець). Якщо ви повністю застосували програму до її меж, ви досить точно знаєте, чи можете ви зменшити стек або, якщо ваша програма виходить з ладу або не залишилося кардинальних значень, вам потрібно збільшити стек і спробувати ще раз.
Купівля розмірів
Визначення розміру купи трохи більше залежить від програми. Якщо ви робите динамічний розподіл лише під час запуску, ви можете просто додати простір, необхідний у вашому стартовому коді (плюс деякі накладні витрати для управління пам'яттю). Якщо у вас є доступ до джерела диспетчера пам’яті, ви можете точно знати, що таке накладні витрати, і, можливо, навіть написати код, щоб пройти пам’ять, щоб дати вам інформацію про використання. Для додатків, які потребують динамічної пам’яті виконання (наприклад, виділення буферів для вхідних кадрів Ethernet), найкраще, що я можу запропонувати, - це ретельно відточити розмір стека і надати Heap все, що залишилося після стека та статики.
Заключна примітка (RTOS)
Питання OP було позначене як голий метал, але я хочу додати примітку для RTOSes. Часто (завжди?) Кожному завданню / процесу / потоці (я просто напишу тут завдання для простоти) призначається розмір стека, коли завдання створюється, окрім стеків завдань, ймовірно, буде невелика ОС стек (використовується для переривань тощо)
Структури обліку завдань та стеки мають бути розподілені звідкись, і це часто буде залежати від загального простору вашої програми. У цих випадках ваш початковий розмір стека часто не має значення, оскільки ОС буде використовувати його лише під час ініціалізації. Я бачив, наприклад, вказуючи, що ВСЕ залишився простір під час посилання буде виділено HEAP і розмістити початковий покажчик стека в кінці купи, щоб перерости в купу, знаючи, що ОС виділить, починаючи з початку купи і виділить стек ОС безпосередньо перед відмовою від стеку початковий_sp. Потім весь простір використовується для розподілу стеків завдань та іншої динамічно розподіленої пам'яті.