1// Package attr provides attributes for text and data sections.
2package attr
3
4import (
5	"fmt"
6	"math/bits"
7	"strings"
8)
9
10// Attribute represents TEXT or DATA flags.
11type Attribute uint16
12
13// Reference: https://github.com/golang/go/blob/aafe257390cc9048e8b5df898fabd79a9e0d4c39/src/runtime/textflag.h#L11-L37
14//
15//	// Don't profile the marked routine. This flag is deprecated.
16//	#define NOPROF	1
17//	// It is ok for the linker to get multiple of these symbols. It will
18//	// pick one of the duplicates to use.
19//	#define DUPOK	2
20//	// Don't insert stack check preamble.
21//	#define NOSPLIT	4
22//	// Put this data in a read-only section.
23//	#define RODATA	8
24//	// This data contains no pointers.
25//	#define NOPTR	16
26//	// This is a wrapper function and should not count as disabling 'recover'.
27//	#define WRAPPER 32
28//	// This function uses its incoming context register.
29//	#define NEEDCTXT 64
30//	// Allocate a word of thread local storage and store the offset from the
31//	// thread local base to the thread local storage in this variable.
32//	#define TLSBSS	256
33//	// Do not insert instructions to allocate a stack frame for this function.
34//	// Only valid on functions that declare a frame size of 0.
35//	// TODO(mwhudson): only implemented for ppc64x at present.
36//	#define NOFRAME 512
37//	// Function can call reflect.Type.Method or reflect.Type.MethodByName.
38//	#define REFLECTMETHOD 1024
39//	// Function is the top of the call stack. Call stack unwinders should stop
40//	// at this function.
41//	#define TOPFRAME 2048
42//
43const (
44	NOPROF Attribute = 1 << iota
45	DUPOK
46	NOSPLIT
47	RODATA
48	NOPTR
49	WRAPPER
50	NEEDCTXT
51	_
52	TLSBSS
53	NOFRAME
54	REFLECTMETHOD
55	TOPFRAME
56)
57
58// Asm returns a representation of the attributes in assembly syntax. This may use macros from "textflags.h"; see ContainsTextFlags() to determine if this header is required.
59func (a Attribute) Asm() string {
60	parts, rest := a.split()
61	if len(parts) == 0 || rest != 0 {
62		parts = append(parts, fmt.Sprintf("%d", rest))
63	}
64	return strings.Join(parts, "|")
65}
66
67// ContainsTextFlags returns whether the Asm() representation requires macros in "textflags.h".
68func (a Attribute) ContainsTextFlags() bool {
69	flags, _ := a.split()
70	return len(flags) > 0
71}
72
73// split splits a into known flags and any remaining bits.
74func (a Attribute) split() ([]string, Attribute) {
75	var flags []string
76	var rest Attribute
77	for a != 0 {
78		i := uint(bits.TrailingZeros16(uint16(a)))
79		bit := Attribute(1) << i
80		if flag := attrname[bit]; flag != "" {
81			flags = append(flags, flag)
82		} else {
83			rest |= bit
84		}
85		a ^= bit
86	}
87	return flags, rest
88}
89
90var attrname = map[Attribute]string{
91	NOPROF:        "NOPROF",
92	DUPOK:         "DUPOK",
93	NOSPLIT:       "NOSPLIT",
94	RODATA:        "RODATA",
95	NOPTR:         "NOPTR",
96	WRAPPER:       "WRAPPER",
97	NEEDCTXT:      "NEEDCTXT",
98	TLSBSS:        "TLSBSS",
99	NOFRAME:       "NOFRAME",
100	REFLECTMETHOD: "REFLECTMETHOD",
101	TOPFRAME:      "TOPFRAME",
102}
103