arm: enable functions in RAM for go & cgo
Этот коммит содержится в:
родитель
08cf2b25c5
коммит
faa449a9e1
4 изменённых файлов: 103 добавлений и 4 удалений
|
@ -279,8 +279,12 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||||
info.linkName = parts[2]
|
info.linkName = parts[2]
|
||||||
}
|
}
|
||||||
case "//go:section":
|
case "//go:section":
|
||||||
|
// Only enable go:section when the package imports "unsafe".
|
||||||
|
// go:section also implies go:noinline since inlining could
|
||||||
|
// move the code to a different section than that requested.
|
||||||
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
|
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
info.section = parts[1]
|
info.section = parts[1]
|
||||||
|
info.inline = inlineNone
|
||||||
}
|
}
|
||||||
case "//go:nobounds":
|
case "//go:nobounds":
|
||||||
// Skip bounds checking in this function. Useful for some
|
// Skip bounds checking in this function. Useful for some
|
||||||
|
|
8
compiler/testdata/pragma.ll
предоставленный
8
compiler/testdata/pragma.ll
предоставленный
|
@ -47,13 +47,13 @@ entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: noinline nounwind
|
||||||
define hidden void @main.functionInSection(ptr %context) unnamed_addr #1 section ".special_function_section" {
|
define hidden void @main.functionInSection(ptr %context) unnamed_addr #4 section ".special_function_section" {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: noinline nounwind
|
||||||
define void @exportedFunctionInSection() #5 section ".special_function_section" {
|
define void @exportedFunctionInSection() #5 section ".special_function_section" {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
|
@ -66,4 +66,4 @@ attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,
|
||||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
||||||
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
||||||
|
|
93
src/examples/ram-func/main.go
Обычный файл
93
src/examples/ram-func/main.go
Обычный файл
|
@ -0,0 +1,93 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
// This example demonstrates how to use go:section to place code into RAM for
|
||||||
|
// execution. The code is present in flash in the `.data` region and copied
|
||||||
|
// into the correct place in RAM early in startup sequence (at the same time
|
||||||
|
// as non-zero global variables are initialized).
|
||||||
|
//
|
||||||
|
// This example should work on any ARM Cortex MCU.
|
||||||
|
//
|
||||||
|
// For Go code use the pragma "//go:section", for cgo use the "section" and
|
||||||
|
// "noinline" attributes. The `.ramfuncs` section is explicitly placed into
|
||||||
|
// the `.data` region by the linker script.
|
||||||
|
//
|
||||||
|
// Running the example should print out the program counter from the functions
|
||||||
|
// below. The program counters should be in different memory regions.
|
||||||
|
//
|
||||||
|
// On RP2040, for example, the output is something like this:
|
||||||
|
//
|
||||||
|
// Go in RAM: 0x20000DB4
|
||||||
|
// Go in flash: 0x10007610
|
||||||
|
// cgo in RAM: 0x20000DB8
|
||||||
|
// cgo in flash: 0x10002C26
|
||||||
|
//
|
||||||
|
// This can be confirmed using `objdump -t xxx.elf | grep main | sort`:
|
||||||
|
//
|
||||||
|
// 00000000 l df *ABS* 00000000 main
|
||||||
|
// 1000760d l F .text 00000004 main.in_flash
|
||||||
|
// 10007611 l F .text 0000000c __Thumbv6MABSLongThunk_main.in_ram
|
||||||
|
// 1000761d l F .text 0000000c __Thumbv6MABSLongThunk__Cgo_static_eea7585d7291176ad3bb_main_c_in_ram
|
||||||
|
// 1000bdb5 l O .text 00000013 main$string
|
||||||
|
// 1000bdc8 l O .text 00000013 main$string.1
|
||||||
|
// 1000bddb l O .text 00000013 main$string.2
|
||||||
|
// 1000bdee l O .text 00000013 main$string.3
|
||||||
|
// 20000db1 l F .data 00000004 main.in_ram
|
||||||
|
// 20000db5 l F .data 00000004 _Cgo_static_eea7585d7291176ad3bb_main_c_in_ram
|
||||||
|
//
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
_ "unsafe" // unsafe is required for "//go:section"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define ram_func __attribute__((section(".ramfuncs"),noinline))
|
||||||
|
|
||||||
|
static ram_func void* main_c_in_ram() {
|
||||||
|
void* p = 0;
|
||||||
|
|
||||||
|
asm(
|
||||||
|
"MOV %0, PC"
|
||||||
|
: "=r"(p)
|
||||||
|
);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* main_c_in_flash() {
|
||||||
|
void* p = 0;
|
||||||
|
|
||||||
|
asm(
|
||||||
|
"MOV %0, PC"
|
||||||
|
: "=r"(p)
|
||||||
|
);
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
fmt.Printf("Go in RAM: 0x%X\n", in_ram())
|
||||||
|
fmt.Printf("Go in flash: 0x%X\n", in_flash())
|
||||||
|
fmt.Printf("cgo in RAM: 0x%X\n", C.main_c_in_ram())
|
||||||
|
fmt.Printf("cgo in flash: 0x%X\n", C.main_c_in_flash())
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:section .ramfuncs
|
||||||
|
func in_ram() uintptr {
|
||||||
|
return device.AsmFull("MOV {}, PC", nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// go:noinline used here to prevent function being 'inlined' into main()
|
||||||
|
// so it appears in objdump output. In normal use, go:inline is not
|
||||||
|
// required for functions running from flash (flash is the default).
|
||||||
|
//
|
||||||
|
//go:noinline
|
||||||
|
func in_flash() uintptr {
|
||||||
|
return device.AsmFull("MOV {}, PC", nil)
|
||||||
|
}
|
|
@ -42,6 +42,8 @@ SECTIONS
|
||||||
*(.data)
|
*(.data)
|
||||||
*(.data.*)
|
*(.data.*)
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
|
*(.ramfuncs*) /* Functions that must execute from RAM */
|
||||||
|
. = ALIGN(4);
|
||||||
_edata = .; /* used by startup code */
|
_edata = .; /* used by startup code */
|
||||||
} >RAM AT>FLASH_TEXT
|
} >RAM AT>FLASH_TEXT
|
||||||
|
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче