doc/asm.html HTML 1,081 lines View on github.com → Search inside
1<!--{2	"Title": "A Quick Guide to Go's Assembler",3	"Path":  "/doc/asm"4}-->56<h2 id="introduction">A Quick Guide to Go's Assembler</h2>78<p>9This document is a quick outline of the unusual form of assembly language used by the <code>gc</code> Go compiler.10The document is not comprehensive.11</p>1213<p>14The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail15<a href="https://9p.io/sys/doc/asm.html">elsewhere</a>.16If you plan to write assembly language, you should read that document although much of it is Plan 9-specific.17The current document provides a summary of the syntax and the differences with18what is explained in that document, and19describes the peculiarities that apply when writing assembly code to interact with Go.20</p>2122<p>23The most important thing to know about Go's assembler is that it is not a direct representation of the underlying machine.24Some of the details map precisely to the machine, but some do not.25This is because the compiler suite (see26<a href="https://9p.io/sys/doc/compiler.html">this description</a>)27needs no assembler pass in the usual pipeline.28Instead, the compiler operates on a kind of semi-abstract instruction set,29and instruction selection occurs partly after code generation.30The assembler works on the semi-abstract form, so31when you see an instruction like <code>MOV</code>32what the toolchain actually generates for that operation might33not be a move instruction at all, perhaps a clear or load.34Or it might correspond exactly to the machine instruction with that name.35In general, machine-specific operations tend to appear as themselves, while more general concepts like36memory move and subroutine call and return are more abstract.37The details vary with architecture, and we apologize for the imprecision; the situation is not well-defined.38</p>3940<p>41The assembler program is a way to parse a description of that42semi-abstract instruction set and turn it into instructions to be43input to the linker.44If you want to see what the instructions look like in assembly for a given architecture, say amd64, there45are many examples in the sources of the standard library, in packages such as46<a href="/pkg/runtime/"><code>runtime</code></a> and47<a href="/pkg/math/big/"><code>math/big</code></a>.48You can also examine what the compiler emits as assembly code49(the actual output may differ from what you see here):50</p>5152<pre>53$ cat x.go54package main5556func main() {57	println(3)58}59$ GOOS=linux GOARCH=amd64 go tool compile -S x.go        # or: go build -gcflags -S x.go60"".main STEXT size=74 args=0x0 locals=0x1061	0x0000 00000 (x.go:3)	TEXT	"".main(SB), $16-062	0x0000 00000 (x.go:3)	MOVQ	(TLS), CX63	0x0009 00009 (x.go:3)	CMPQ	SP, 16(CX)64	0x000d 00013 (x.go:3)	JLS	6765	0x000f 00015 (x.go:3)	SUBQ	$16, SP66	0x0013 00019 (x.go:3)	MOVQ	BP, 8(SP)67	0x0018 00024 (x.go:3)	LEAQ	8(SP), BP68	0x001d 00029 (x.go:3)	FUNCDATA	$0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)69	0x001d 00029 (x.go:3)	FUNCDATA	$1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)70	0x001d 00029 (x.go:3)	FUNCDATA	$2, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)71	0x001d 00029 (x.go:4)	PCDATA	$0, $072	0x001d 00029 (x.go:4)	PCDATA	$1, $073	0x001d 00029 (x.go:4)	CALL	runtime.printlock(SB)74	0x0022 00034 (x.go:4)	MOVQ	$3, (SP)75	0x002a 00042 (x.go:4)	CALL	runtime.printint(SB)76	0x002f 00047 (x.go:4)	CALL	runtime.printnl(SB)77	0x0034 00052 (x.go:4)	CALL	runtime.printunlock(SB)78	0x0039 00057 (x.go:5)	MOVQ	8(SP), BP79	0x003e 00062 (x.go:5)	ADDQ	$16, SP80	0x0042 00066 (x.go:5)	RET81	0x0043 00067 (x.go:5)	NOP82	0x0043 00067 (x.go:3)	PCDATA	$1, $-183	0x0043 00067 (x.go:3)	PCDATA	$0, $-184	0x0043 00067 (x.go:3)	CALL	runtime.morestack_noctxt(SB)85	0x0048 00072 (x.go:3)	JMP	086...87</pre>8889<p>90The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information91for use by the garbage collector; they are introduced by the compiler.92</p>9394<p>95To see what gets put in the binary after linking, use <code>go tool objdump</code>:96</p>9798<pre>99$ go build -o x.exe x.go100$ go tool objdump -s main.main x.exe101TEXT main.main(SB) /tmp/x.go102  x.go:3		0x10501c0		65488b0c2530000000	MOVQ GS:0x30, CX103  x.go:3		0x10501c9		483b6110		CMPQ 0x10(CX), SP104  x.go:3		0x10501cd		7634			JBE 0x1050203105  x.go:3		0x10501cf		4883ec10		SUBQ $0x10, SP106  x.go:3		0x10501d3		48896c2408		MOVQ BP, 0x8(SP)107  x.go:3		0x10501d8		488d6c2408		LEAQ 0x8(SP), BP108  x.go:4		0x10501dd		e86e45fdff		CALL runtime.printlock(SB)109  x.go:4		0x10501e2		48c7042403000000	MOVQ $0x3, 0(SP)110  x.go:4		0x10501ea		e8e14cfdff		CALL runtime.printint(SB)111  x.go:4		0x10501ef		e8ec47fdff		CALL runtime.printnl(SB)112  x.go:4		0x10501f4		e8d745fdff		CALL runtime.printunlock(SB)113  x.go:5		0x10501f9		488b6c2408		MOVQ 0x8(SP), BP114  x.go:5		0x10501fe		4883c410		ADDQ $0x10, SP115  x.go:5		0x1050202		c3			RET116  x.go:3		0x1050203		e83882ffff		CALL runtime.morestack_noctxt(SB)117  x.go:3		0x1050208		ebb6			JMP main.main(SB)118</pre>119120<h3 id="constants">Constants</h3>121122<p>123Although the assembler takes its guidance from the Plan 9 assemblers,124it is a distinct program, so there are some differences.125One is in constant evaluation.126Constant expressions in the assembler are parsed using Go's operator127precedence, not the C-like precedence of the original.128Thus <code>3&amp;1&lt;&lt;2</code> is 4, not 0it parses as <code>(3&amp;1)&lt;&lt;2</code>129not <code>3&amp;(1&lt;&lt;2)</code>.130Also, constants are always evaluated as 64-bit unsigned integers.131Thus <code>-2</code> is not the integer value minus two,132but the unsigned 64-bit integer with the same bit pattern.133The distinction rarely matters but134to avoid ambiguity, division or right shift where the right operand's135high bit is set is rejected.136</p>137138<h3 id="symbols">Symbols</h3>139140<p>141Some symbols, such as <code>R1</code> or <code>LR</code>,142are predefined and refer to registers.143The exact set depends on the architecture.144</p>145146<p>147There are four predeclared symbols that refer to pseudo-registers.148These are not real registers, but rather virtual registers maintained by149the toolchain, such as a frame pointer.150The set of pseudo-registers is the same for all architectures:151</p>152153<ul>154155<li>156<code>FP</code>: Frame pointer: arguments and locals.157</li>158159<li>160<code>PC</code>: Program counter:161jumps and branches.162</li>163164<li>165<code>SB</code>: Static base pointer: global symbols.166</li>167168<li>169<code>SP</code>: Stack pointer: the highest address within the local stack frame.170</li>171172</ul>173174<p>175All user-defined symbols are written as offsets to the pseudo-registers176<code>FP</code> (arguments and locals) and <code>SB</code> (globals).177</p>178179<p>180The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>181is the name <code>foo</code> as an address in memory.182This form is used to name global functions and data.183Adding <code>&lt;&gt;</code> to the name, as in <span style="white-space: nowrap"><code>foo&lt;&gt;(SB)</code></span>, makes the name184visible only in the current source file, like a top-level <code>static</code> declaration in a C file.185Adding an offset to the name refers to that offset from the symbol's address, so186<code>foo+4(SB)</code> is four bytes past the start of <code>foo</code>.187</p>188189<p>190The <code>FP</code> pseudo-register is a virtual frame pointer191used to refer to function arguments.192The compilers maintain a virtual frame pointer and refer to the arguments on the stack as offsets from that pseudo-register.193Thus <code>0(FP)</code> is the first argument to the function,194<code>8(FP)</code> is the second (on a 64-bit machine), and so on.195However, when referring to a function argument this way, it is necessary to place a name196at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.197(The meaning of the offsetoffset from the frame pointerdistinct198from its use with <code>SB</code>, where it is an offset from the symbol.)199The assembler enforces this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.200The actual name is semantically irrelevant but should be used to document201the argument's name.202It is worth stressing that <code>FP</code> is always a203pseudo-register, not a hardware204register, even on architectures with a hardware frame pointer.205</p>206207<p>208For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the argument names209and offsets match.210On 32-bit systems, the low and high 32 bits of a 64-bit value are distinguished by adding211a <code>_lo</code> or <code>_hi</code> suffix to the name, as in <code>arg_lo+0(FP)</code> or <code>arg_hi+4(FP)</code>.212If a Go prototype does not name its result, the expected assembly name is <code>ret</code>.213</p>214215<p>216The <code>SP</code> pseudo-register is a virtual stack pointer217used to refer to frame-local variables and the arguments being218prepared for function calls.219It points to the highest address within the local stack frame, so references should use negative offsets220in the range [−framesize, 0):221<code>x-8(SP)</code>, <code>y-4(SP)</code>, and so on.222</p>223224<p>225On architectures with a hardware register named <code>SP</code>,226the name prefix distinguishes227references to the virtual stack pointer from references to the architectural228<code>SP</code> register.229That is, <code>x-8(SP)</code> and <code>-8(SP)</code>230are different memory locations:231the first refers to the virtual stack pointer pseudo-register,232while the second refers to the233hardware's <code>SP</code> register.234</p>235236<p>237On machines where <code>SP</code> and <code>PC</code> are238traditionally aliases for a physical, numbered register,239in the Go assembler the names <code>SP</code> and <code>PC</code>240are still treated specially;241for instance, references to <code>SP</code> require a symbol,242much like <code>FP</code>.243To access the actual hardware register use the true <code>R</code> name.244For example, on the ARM architecture the hardware245<code>SP</code> and <code>PC</code> are accessible as246<code>R13</code> and <code>R15</code>.247</p>248249<p>250Branches and direct jumps are always written as offsets to the PC, or as251jumps to labels:252</p>253254<pre>255label:256	MOVW $0, R1257	JMP label258</pre>259260<p>261Each label is visible only within the function in which it is defined.262It is therefore permitted for multiple functions in a file to define263and use the same label names.264Direct jumps and call instructions can target text symbols,265such as <code>name(SB)</code>, but not offsets from symbols,266such as <code>name+4(SB)</code>.267</p>268269<p>270Instructions, registers, and assembler directives are always in UPPER CASE to remind you271that assembly programming is a fraught endeavor.272(Exception: the <code>g</code> register renaming on ARM.)273</p>274275<p>276In Go object files and binaries, the full name of a symbol is the277package path followed by a period and the symbol name:278<code>fmt.Printf</code> or <code>math/rand.Int</code>.279Because the assembler's parser treats period and slash as punctuation,280those strings cannot be used directly as identifier names.281Instead, the assembler allows the middle dot character U+00B7282and the division slash U+2215 in identifiers and rewrites them to283plain period and slash.284Within an assembler source file, the symbols above are written as285<code>fmt·Printf</code> and <code>mathrand·Int</code>.286The assembly listings generated by the compilers when using the <code>-S</code> flag287show the period and slash directly instead of the Unicode replacements288required by the assemblers.289</p>290291<p>292Most hand-written assembly files do not include the full package path293in symbol names, because the linker inserts the package path of the current294object file at the beginning of any name starting with a period:295in an assembly source file within the math/rand package implementation,296the package's Int function can be referred to as <code>·Int</code>.297This convention avoids the need to hard-code a package's import path in its298own source code, making it easier to move the code from one location to another.299</p>300301<h3 id="directives">Directives</h3>302303<p>304The assembler uses various directives to bind text and data to symbol names.305For example, here is a simple complete function definition. The <code>TEXT</code>306directive declares the symbol <code>runtime·profileloop</code> and the instructions307that follow form the body of the function.308The last instruction in a <code>TEXT</code> block must be some sort of jump, usually a <code>RET</code> (pseudo-)instruction.309(If it's not, the linker will append a jump-to-itself instruction; there is no fallthrough in <code>TEXTs</code>.)310After the symbol, the arguments are flags (see below)311and the frame size, a constant (but see below):312</p>313314<pre>315TEXT runtime·profileloop(SB),NOSPLIT,$8316	MOVQ	$runtime·profileloop1(SB), CX317	MOVQ	CX, 0(SP)318	CALL	runtime·externalthreadhandler(SB)319	RET320</pre>321322<p>323In the general case, the frame size is followed by an argument size, separated by a minus sign.324(It's not a subtraction, just idiosyncratic syntax.)325The frame size <code>$24-8</code> states that the function has a 24-byte frame326and is called with 8 bytes of argument, which live on the caller's frame.327If <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,328the argument size must be provided.329For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the330argument size is correct.331</p>332333<p>334Note that the symbol name uses a middle dot to separate the components and is specified as an offset from the335static base pseudo-register <code>SB</code>.336This function would be called from Go source for package <code>runtime</code> using the337simple name <code>profileloop</code>.338</p>339340<p>341Global data symbols are defined by a sequence of initializing342<code>DATA</code> directives followed by a <code>GLOBL</code> directive.343Each <code>DATA</code> directive initializes a section of the344corresponding memory.345The memory not explicitly initialized is zeroed.346The general form of the <code>DATA</code> directive is347348<pre>349DATA	symbol+offset(SB)/width, value350</pre>351352<p>353which initializes the symbol memory at the given offset and width with the given value.354The <code>DATA</code> directives for a given symbol must be written with increasing offsets.355</p>356357<p>358The <code>GLOBL</code> directive declares a symbol to be global.359The arguments are optional flags and the size of the data being declared as a global,360which will have initial value all zeros unless a <code>DATA</code> directive361has initialized it.362The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives.363</p>364365<p>366For example,367</p>368369<pre>370DATA divtab&lt;&gt;+0x00(SB)/4, $0xf4f8fcff371DATA divtab&lt;&gt;+0x04(SB)/4, $0xe6eaedf0372...373DATA divtab&lt;&gt;+0x3c(SB)/4, $0x81828384374GLOBL divtab&lt;&gt;(SB), RODATA, $64375376GLOBL runtime·tlsoffset(SB), NOPTR, $4377</pre>378379<p>380declares and initializes <code>divtab&lt;&gt;</code>, a read-only 64-byte table of 4-byte integer values,381and declares <code>runtime·tlsoffset</code>, a 4-byte, implicitly zeroed variable that382contains no pointers.383</p>384385<p>386There may be one or two arguments to the directives.387If there are two, the first is a bit mask of flags,388which can be written as numeric expressions, added or or-ed together,389or can be set symbolically for easier absorption by a human.390Their values, defined in the standard <code>#include</code>  file <code>textflag.h</code>, are:391</p>392393<ul>394<li>395<code>NOPROF</code> = 1396<br>397(For <code>TEXT</code> items.)398Don't profile the marked function.  This flag is deprecated.399</li>400<li>401<code>DUPOK</code> = 2402<br>403It is legal to have multiple instances of this symbol in a single binary.404The linker will choose one of the duplicates to use.405</li>406<li>407<code>NOSPLIT</code> = 4408<br>409(For <code>TEXT</code> items.)410Don't insert the preamble to check if the stack must be split.411The frame for the routine, plus anything it calls, must fit in the412spare space remaining in the current stack segment.413Used to protect routines such as the stack splitting code itself.414</li>415<li>416<code>RODATA</code> = 8417<br>418(For <code>DATA</code> and <code>GLOBL</code> items.)419Put this data in a read-only section.420</li>421<li>422<code>NOPTR</code> = 16423<br>424(For <code>DATA</code> and <code>GLOBL</code> items.)425This data contains no pointers and therefore does not need to be426scanned by the garbage collector.427</li>428<li>429<code>WRAPPER</code> = 32430<br>431(For <code>TEXT</code> items.)432This is a wrapper function and should not count as disabling <code>recover</code>.433</li>434<li>435<code>NEEDCTXT</code> = 64436<br>437(For <code>TEXT</code> items.)438This function is a closure so it uses its incoming context register.439</li>440<li>441<code>LOCAL</code> = 128442<br>443This symbol is local to the dynamic shared object.444</li>445<li>446<code>TLSBSS</code> = 256447<br>448(For <code>DATA</code> and <code>GLOBL</code> items.)449Put this data in thread local storage.450</li>451<li>452<code>NOFRAME</code> = 512453<br>454(For <code>TEXT</code> items.)455Do not insert instructions to allocate a stack frame and save/restore the return456address, even if this is not a leaf function.457Only valid on functions that declare a frame size of 0.458</li>459<li>460<code>TOPFRAME</code> = 2048461<br>462(For <code>TEXT</code> items.)463Function is the outermost frame of the call stack. Traceback should stop at this function.464</li>465</ul>466467<h3 id="special-instructions">Special instructions</h3>468469<p>470The <code>PCALIGN</code> pseudo-instruction is used to indicate that the next instruction should be aligned471to a specified boundary by padding with no-op instructions.472</p>473474<p>475It is currently supported on arm64, amd64, ppc64, loong64 and riscv64.476477For example, the start of the <code>MOVD</code> instruction below is aligned to 32 bytes:478</p>479480<pre>481PCALIGN $32482MOVD $2, R0483</pre>484485<h3 id="data-offsets">Interacting with Go types and constants</h3>486487<p>488If a package has any .s files, then <code>go build</code> will direct489the compiler to emit a special header called <code>go_asm.h</code>,490which the .s files can then <code>#include</code>.491The file contains symbolic <code>#define</code> constants for the492offsets of Go struct fields, the sizes of Go struct types, and most493Go <code>const</code> declarations defined in the current package.494Go assembly should avoid making assumptions about the layout of Go495types and instead use these constants.496This improves the readability of assembly code, and keeps it robust to497changes in data layout either in the Go type definitions or in the498layout rules used by the Go compiler.499</p>500501<p>502Constants are of the form <code>const_<i>name</i></code>.503For example, given the Go declaration <code>const bufSize =5041024</code>, assembly code can refer to the value of this constant505as <code>const_bufSize</code>.506</p>507508<p>509Field offsets are of the form <code><i>type</i>_<i>field</i></code>.510Struct sizes are of the form <code><i>type</i>__size</code>.511For example, consider the following Go definition:512</p>513514<pre>515type reader struct {516	buf [bufSize]byte517	r   int518}519</pre>520521<p>522Assembly can refer to the size of this struct523as <code>reader__size</code> and the offsets of the two fields524as <code>reader_buf</code> and <code>reader_r</code>.525Hence, if register <code>R1</code> contains a pointer to526a <code>reader</code>, assembly can reference the <code>r</code> field527as <code>reader_r(R1)</code>.528</p>529530<p>531If any of these <code>#define</code> names are ambiguous (for example,532a struct with a <code>_size</code> field), <code>#include533"go_asm.h"</code> will fail with a "redefinition of macro" error.534</p>535536<h3 id="runtime">Runtime Coordination</h3>537538<p>539For garbage collection to run correctly, the runtime must know the540location of pointers in all global data and in most stack frames.541The Go compiler emits this information when compiling Go source files,542but assembly programs must define it explicitly.543</p>544545<p>546A data symbol marked with the <code>NOPTR</code> flag (see above)547is treated as containing no pointers to runtime-allocated data.548A data symbol with the <code>RODATA</code> flag549is allocated in read-only memory and is therefore treated550as implicitly marked <code>NOPTR</code>.551A data symbol with a total size smaller than a pointer552is also treated as implicitly marked <code>NOPTR</code>.553It is not possible to define a symbol containing pointers in an assembly source file;554such a symbol must be defined in a Go source file instead.555Assembly source can still refer to the symbol by name556even without <code>DATA</code> and <code>GLOBL</code> directives.557A good general rule of thumb is to define all non-<code>RODATA</code>558symbols in Go instead of in assembly.559</p>560561<p>562Each function also needs annotations giving the location of563live pointers in its arguments, results, and local stack frame.564For an assembly function with no pointer results and565either no local stack frame or no function calls,566the only requirement is to define a Go prototype for the function567in a Go source file in the same package. The name of the assembly568function must not contain the package name component (for example,569function <code>Syscall</code> in package <code>syscall</code> should570use the name <codeSyscall</code> instead of the equivalent name571<code>syscall·Syscall</code> in its <code>TEXT</code> directive).572For more complex situations, explicit annotation is needed.573These annotations use pseudo-instructions defined in the standard574<code>#include</code> file <code>funcdata.h</code>.575</p>576577<p>578If a function has no arguments and no results,579the pointer information can be omitted.580This is indicated by an argument size annotation of <code>$<i>n</i>-0</code>581on the <code>TEXT</code> instruction.582Otherwise, pointer information must be provided by583a Go prototype for the function in a Go source file,584even for assembly functions not called directly from Go.585(The prototype will also let <code>go</code> <code>vet</code> check the argument references.)586At the start of the function, the arguments are assumed587to be initialized but the results are assumed uninitialized.588If the results will hold live pointers during a call instruction,589the function should start by zeroing the results and then590executing the pseudo-instruction <code>GO_RESULTS_INITIALIZED</code>.591This instruction records that the results are now initialized592and should be scanned during stack movement and garbage collection.593It is typically easier to arrange that assembly functions do not594return pointers or do not contain call instructions;595no assembly functions in the standard library use596<code>GO_RESULTS_INITIALIZED</code>.597</p>598599<p>600If a function has no local stack frame,601the pointer information can be omitted.602This is indicated by a local frame size annotation of <code>$0-<i>n</i></code>603on the <code>TEXT</code> instruction.604The pointer information can also be omitted if the605function contains no call instructions.606Otherwise, the local stack frame must not contain pointers,607and the assembly must confirm this fact by executing the608pseudo-instruction <code>NO_LOCAL_POINTERS</code>.609Because stack resizing is implemented by moving the stack,610the stack pointer may change during any function call:611even pointers to stack data must not be kept in local variables.612</p>613614<p>615Assembly functions should always be given Go prototypes,616both to provide pointer information for the arguments and results617and to let <code>go</code> <code>vet</code> check that618the offsets being used to access them are correct.619</p>620621<h2 id="architectures">Architecture-specific details</h2>622623<p>624It is impractical to list all the instructions and other details for each machine.625To see what instructions are defined for a given machine, say ARM,626look in the source for the <code>obj</code> support library for627that architecture, located in the directory <code>src/cmd/internal/obj/arm</code>.628In that directory is a file <code>a.out.go</code>; it contains629a long list of constants starting with <code>A</code>, like this:630</p>631632<pre>633const (634	AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota635	AEOR636	ASUB637	ARSB638	AADD639	...640</pre>641642<p>643This is the list of instructions and their spellings as known to the assembler and linker for that architecture.644Each instruction begins with an initial capital <code>A</code> in this list, so <code>AAND</code>645represents the bitwise and instruction,646<code>AND</code> (without the leading <code>A</code>),647and is written in assembly source as <code>AND</code>.648The enumeration is mostly in alphabetical order.649(The architecture-independent <code>AXXX</code>, defined in the650<code>cmd/internal/obj</code> package,651represents an invalid instruction).652The sequence of the <code>A</code> names has nothing to do with the actual653encoding of the machine instructions.654The <code>cmd/internal/obj</code> package takes care of that detail.655</p>656657<p>658The instructions for both the 386 and AMD64 architectures are listed in659<code>cmd/internal/obj/x86/a.out.go</code>.660</p>661662<p>663The architectures share syntax for common addressing modes such as664<code>(R1)</code> (register indirect),665<code>4(R1)</code> (register indirect with offset), and666<code>$foo(SB)</code> (absolute address).667The assembler also supports some (not necessarily all) addressing modes668specific to each architecture.669The sections below list these.670</p>671672<p>673One detail evident in the examples from the previous sections is that data in the instructions flows from left to right:674<code>MOVQ</code> <code>$0,</code> <code>CX</code> clears <code>CX</code>.675This rule applies even on architectures where the conventional notation uses the opposite direction.676</p>677678<p>679Here follow some descriptions of key Go-specific details for the supported architectures.680</p>681682<h3 id="x86">32-bit Intel 386</h3>683684<p>685The runtime pointer to the <code>g</code> structure is maintained686through the value of an otherwise unused (as far as Go is concerned) register in the MMU.687In the runtime package, assembly code can include <code>go_tls.h</code>, which defines688an OS- and architecture-dependent macro <code>get_tls</code> for accessing this register.689The <code>get_tls</code> macro takes one argument, which is the register to load the690<code>g</code> pointer into.691</p>692693<p>694For example, the sequence to load <code>g</code> and <code>m</code>695using <code>CX</code> looks like this:696</p>697698<pre>699#include "go_tls.h"700#include "go_asm.h"701...702get_tls(CX)703MOVL	g(CX), AX     // Move g into AX.704MOVL	g_m(AX), BX   // Move g.m into BX.705</pre>706707<p>708The <code>get_tls</code> macro is also defined on <a href="#amd64">amd64</a>.709</p>710711<p>712Addressing modes:713</p>714715<ul>716717<li>718<code>(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code>.719</li>720721<li>722<code>64(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code> plus 64.723These modes accept only 1, 2, 4, and 8 as scale factors.724</li>725726</ul>727728<p>729When using the compiler and assembler's730<code>-dynlink</code> or <code>-shared</code> modes,731any load or store of a fixed memory location such as a global variable732must be assumed to overwrite <code>CX</code>.733Therefore, to be safe for use with these modes,734assembly sources should typically avoid CX except between memory references.735</p>736737<h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>738739<p>740The two architectures behave largely the same at the assembler level.741Assembly code to access the <code>m</code> and <code>g</code>742pointers on the 64-bit version is the same as on the 32-bit 386,743except it uses <code>MOVQ</code> rather than <code>MOVL</code>:744</p>745746<pre>747get_tls(CX)748MOVQ	g(CX), AX     // Move g into AX.749MOVQ	g_m(AX), BX   // Move g.m into BX.750</pre>751752<p>753Register <code>BP</code> is callee-save.754The assembler automatically inserts <code>BP</code> save/restore when frame size is larger than zero.755Using <code>BP</code> as a general purpose register is allowed,756however it can interfere with sampling-based profiling.757</p>758759<h3 id="arm">ARM</h3>760761<p>762The registers <code>R10</code> and <code>R11</code>763are reserved by the compiler and linker.764</p>765766<p>767<code>R10</code> points to the <code>g</code> (goroutine) structure.768Within assembler source code, this pointer must be referred to as <code>g</code>;769the name <code>R10</code> is not recognized.770</p>771772<p>773To make it easier for people and compilers to write assembly, the ARM linker774allows general addressing forms and pseudo-operations like <code>DIV</code> or <code>MOD</code>775that may not be expressible using a single hardware instruction.776It implements these forms as multiple instructions, often using the <code>R11</code> register777to hold temporary values.778Hand-written assembly can use <code>R11</code>, but doing so requires779being sure that the linker is not also using it to implement any of the other780instructions in the function.781</p>782783<p>784When defining a <code>TEXT</code>, specifying frame size <code>$-4</code>785tells the linker that this is a leaf function that does not need to save <code>LR</code> on entry.786</p>787788<p>789The name <code>SP</code> always refers to the virtual stack pointer described earlier.790For the hardware register, use <code>R13</code>.791</p>792793<p>794Condition code syntax is to append a period and the one- or two-letter code to the instruction,795as in <code>MOVW.EQ</code>.796Multiple codes may be appended: <code>MOVM.IA.W</code>.797The order of the code modifiers is irrelevant.798</p>799800<p>801Addressing modes:802</p>803804<ul>805806<li>807<code>R0-&gt;16</code>808<br>809<code>R0&gt;&gt;16</code>810<br>811<code>R0&lt;&lt;16</code>812<br>813<code>R0@&gt;16</code>:814For <code>&lt;&lt;</code>, left shift <code>R0</code> by 16 bits.815The other codes are <code>-&gt;</code> (arithmetic right shift),816<code>&gt;&gt;</code> (logical right shift), and817<code>@&gt;</code> (rotate right).818</li>819820<li>821<code>R0-&gt;R1</code>822<br>823<code>R0&gt;&gt;R1</code>824<br>825<code>R0&lt;&lt;R1</code>826<br>827<code>R0@&gt;R1</code>:828For <code>&lt;&lt;</code>, left shift <code>R0</code> by the count in <code>R1</code>.829The other codes are <code>-&gt;</code> (arithmetic right shift),830<code>&gt;&gt;</code> (logical right shift), and831<code>@&gt;</code> (rotate right).832833</li>834835<li>836<code>[R0,g,R12-R15]</code>: For multi-register instructions, the set comprising837<code>R0</code>, <code>g</code>, and <code>R12</code> through <code>R15</code> inclusive.838</li>839840<li>841<code>(R5, R6)</code>: Destination register pair.842</li>843844</ul>845846<h3 id="arm64">ARM64</h3>847848<p>849<code>R18</code> is the "platform register", reserved on the Apple platform.850To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.851<code>R27</code> and <code>R28</code> are reserved by the compiler and linker.852<code>R29</code> is the frame pointer.853<code>R30</code> is the link register.854</p>855856<p>857Instruction modifiers are appended to the instruction following a period.858The only modifiers are <code>P</code> (postincrement) and <code>W</code>859(preincrement):860<code>MOVW.P</code>, <code>MOVW.W</code>861</p>862863<p>864Addressing modes:865</p>866867<ul>868869<li>870<code>R0-&gt;16</code>871<br>872<code>R0&gt;&gt;16</code>873<br>874<code>R0&lt;&lt;16</code>875<br>876<code>R0@&gt;16</code>:877These are the same as on the 32-bit ARM.878</li>879880<li>881<code>$(8&lt;&lt;12)</code>:882Left shift the immediate value <code>8</code> by <code>12</code> bits.883</li>884885<li>886<code>8(R0)</code>:887Add the value of <code>R0</code> and <code>8</code>.888</li>889890<li>891<code>(R2)(R0)</code>:892The location at <code>R0</code> plus <code>R2</code>.893</li>894895<li>896<code>R0.UXTB</code>897<br>898<code>R0.UXTB&lt;&lt;imm</code>:899<code>UXTB</code>: extract an 8-bit value from the low-order bits of <code>R0</code> and zero-extend it to the size of <code>R0</code>.900<code>R0.UXTB&lt;&lt;imm</code>: left shift the result of <code>R0.UXTB</code> by <code>imm</code> bits.901The <code>imm</code> value can be 0, 1, 2, 3, or 4.902The other extensions include <code>UXTH</code> (16-bit), <code>UXTW</code> (32-bit), and <code>UXTX</code> (64-bit).903</li>904905<li>906<code>R0.SXTB</code>907<br>908<code>R0.SXTB&lt;&lt;imm</code>:909<code>SXTB</code>: extract an 8-bit value from the low-order bits of <code>R0</code> and sign-extend it to the size of <code>R0</code>.910<code>R0.SXTB&lt;&lt;imm</code>: left shift the result of <code>R0.SXTB</code> by <code>imm</code> bits.911The <code>imm</code> value can be 0, 1, 2, 3, or 4.912The other extensions include <code>SXTH</code> (16-bit), <code>SXTW</code> (32-bit), and <code>SXTX</code> (64-bit).913</li>914915<li>916<code>(R5, R6)</code>: Register pair for <code>LDAXP</code>/<code>LDP</code>/<code>LDXP</code>/<code>STLXP</code>/<code>STP</code>/<code>STP</code>.917</li>918919</ul>920921<p>922Reference: <a href="/pkg/cmd/internal/obj/arm64">Go ARM64 Assembly Instructions Reference Manual</a>923</p>924925<h3 id="ppc64">PPC64</h3>926927<p>928This assembler is used by GOARCH values ppc64 and ppc64le.929</p>930931<p>932Reference: <a href="/pkg/cmd/internal/obj/ppc64">Go PPC64 Assembly Instructions Reference Manual</a>933</p>934935<h3 id="s390x">IBM z/Architecture, a.k.a. s390x</h3>936937<p>938The registers <code>R10</code> and <code>R11</code> are reserved.939The assembler uses them to hold temporary values when assembling some instructions.940</p>941942<p>943<code>R13</code> points to the <code>g</code> (goroutine) structure.944This register must be referred to as <code>g</code>; the name <code>R13</code> is not recognized.945</p>946947<p>948<code>R15</code> points to the stack frame and should typically only be accessed using the949virtual registers <code>SP</code> and <code>FP</code>.950</p>951952<p>953Load- and store-multiple instructions operate on a range of registers.954The range of registers is specified by a start register and an end register.955For example, <code>LMG</code> <code>(R9),</code> <code>R5,</code> <code>R7</code> would load956<code>R5</code>, <code>R6</code> and <code>R7</code> with the 64-bit values at957<code>0(R9)</code>, <code>8(R9)</code> and <code>16(R9)</code> respectively.958</p>959960<p>961Storage-and-storage instructions such as <code>MVC</code> and <code>XC</code> are written962with the length as the first argument.963For example, <code>XC</code> <code>$8,</code> <code>(R9),</code> <code>(R9)</code> would clear964eight bytes at the address specified in <code>R9</code>.965</p>966967<p>968If a vector instruction takes a length or an index as an argument then it will be the969first argument.970For example, <code>VLEIF</code> <code>$1,</code> <code>$16,</code> <code>V2</code> will load971the value sixteen into index one of <code>V2</code>.972Care should be taken when using vector instructions to ensure that they are available at973runtime.974To use vector instructions a machine must have both the vector facility (bit 129 in the975facility list) and kernel support.976Without kernel support a vector instruction will have no effect (it will be equivalent977to a <code>NOP</code> instruction).978</p>979980<p>981Addressing modes:982</p>983984<ul>985986<li>987<code>(R5)(R6*1)</code>: The location at <code>R5</code> plus <code>R6</code>.988It is a scaled mode as on the x86, but the only scale allowed is <code>1</code>.989</li>990991</ul>992993<h3 id="mips">MIPS, MIPS64</h3>994995<p>996General purpose registers are named <code>R0</code> through <code>R31</code>,997floating point registers are <code>F0</code> through <code>F31</code>.998</p>9991000<p>1001<code>R30</code> is reserved to point to <code>g</code>.1002<code>R23</code> is used as a temporary register.1003</p>10041005<p>1006In a <code>TEXT</code> directive, the frame size <code>$-4</code> for MIPS or1007<code>$-8</code> for MIPS64 instructs the linker not to save <code>LR</code>.1008</p>10091010<p>1011<code>SP</code> refers to the virtual stack pointer.1012For the hardware register, use <code>R29</code>.1013</p>10141015<p>1016Addressing modes:1017</p>10181019<ul>10201021<li>1022<code>16(R1)</code>: The location at <code>R1</code> plus 16.1023</li>10241025<li>1026<code>(R1)</code>: Alias for <code>0(R1)</code>.1027</li>10281029</ul>10301031<p>1032The value of <code>GOMIPS</code> environment variable (<code>hardfloat</code> or1033<code>softfloat</code>) is made available to assembly code by predefining either1034<code>GOMIPS_hardfloat</code> or <code>GOMIPS_softfloat</code>.1035</p>10361037<p>1038The value of <code>GOMIPS64</code> environment variable (<code>hardfloat</code> or1039<code>softfloat</code>) is made available to assembly code by predefining either1040<code>GOMIPS64_hardfloat</code> or <code>GOMIPS64_softfloat</code>.1041</p>10421043<h3 id="riscv64">RISCV64</h3>10441045<p>1046Reference: <a href="/pkg/cmd/internal/obj/riscv">Go RISCV64 Assembly Instructions Reference Manual</a>1047</p>10481049<h3 id="unsupported_opcodes">Unsupported opcodes</h3>10501051<p>1052The assemblers are designed to support the compiler so not all hardware instructions1053are defined for all architectures: if the compiler doesn't generate it, it might not be there.1054If you need to use a missing instruction, there are two ways to proceed.1055One is to update the assembler to support that instruction, which is straightforward1056but only worthwhile if it's likely the instruction will be used again.1057Instead, for simple one-off cases, it's possible to use the <code>BYTE</code>1058and <code>WORD</code> directives1059to lay down explicit data into the instruction stream within a <code>TEXT</code>.1060Here's how the 386 runtime defines the 64-bit atomic load function.1061</p>10621063<pre>1064// uint64 atomicload64(uint64 volatile* addr);1065// so actually1066// void atomicload64(uint64 *res, uint64 volatile *addr);1067TEXT runtime·atomicload64(SB), NOSPLIT, $0-121068	MOVL	ptr+0(FP), AX1069	TESTL	$7, AX1070	JZ	2(PC)1071	MOVL	0, AX // crash with nil ptr deref1072	LEAL	ret_lo+4(FP), BX1073	// MOVQ (%EAX), %MM01074	BYTE $0x0f; BYTE $0x6f; BYTE $0x001075	// MOVQ %MM0, 0(%EBX)1076	BYTE $0x0f; BYTE $0x7f; BYTE $0x031077	// EMMS1078	BYTE $0x0F; BYTE $0x771079	RET1080</pre>

Code quality findings 1

Inline CSS detected; use external stylesheets for maintainability and performance
info maintainability inline-css
Adding <code>&lt;&gt;</code> to the name, as in <span style="white-space: nowrap"><code>foo&lt;&gt;(SB)</code></span>, makes the name

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.