Make binaries specify their stack size using a new stack_size!{} macro.

Prior to this PR, it was not possible for binaries to specify their own stack size. libtock-rs had a hardcoded stack size of 2KiB.
diff --git a/boards/layout_apollo3.ld b/boards/layout_apollo3.ld
index 95fde33..8713c27 100644
--- a/boards/layout_apollo3.ld
+++ b/boards/layout_apollo3.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x10002000, LENGTH = 0x2000
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_hail.ld b/boards/layout_hail.ld
index f5473ee..179a883 100644
--- a/boards/layout_hail.ld
+++ b/boards/layout_hail.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_hifive1.ld b/boards/layout_hifive1.ld
index 2e08580..20294ce 100644
--- a/boards/layout_hifive1.ld
+++ b/boards/layout_hifive1.ld
@@ -13,12 +13,6 @@
   SRAM (rwx) : ORIGIN = 0x80002400, LENGTH = 0x1C00
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 1K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_imxrt1050.ld b/boards/layout_imxrt1050.ld
index 56ecf11..3e7f904 100644
--- a/boards/layout_imxrt1050.ld
+++ b/boards/layout_imxrt1050.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 112K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_msp432.ld b/boards/layout_msp432.ld
index 2262a15..2c9d2a4 100644
--- a/boards/layout_msp432.ld
+++ b/boards/layout_msp432.ld
@@ -4,12 +4,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 0x2000
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_nrf52.ld b/boards/layout_nrf52.ld
index 40cdb10..942e86b 100644
--- a/boards/layout_nrf52.ld
+++ b/boards/layout_nrf52.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_nrf52840.ld b/boards/layout_nrf52840.ld
index d99efa0..31bf346 100644
--- a/boards/layout_nrf52840.ld
+++ b/boards/layout_nrf52840.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 62K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_nucleo_f429zi.ld b/boards/layout_nucleo_f429zi.ld
index 8261e9c..3e407b4 100644
--- a/boards/layout_nucleo_f429zi.ld
+++ b/boards/layout_nucleo_f429zi.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 112K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_nucleo_f446re.ld b/boards/layout_nucleo_f446re.ld
index 6536b30..83e698b 100644
--- a/boards/layout_nucleo_f446re.ld
+++ b/boards/layout_nucleo_f446re.ld
@@ -6,12 +6,6 @@
   SRAM (rwx) : ORIGIN = 0x20004000, LENGTH = 176K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 8K;
 
 INCLUDE layout_generic.ld
diff --git a/boards/layout_opentitan.ld b/boards/layout_opentitan.ld
index bf15b4d..ada781c 100644
--- a/boards/layout_opentitan.ld
+++ b/boards/layout_opentitan.ld
@@ -13,12 +13,6 @@
   SRAM (rwx) : ORIGIN = 0x10004000, LENGTH = 512K
 }
 
-/*
- * Any change to STACK_SIZE should be accompanied by a corresponding change to
- * `elf2tab`'s `--stack` option
- */
-STACK_SIZE = 2048;
-
 MPU_MIN_ALIGN = 1K;
 
 INCLUDE layout_generic.ld
diff --git a/core/examples/empty_main.rs b/core/examples/empty_main.rs
index 1179b43..a3644b7 100644
--- a/core/examples/empty_main.rs
+++ b/core/examples/empty_main.rs
@@ -11,4 +11,6 @@
 // follows.
 extern crate libtock_core;
 
+libtock_core::stack_size! {0x400}
+
 fn main() {}
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 3bdfe5b..717dc41 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -18,5 +18,6 @@
 pub mod memop;
 pub mod result;
 pub mod shared_memory;
+pub mod stack_size;
 pub mod syscalls;
 pub mod unwind_symbols;
diff --git a/core/src/stack_size.rs b/core/src/stack_size.rs
new file mode 100644
index 0000000..9145393
--- /dev/null
+++ b/core/src/stack_size.rs
@@ -0,0 +1,19 @@
+//! Executables must specify their stack size by using the `stack_size!` macro.
+//! It takes a single argument, the desired stack size in bytes. Example:
+//! ```
+//! stack_size!{0x400}
+//! ```
+
+// stack_size works by putting a symbol equal to the size of the stack in the
+// .stack_buffer section. The linker script uses the .stack_buffer section to
+// size the stack. flash.sh looks for the symbol by name (hence #[no_mangle]) to
+// determine the size of the stack to pass to elf2tab.
+
+#[macro_export]
+macro_rules! stack_size {
+    {$size:expr} => {
+        #[no_mangle]
+        #[link_section = ".stack_buffer"]
+        pub static mut STACK_MEMORY: [u8; $size] = [0; $size];
+    }
+}
diff --git a/examples-features/alloc_error.rs b/examples-features/alloc_error.rs
index 8b20f84..f5bcc5a 100644
--- a/examples-features/alloc_error.rs
+++ b/examples-features/alloc_error.rs
@@ -11,6 +11,8 @@
 use libtock::result::TockResult;
 use libtock::syscalls;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 fn main() -> TockResult<()> {
     let mut vec = Vec::new();
diff --git a/examples-features/ble_scanning.rs b/examples-features/ble_scanning.rs
index c6a6873..afdb8bb 100644
--- a/examples-features/ble_scanning.rs
+++ b/examples-features/ble_scanning.rs
@@ -5,6 +5,8 @@
 use libtock::simple_ble;
 use serde::Deserialize;
 
+libtock_core::stack_size! {0x800}
+
 #[derive(Deserialize)]
 struct LedCommand {
     pub nr: u8,
diff --git a/examples-features/libtock_test.rs b/examples-features/libtock_test.rs
index a938f46..422b489 100644
--- a/examples-features/libtock_test.rs
+++ b/examples-features/libtock_test.rs
@@ -22,6 +22,8 @@
 use libtock::timer::DriverContext;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples-features/panic.rs b/examples-features/panic.rs
index 8af98bf..c4737dc 100644
--- a/examples-features/panic.rs
+++ b/examples-features/panic.rs
@@ -7,6 +7,8 @@
 use libtock::result::TockResult;
 use libtock::syscalls;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     panic!("Bye world!");
diff --git a/examples-features/simple_ble.rs b/examples-features/simple_ble.rs
index 8dde309..b6b6c08 100644
--- a/examples-features/simple_ble.rs
+++ b/examples-features/simple_ble.rs
@@ -7,6 +7,8 @@
 use libtock::timer::Duration;
 use serde::Serialize;
 
+libtock_core::stack_size! {0x800}
+
 #[derive(Serialize)]
 struct LedCommand {
     pub nr: u8,
diff --git a/examples/adc.rs b/examples/adc.rs
index 28b1534..c0a6da7 100644
--- a/examples/adc.rs
+++ b/examples/adc.rs
@@ -4,6 +4,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/adc_buffer.rs b/examples/adc_buffer.rs
index 1337cf4..fe168f3 100644
--- a/examples/adc_buffer.rs
+++ b/examples/adc_buffer.rs
@@ -5,6 +5,8 @@
 use libtock::result::TockResult;
 use libtock::syscalls;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 /// Reads a 128 byte sample into a buffer and prints the first value to the console.
 async fn main() -> TockResult<()> {
diff --git a/examples/blink.rs b/examples/blink.rs
index fd3b1e5..c923c16 100644
--- a/examples/blink.rs
+++ b/examples/blink.rs
@@ -3,6 +3,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x400}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/blink_random.rs b/examples/blink_random.rs
index 93a263d..1e10814 100644
--- a/examples/blink_random.rs
+++ b/examples/blink_random.rs
@@ -4,6 +4,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x400}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/button_leds.rs b/examples/button_leds.rs
index 4a48f2f..ea3898b 100644
--- a/examples/button_leds.rs
+++ b/examples/button_leds.rs
@@ -4,6 +4,8 @@
 use libtock::buttons::ButtonState;
 use libtock::result::TockResult;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/button_read.rs b/examples/button_read.rs
index e888185..38a822b 100644
--- a/examples/button_read.rs
+++ b/examples/button_read.rs
@@ -4,6 +4,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/button_subscribe.rs b/examples/button_subscribe.rs
index 8b2f17e..34b7d8d 100644
--- a/examples/button_subscribe.rs
+++ b/examples/button_subscribe.rs
@@ -6,6 +6,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/ctap.rs b/examples/ctap.rs
index d545d0c..f9fa7bc 100644
--- a/examples/ctap.rs
+++ b/examples/ctap.rs
@@ -6,6 +6,8 @@
 use libtock::syscalls;
 use libtock::{print, println};
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/gpio.rs b/examples/gpio.rs
index 9241e74..4d61d5a 100644
--- a/examples/gpio.rs
+++ b/examples/gpio.rs
@@ -3,6 +3,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 // Example works on P0.03
 #[libtock::main]
 async fn main() -> TockResult<()> {
diff --git a/examples/gpio_read.rs b/examples/gpio_read.rs
index 8fc216b..1bd1388 100644
--- a/examples/gpio_read.rs
+++ b/examples/gpio_read.rs
@@ -5,6 +5,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 // example works on p0.03
 #[libtock::main]
 async fn main() -> TockResult<()> {
diff --git a/examples/hello_world.rs b/examples/hello_world.rs
index 49ada78..2872f25 100644
--- a/examples/hello_world.rs
+++ b/examples/hello_world.rs
@@ -7,6 +7,8 @@
 use libtock::println;
 use libtock::result::TockResult;
 
+libtock_core::stack_size! {0x400}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let drivers = libtock::retrieve_drivers()?;
diff --git a/examples/hmac.rs b/examples/hmac.rs
index fe956bb..75382fa 100644
--- a/examples/hmac.rs
+++ b/examples/hmac.rs
@@ -5,6 +5,8 @@
 use libtock::result::TockResult;
 use libtock::syscalls;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/sensors.rs b/examples/sensors.rs
index 5196cd1..5dce698 100644
--- a/examples/sensors.rs
+++ b/examples/sensors.rs
@@ -5,6 +5,8 @@
 use libtock::sensors::Sensor;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/seven_segment.rs b/examples/seven_segment.rs
index 88b0700..7befeb5 100644
--- a/examples/seven_segment.rs
+++ b/examples/seven_segment.rs
@@ -4,6 +4,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 fn number_to_bits(n: u8) -> [bool; 8] {
     match n {
         1 => [false, false, false, true, false, true, false, false],
diff --git a/examples/temperature.rs b/examples/temperature.rs
index 6298cb4..5e46f90 100644
--- a/examples/temperature.rs
+++ b/examples/temperature.rs
@@ -4,6 +4,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/examples/timer.rs b/examples/timer.rs
index 2277e6c..d8f5b1d 100644
--- a/examples/timer.rs
+++ b/examples/timer.rs
@@ -8,6 +8,8 @@
 use libtock::timer::DriverContext;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 const DELAY_MS: usize = 500;
 
 #[libtock::main]
diff --git a/examples/timer_parallel.rs b/examples/timer_parallel.rs
index 66ddac2..f2fc786 100644
--- a/examples/timer_parallel.rs
+++ b/examples/timer_parallel.rs
@@ -6,6 +6,8 @@
 use libtock::timer::Duration;
 use libtock::timer::ParallelSleepDriver;
 
+libtock_core::stack_size! {0x800}
+
 async fn blink(
     timer_driver: &ParallelSleepDriver<'_>,
     duration: Duration<usize>,
diff --git a/examples/timer_subscribe.rs b/examples/timer_subscribe.rs
index 5a7ad4b..f021345 100644
--- a/examples/timer_subscribe.rs
+++ b/examples/timer_subscribe.rs
@@ -5,6 +5,8 @@
 use libtock::result::TockResult;
 use libtock::timer::Duration;
 
+libtock_core::stack_size! {0x800}
+
 #[libtock::main]
 async fn main() -> TockResult<()> {
     let mut drivers = libtock::retrieve_drivers()?;
diff --git a/layout_generic.ld b/layout_generic.ld
index 3c5065c..f2deebb 100644
--- a/layout_generic.ld
+++ b/layout_generic.ld
@@ -14,7 +14,6 @@
  *         FLASH (rx) : ORIGIN = 0x10030, LENGTH = 0x0FFD0
  *         SRAM (RWX) : ORIGIN = 0x20000, LENGTH = 0x10000
  *     }
- *     STACK_SIZE = 2048;
  *     MPU_MIN_ALIGN = 8K;
  *     INCLUDE ../libtock-rs/layout.ld
  */
@@ -64,7 +63,7 @@
          * .rel.data section */
         LONG(LOADADDR(.endflash) - _beginning);
         /* The size of the stack requested by this application */
-        LONG(STACK_SIZE);
+        LONG(_stack_top_aligned - _sstack);
         /* Pad the header out to a multiple of 32 bytes so there is not a gap
          * between the header and subsequent .data section. It's unclear why,
          * but LLD is aligning sections to a multiple of 32 bytes. */
@@ -96,12 +95,11 @@
          * TBF header if needed.
          */
         _sram_origin = .;
-
-        . = . + STACK_SIZE;
-
-	_stack_top_unaligned = .;
+        _sstack = .;
+        KEEP(*(.stack_buffer))
+        _stack_top_unaligned = .;
         . = ALIGN(8);
-	_stack_top_aligned = .;
+        _stack_top_aligned = .;
     } > SRAM
 
     /* Data section, static initialized variables
diff --git a/tock b/tock
index c5b7a4f..9f40864 160000
--- a/tock
+++ b/tock
@@ -1 +1 @@
-Subproject commit c5b7a4f2c89a8c067f0f5786788f4037b32329fd
+Subproject commit 9f408649ce25f46f0dd49dae7f1a0a9849cae2af
diff --git a/tools/flash.sh b/tools/flash.sh
index 2ac2867..48bf486 100755
--- a/tools/flash.sh
+++ b/tools/flash.sh
@@ -68,7 +68,9 @@
 mkdir -p "${libtock_target_path}"
 cp "$1" "${elf_file_name}"
 
-elf2tab -n "${artifact}" -o "${tab_file_name}" "${elf_file_name}" --stack 2048 --app-heap $APP_HEAP_SIZE --kernel-heap $KERNEL_HEAP_SIZE --protected-region-size=64
+STACK_SIZE=$(nm --print-size --size-sort --radix=d "${elf_file_name}" | grep STACK_MEMORY | cut -d " " -f 2)
+
+elf2tab -n "${artifact}" -o "${tab_file_name}" "${elf_file_name}" --stack ${STACK_SIZE} --app-heap $APP_HEAP_SIZE --kernel-heap $KERNEL_HEAP_SIZE --protected-region-size=64
 
 if [ $tockload == "n" ]; then
 	echo "Skipping flashing for platform \"${PLATFORM}\""