github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/examples/ram-func/main.go (about) 1 package main 2 3 // This example demonstrates how to use go:section to place code into RAM for 4 // execution. The code is present in flash in the `.data` region and copied 5 // into the correct place in RAM early in startup sequence (at the same time 6 // as non-zero global variables are initialized). 7 // 8 // This example should work on any ARM Cortex MCU. 9 // 10 // For Go code use the pragma "//go:section", for cgo use the "section" and 11 // "noinline" attributes. The `.ramfuncs` section is explicitly placed into 12 // the `.data` region by the linker script. 13 // 14 // Running the example should print out the program counter from the functions 15 // below. The program counters should be in different memory regions. 16 // 17 // On RP2040, for example, the output is something like this: 18 // 19 // Go in RAM: 0x20000DB4 20 // Go in flash: 0x10007610 21 // cgo in RAM: 0x20000DB8 22 // cgo in flash: 0x10002C26 23 // 24 // This can be confirmed using `objdump -t xxx.elf | grep main | sort`: 25 // 26 // 00000000 l df *ABS* 00000000 main 27 // 1000760d l F .text 00000004 main.in_flash 28 // 10007611 l F .text 0000000c __Thumbv6MABSLongThunk_main.in_ram 29 // 1000761d l F .text 0000000c __Thumbv6MABSLongThunk__Cgo_static_eea7585d7291176ad3bb_main_c_in_ram 30 // 1000bdb5 l O .text 00000013 main$string 31 // 1000bdc8 l O .text 00000013 main$string.1 32 // 1000bddb l O .text 00000013 main$string.2 33 // 1000bdee l O .text 00000013 main$string.3 34 // 20000db1 l F .data 00000004 main.in_ram 35 // 20000db5 l F .data 00000004 _Cgo_static_eea7585d7291176ad3bb_main_c_in_ram 36 // 37 38 import ( 39 "device" 40 "fmt" 41 "time" 42 _ "unsafe" // unsafe is required for "//go:section" 43 ) 44 45 /* 46 #define ram_func __attribute__((section(".ramfuncs"),noinline)) 47 48 static ram_func void* main_c_in_ram() { 49 void* p = 0; 50 51 asm( 52 "MOV %0, PC" 53 : "=r"(p) 54 ); 55 56 return p; 57 } 58 59 static void* main_c_in_flash() { 60 void* p = 0; 61 62 asm( 63 "MOV %0, PC" 64 : "=r"(p) 65 ); 66 67 return p; 68 } 69 */ 70 import "C" 71 72 func main() { 73 time.Sleep(2 * time.Second) 74 75 fmt.Printf("Go in RAM: 0x%X\n", in_ram()) 76 fmt.Printf("Go in flash: 0x%X\n", in_flash()) 77 fmt.Printf("cgo in RAM: 0x%X\n", C.main_c_in_ram()) 78 fmt.Printf("cgo in flash: 0x%X\n", C.main_c_in_flash()) 79 } 80 81 //go:section .ramfuncs 82 func in_ram() uintptr { 83 return device.AsmFull("MOV {}, PC", nil) 84 } 85 86 // 'go:noinline' used here to prevent function being 'inlined' into main() 87 // so it appears in objdump output. In normal use, go:inline is not 88 // required for functions running from flash (flash is the default). 89 // 90 //go:noinline 91 func in_flash() uintptr { 92 return device.AsmFull("MOV {}, PC", nil) 93 }