1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
|
<!--{
"Title": "A Quick Guide to Go's Assembler",
"Path": "/doc/asm"
}-->
<h2 id="introduction">A Quick Guide to Go's Assembler</h2>
<p>
This document is a quick outline of the unusual form of assembly language used by the <code>gc</code> Go compiler.
The document is not comprehensive.
</p>
<p>
The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail
<a href="https://9p.io/sys/doc/asm.html">elsewhere</a>.
If you plan to write assembly language, you should read that document although much of it is Plan 9-specific.
The current document provides a summary of the syntax and the differences with
what is explained in that document, and
describes the peculiarities that apply when writing assembly code to interact with Go.
</p>
<p>
The most important thing to know about Go's assembler is that it is not a direct representation of the underlying machine.
Some of the details map precisely to the machine, but some do not.
This is because the compiler suite (see
<a href="https://9p.io/sys/doc/compiler.html">this description</a>)
needs no assembler pass in the usual pipeline.
Instead, the compiler operates on a kind of semi-abstract instruction set,
and instruction selection occurs partly after code generation.
The assembler works on the semi-abstract form, so
when you see an instruction like <code>MOV</code>
what the toolchain actually generates for that operation might
not be a move instruction at all, perhaps a clear or load.
Or it might correspond exactly to the machine instruction with that name.
In general, machine-specific operations tend to appear as themselves, while more general concepts like
memory move and subroutine call and return are more abstract.
The details vary with architecture, and we apologize for the imprecision; the situation is not well-defined.
</p>
<p>
The assembler program is a way to parse a description of that
semi-abstract instruction set and turn it into instructions to be
input to the linker.
If you want to see what the instructions look like in assembly for a given architecture, say amd64, there
are many examples in the sources of the standard library, in packages such as
<a href="/pkg/runtime/"><code>runtime</code></a> and
<a href="/pkg/math/big/"><code>math/big</code></a>.
You can also examine what the compiler emits as assembly code
(the actual output may differ from what you see here):
</p>
<pre>
$ cat x.go
package main
func main() {
println(3)
}
$ GOOS=linux GOARCH=amd64 go tool compile -S x.go # or: go build -gcflags -S x.go
"".main STEXT size=74 args=0x0 locals=0x10
0x0000 00000 (x.go:3) TEXT "".main(SB), $16-0
0x0000 00000 (x.go:3) MOVQ (TLS), CX
0x0009 00009 (x.go:3) CMPQ SP, 16(CX)
0x000d 00013 (x.go:3) JLS 67
0x000f 00015 (x.go:3) SUBQ $16, SP
0x0013 00019 (x.go:3) MOVQ BP, 8(SP)
0x0018 00024 (x.go:3) LEAQ 8(SP), BP
0x001d 00029 (x.go:3) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001d 00029 (x.go:3) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001d 00029 (x.go:3) FUNCDATA $2, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
0x001d 00029 (x.go:4) PCDATA $0, $0
0x001d 00029 (x.go:4) PCDATA $1, $0
0x001d 00029 (x.go:4) CALL runtime.printlock(SB)
0x0022 00034 (x.go:4) MOVQ $3, (SP)
0x002a 00042 (x.go:4) CALL runtime.printint(SB)
0x002f 00047 (x.go:4) CALL runtime.printnl(SB)
0x0034 00052 (x.go:4) CALL runtime.printunlock(SB)
0x0039 00057 (x.go:5) MOVQ 8(SP), BP
0x003e 00062 (x.go:5) ADDQ $16, SP
0x0042 00066 (x.go:5) RET
0x0043 00067 (x.go:5) NOP
0x0043 00067 (x.go:3) PCDATA $1, $-1
0x0043 00067 (x.go:3) PCDATA $0, $-1
0x0043 00067 (x.go:3) CALL runtime.morestack_noctxt(SB)
0x0048 00072 (x.go:3) JMP 0
...
</pre>
<p>
The <code>FUNCDATA</code> and <code>PCDATA</code> directives contain information
for use by the garbage collector; they are introduced by the compiler.
</p>
<p>
To see what gets put in the binary after linking, use <code>go tool objdump</code>:
</p>
<pre>
$ go build -o x.exe x.go
$ go tool objdump -s main.main x.exe
TEXT main.main(SB) /tmp/x.go
x.go:3 0x10501c0 65488b0c2530000000 MOVQ GS:0x30, CX
x.go:3 0x10501c9 483b6110 CMPQ 0x10(CX), SP
x.go:3 0x10501cd 7634 JBE 0x1050203
x.go:3 0x10501cf 4883ec10 SUBQ $0x10, SP
x.go:3 0x10501d3 48896c2408 MOVQ BP, 0x8(SP)
x.go:3 0x10501d8 488d6c2408 LEAQ 0x8(SP), BP
x.go:4 0x10501dd e86e45fdff CALL runtime.printlock(SB)
x.go:4 0x10501e2 48c7042403000000 MOVQ $0x3, 0(SP)
x.go:4 0x10501ea e8e14cfdff CALL runtime.printint(SB)
x.go:4 0x10501ef e8ec47fdff CALL runtime.printnl(SB)
x.go:4 0x10501f4 e8d745fdff CALL runtime.printunlock(SB)
x.go:5 0x10501f9 488b6c2408 MOVQ 0x8(SP), BP
x.go:5 0x10501fe 4883c410 ADDQ $0x10, SP
x.go:5 0x1050202 c3 RET
x.go:3 0x1050203 e83882ffff CALL runtime.morestack_noctxt(SB)
x.go:3 0x1050208 ebb6 JMP main.main(SB)
</pre>
<h3 id="constants">Constants</h3>
<p>
Although the assembler takes its guidance from the Plan 9 assemblers,
it is a distinct program, so there are some differences.
One is in constant evaluation.
Constant expressions in the assembler are parsed using Go's operator
precedence, not the C-like precedence of the original.
Thus <code>3&1<<2</code> is 4, not 0—it parses as <code>(3&1)<<2</code>
not <code>3&(1<<2)</code>.
Also, constants are always evaluated as 64-bit unsigned integers.
Thus <code>-2</code> is not the integer value minus two,
but the unsigned 64-bit integer with the same bit pattern.
The distinction rarely matters but
to avoid ambiguity, division or right shift where the right operand's
high bit is set is rejected.
</p>
<h3 id="symbols">Symbols</h3>
<p>
Some symbols, such as <code>R1</code> or <code>LR</code>,
are predefined and refer to registers.
The exact set depends on the architecture.
</p>
<p>
There are four predeclared symbols that refer to pseudo-registers.
These are not real registers, but rather virtual registers maintained by
the toolchain, such as a frame pointer.
The set of pseudo-registers is the same for all architectures:
</p>
<ul>
<li>
<code>FP</code>: Frame pointer: arguments and locals.
</li>
<li>
<code>PC</code>: Program counter:
jumps and branches.
</li>
<li>
<code>SB</code>: Static base pointer: global symbols.
</li>
<li>
<code>SP</code>: Stack pointer: top of stack.
</li>
</ul>
<p>
All user-defined symbols are written as offsets to the pseudo-registers
<code>FP</code> (arguments and locals) and <code>SB</code> (globals).
</p>
<p>
The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>
is the name <code>foo</code> as an address in memory.
This form is used to name global functions and data.
Adding <code><></code> to the name, as in <span style="white-space: nowrap"><code>foo<>(SB)</code></span>, makes the name
visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
Adding an offset to the name refers to that offset from the symbol's address, so
<code>foo+4(SB)</code> is four bytes past the start of <code>foo</code>.
</p>
<p>
The <code>FP</code> pseudo-register is a virtual frame pointer
used to refer to function arguments.
The compilers maintain a virtual frame pointer and refer to the arguments on the stack as offsets from that pseudo-register.
Thus <code>0(FP)</code> is the first argument to the function,
<code>8(FP)</code> is the second (on a 64-bit machine), and so on.
However, when referring to a function argument this way, it is necessary to place a name
at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.
(The meaning of the offset—offset from the frame pointer—distinct
from its use with <code>SB</code>, where it is an offset from the symbol.)
The assembler enforces this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
The actual name is semantically irrelevant but should be used to document
the argument's name.
It is worth stressing that <code>FP</code> is always a
pseudo-register, not a hardware
register, even on architectures with a hardware frame pointer.
</p>
<p>
For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the argument names
and offsets match.
On 32-bit systems, the low and high 32 bits of a 64-bit value are distinguished by adding
a <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>.
If a Go prototype does not name its result, the expected assembly name is <code>ret</code>.
</p>
<p>
The <code>SP</code> pseudo-register is a virtual stack pointer
used to refer to frame-local variables and the arguments being
prepared for function calls.
It points to the top of the local stack frame, so references should use negative offsets
in the range [−framesize, 0):
<code>x-8(SP)</code>, <code>y-4(SP)</code>, and so on.
</p>
<p>
On architectures with a hardware register named <code>SP</code>,
the name prefix distinguishes
references to the virtual stack pointer from references to the architectural
<code>SP</code> register.
That is, <code>x-8(SP)</code> and <code>-8(SP)</code>
are different memory locations:
the first refers to the virtual stack pointer pseudo-register,
while the second refers to the
hardware's <code>SP</code> register.
</p>
<p>
On machines where <code>SP</code> and <code>PC</code> are
traditionally aliases for a physical, numbered register,
in the Go assembler the names <code>SP</code> and <code>PC</code>
are still treated specially;
for instance, references to <code>SP</code> require a symbol,
much like <code>FP</code>.
To access the actual hardware register use the true <code>R</code> name.
For example, on the ARM architecture the hardware
<code>SP</code> and <code>PC</code> are accessible as
<code>R13</code> and <code>R15</code>.
</p>
<p>
Branches and direct jumps are always written as offsets to the PC, or as
jumps to labels:
</p>
<pre>
label:
MOVW $0, R1
JMP label
</pre>
<p>
Each label is visible only within the function in which it is defined.
It is therefore permitted for multiple functions in a file to define
and use the same label names.
Direct jumps and call instructions can target text symbols,
such as <code>name(SB)</code>, but not offsets from symbols,
such as <code>name+4(SB)</code>.
</p>
<p>
Instructions, registers, and assembler directives are always in UPPER CASE to remind you
that assembly programming is a fraught endeavor.
(Exception: the <code>g</code> register renaming on ARM.)
</p>
<p>
In Go object files and binaries, the full name of a symbol is the
package path followed by a period and the symbol name:
<code>fmt.Printf</code> or <code>math/rand.Int</code>.
Because the assembler's parser treats period and slash as punctuation,
those strings cannot be used directly as identifier names.
Instead, the assembler allows the middle dot character U+00B7
and the division slash U+2215 in identifiers and rewrites them to
plain period and slash.
Within an assembler source file, the symbols above are written as
<code>fmt·Printf</code> and <code>math∕rand·Int</code>.
The assembly listings generated by the compilers when using the <code>-S</code> flag
show the period and slash directly instead of the Unicode replacements
required by the assemblers.
</p>
<p>
Most hand-written assembly files do not include the full package path
in symbol names, because the linker inserts the package path of the current
object file at the beginning of any name starting with a period:
in an assembly source file within the math/rand package implementation,
the package's Int function can be referred to as <code>·Int</code>.
This convention avoids the need to hard-code a package's import path in its
own source code, making it easier to move the code from one location to another.
</p>
<h3 id="directives">Directives</h3>
<p>
The assembler uses various directives to bind text and data to symbol names.
For example, here is a simple complete function definition. The <code>TEXT</code>
directive declares the symbol <code>runtime·profileloop</code> and the instructions
that follow form the body of the function.
The last instruction in a <code>TEXT</code> block must be some sort of jump, usually a <code>RET</code> (pseudo-)instruction.
(If it's not, the linker will append a jump-to-itself instruction; there is no fallthrough in <code>TEXTs</code>.)
After the symbol, the arguments are flags (see below)
and the frame size, a constant (but see below):
</p>
<pre>
TEXT runtime·profileloop(SB),NOSPLIT,$8
MOVQ $runtime·profileloop1(SB), CX
MOVQ CX, 0(SP)
CALL runtime·externalthreadhandler(SB)
RET
</pre>
<p>
In the general case, the frame size is followed by an argument size, separated by a minus sign.
(It's not a subtraction, just idiosyncratic syntax.)
The frame size <code>$24-8</code> states that the function has a 24-byte frame
and is called with 8 bytes of argument, which live on the caller's frame.
If <code>NOSPLIT</code> is not specified for the <code>TEXT</code>,
the argument size must be provided.
For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the
argument size is correct.
</p>
<p>
Note that the symbol name uses a middle dot to separate the components and is specified as an offset from the
static base pseudo-register <code>SB</code>.
This function would be called from Go source for package <code>runtime</code> using the
simple name <code>profileloop</code>.
</p>
<p>
Global data symbols are defined by a sequence of initializing
<code>DATA</code> directives followed by a <code>GLOBL</code> directive.
Each <code>DATA</code> directive initializes a section of the
corresponding memory.
The memory not explicitly initialized is zeroed.
The general form of the <code>DATA</code> directive is
<pre>
DATA symbol+offset(SB)/width, value
</pre>
<p>
which initializes the symbol memory at the given offset and width with the given value.
The <code>DATA</code> directives for a given symbol must be written with increasing offsets.
</p>
<p>
The <code>GLOBL</code> directive declares a symbol to be global.
The arguments are optional flags and the size of the data being declared as a global,
which will have initial value all zeros unless a <code>DATA</code> directive
has initialized it.
The <code>GLOBL</code> directive must follow any corresponding <code>DATA</code> directives.
</p>
<p>
For example,
</p>
<pre>
DATA divtab<>+0x00(SB)/4, $0xf4f8fcff
DATA divtab<>+0x04(SB)/4, $0xe6eaedf0
...
DATA divtab<>+0x3c(SB)/4, $0x81828384
GLOBL divtab<>(SB), RODATA, $64
GLOBL runtime·tlsoffset(SB), NOPTR, $4
</pre>
<p>
declares and initializes <code>divtab<></code>, a read-only 64-byte table of 4-byte integer values,
and declares <code>runtime·tlsoffset</code>, a 4-byte, implicitly zeroed variable that
contains no pointers.
</p>
<p>
There may be one or two arguments to the directives.
If there are two, the first is a bit mask of flags,
which can be written as numeric expressions, added or or-ed together,
or can be set symbolically for easier absorption by a human.
Their values, defined in the standard <code>#include</code> file <code>textflag.h</code>, are:
</p>
<ul>
<li>
<code>NOPROF</code> = 1
<br>
(For <code>TEXT</code> items.)
Don't profile the marked function. This flag is deprecated.
</li>
<li>
<code>DUPOK</code> = 2
<br>
It is legal to have multiple instances of this symbol in a single binary.
The linker will choose one of the duplicates to use.
</li>
<li>
<code>NOSPLIT</code> = 4
<br>
(For <code>TEXT</code> items.)
Don't insert the preamble to check if the stack must be split.
The frame for the routine, plus anything it calls, must fit in the
spare space at the top of the stack segment.
Used to protect routines such as the stack splitting code itself.
</li>
<li>
<code>RODATA</code> = 8
<br>
(For <code>DATA</code> and <code>GLOBL</code> items.)
Put this data in a read-only section.
</li>
<li>
<code>NOPTR</code> = 16
<br>
(For <code>DATA</code> and <code>GLOBL</code> items.)
This data contains no pointers and therefore does not need to be
scanned by the garbage collector.
</li>
<li>
<code>WRAPPER</code> = 32
<br>
(For <code>TEXT</code> items.)
This is a wrapper function and should not count as disabling <code>recover</code>.
</li>
<li>
<code>NEEDCTXT</code> = 64
<br>
(For <code>TEXT</code> items.)
This function is a closure so it uses its incoming context register.
</li>
<li>
<code>LOCAL</code> = 128
<br>
This symbol is local to the dynamic shared object.
</li>
<li>
<code>TLSBSS</code> = 256
<br>
(For <code>DATA</code> and <code>GLOBL</code> items.)
Put this data in thread local storage.
</li>
<li>
<code>NOFRAME</code> = 512
<br>
(For <code>TEXT</code> items.)
Do not insert instructions to allocate a stack frame and save/restore the return
address, even if this is not a leaf function.
Only valid on functions that declare a frame size of 0.
</li>
<li>
<code>TOPFRAME</code> = 2048
<br>
(For <code>TEXT</code> items.)
Function is the top of the call stack. Traceback should stop at this function.
</li>
</ul>
<h3 id="data-offsets">Interacting with Go types and constants</h3>
<p>
If a package has any .s files, then <code>go build</code> will direct
the compiler to emit a special header called <code>go_asm.h</code>,
which the .s files can then <code>#include</code>.
The file contains symbolic <code>#define</code> constants for the
offsets of Go struct fields, the sizes of Go struct types, and most
Go <code>const</code> declarations defined in the current package.
Go assembly should avoid making assumptions about the layout of Go
types and instead use these constants.
This improves the readability of assembly code, and keeps it robust to
changes in data layout either in the Go type definitions or in the
layout rules used by the Go compiler.
</p>
<p>
Constants are of the form <code>const_<i>name</i></code>.
For example, given the Go declaration <code>const bufSize =
1024</code>, assembly code can refer to the value of this constant
as <code>const_bufSize</code>.
</p>
<p>
Field offsets are of the form <code><i>type</i>_<i>field</i></code>.
Struct sizes are of the form <code><i>type</i>__size</code>.
For example, consider the following Go definition:
</p>
<pre>
type reader struct {
buf [bufSize]byte
r int
}
</pre>
<p>
Assembly can refer to the size of this struct
as <code>reader__size</code> and the offsets of the two fields
as <code>reader_buf</code> and <code>reader_r</code>.
Hence, if register <code>R1</code> contains a pointer to
a <code>reader</code>, assembly can reference the <code>r</code> field
as <code>reader_r(R1)</code>.
</p>
<p>
If any of these <code>#define</code> names are ambiguous (for example,
a struct with a <code>_size</code> field), <code>#include
"go_asm.h"</code> will fail with a "redefinition of macro" error.
</p>
<h3 id="runtime">Runtime Coordination</h3>
<p>
For garbage collection to run correctly, the runtime must know the
location of pointers in all global data and in most stack frames.
The Go compiler emits this information when compiling Go source files,
but assembly programs must define it explicitly.
</p>
<p>
A data symbol marked with the <code>NOPTR</code> flag (see above)
is treated as containing no pointers to runtime-allocated data.
A data symbol with the <code>RODATA</code> flag
is allocated in read-only memory and is therefore treated
as implicitly marked <code>NOPTR</code>.
A data symbol with a total size smaller than a pointer
is also treated as implicitly marked <code>NOPTR</code>.
It is not possible to define a symbol containing pointers in an assembly source file;
such a symbol must be defined in a Go source file instead.
Assembly source can still refer to the symbol by name
even without <code>DATA</code> and <code>GLOBL</code> directives.
A good general rule of thumb is to define all non-<code>RODATA</code>
symbols in Go instead of in assembly.
</p>
<p>
Each function also needs annotations giving the location of
live pointers in its arguments, results, and local stack frame.
For an assembly function with no pointer results and
either no local stack frame or no function calls,
the only requirement is to define a Go prototype for the function
in a Go source file in the same package. The name of the assembly
function must not contain the package name component (for example,
function <code>Syscall</code> in package <code>syscall</code> should
use the name <code>·Syscall</code> instead of the equivalent name
<code>syscall·Syscall</code> in its <code>TEXT</code> directive).
For more complex situations, explicit annotation is needed.
These annotations use pseudo-instructions defined in the standard
<code>#include</code> file <code>funcdata.h</code>.
</p>
<p>
If a function has no arguments and no results,
the pointer information can be omitted.
This is indicated by an argument size annotation of <code>$<i>n</i>-0</code>
on the <code>TEXT</code> instruction.
Otherwise, pointer information must be provided by
a Go prototype for the function in a Go source file,
even for assembly functions not called directly from Go.
(The prototype will also let <code>go</code> <code>vet</code> check the argument references.)
At the start of the function, the arguments are assumed
to be initialized but the results are assumed uninitialized.
If the results will hold live pointers during a call instruction,
the function should start by zeroing the results and then
executing the pseudo-instruction <code>GO_RESULTS_INITIALIZED</code>.
This instruction records that the results are now initialized
and should be scanned during stack movement and garbage collection.
It is typically easier to arrange that assembly functions do not
return pointers or do not contain call instructions;
no assembly functions in the standard library use
<code>GO_RESULTS_INITIALIZED</code>.
</p>
<p>
If a function has no local stack frame,
the pointer information can be omitted.
This is indicated by a local frame size annotation of <code>$0-<i>n</i></code>
on the <code>TEXT</code> instruction.
The pointer information can also be omitted if the
function contains no call instructions.
Otherwise, the local stack frame must not contain pointers,
and the assembly must confirm this fact by executing the
pseudo-instruction <code>NO_LOCAL_POINTERS</code>.
Because stack resizing is implemented by moving the stack,
the stack pointer may change during any function call:
even pointers to stack data must not be kept in local variables.
</p>
<p>
Assembly functions should always be given Go prototypes,
both to provide pointer information for the arguments and results
and to let <code>go</code> <code>vet</code> check that
the offsets being used to access them are correct.
</p>
<h2 id="architectures">Architecture-specific details</h2>
<p>
It is impractical to list all the instructions and other details for each machine.
To see what instructions are defined for a given machine, say ARM,
look in the source for the <code>obj</code> support library for
that architecture, located in the directory <code>src/cmd/internal/obj/arm</code>.
In that directory is a file <code>a.out.go</code>; it contains
a long list of constants starting with <code>A</code>, like this:
</p>
<pre>
const (
AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
AEOR
ASUB
ARSB
AADD
...
</pre>
<p>
This is the list of instructions and their spellings as known to the assembler and linker for that architecture.
Each instruction begins with an initial capital <code>A</code> in this list, so <code>AAND</code>
represents the bitwise and instruction,
<code>AND</code> (without the leading <code>A</code>),
and is written in assembly source as <code>AND</code>.
The enumeration is mostly in alphabetical order.
(The architecture-independent <code>AXXX</code>, defined in the
<code>cmd/internal/obj</code> package,
represents an invalid instruction).
The sequence of the <code>A</code> names has nothing to do with the actual
encoding of the machine instructions.
The <code>cmd/internal/obj</code> package takes care of that detail.
</p>
<p>
The instructions for both the 386 and AMD64 architectures are listed in
<code>cmd/internal/obj/x86/a.out.go</code>.
</p>
<p>
The architectures share syntax for common addressing modes such as
<code>(R1)</code> (register indirect),
<code>4(R1)</code> (register indirect with offset), and
<code>$foo(SB)</code> (absolute address).
The assembler also supports some (not necessarily all) addressing modes
specific to each architecture.
The sections below list these.
</p>
<p>
One detail evident in the examples from the previous sections is that data in the instructions flows from left to right:
<code>MOVQ</code> <code>$0,</code> <code>CX</code> clears <code>CX</code>.
This rule applies even on architectures where the conventional notation uses the opposite direction.
</p>
<p>
Here follow some descriptions of key Go-specific details for the supported architectures.
</p>
<h3 id="x86">32-bit Intel 386</h3>
<p>
The runtime pointer to the <code>g</code> structure is maintained
through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
In the runtime package, assembly code can include <code>go_tls.h</code>, which defines
an OS- and architecture-dependent macro <code>get_tls</code> for accessing this register.
The <code>get_tls</code> macro takes one argument, which is the register to load the
<code>g</code> pointer into.
</p>
<p>
For example, the sequence to load <code>g</code> and <code>m</code>
using <code>CX</code> looks like this:
</p>
<pre>
#include "go_tls.h"
#include "go_asm.h"
...
get_tls(CX)
MOVL g(CX), AX // Move g into AX.
MOVL g_m(AX), BX // Move g.m into BX.
</pre>
<p>
The <code>get_tls</code> macro is also defined on <a href="#amd64">amd64</a>.
</p>
<p>
Addressing modes:
</p>
<ul>
<li>
<code>(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code>.
</li>
<li>
<code>64(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code> plus 64.
These modes accept only 1, 2, 4, and 8 as scale factors.
</li>
</ul>
<p>
When using the compiler and assembler's
<code>-dynlink</code> or <code>-shared</code> modes,
any load or store of a fixed memory location such as a global variable
must be assumed to overwrite <code>CX</code>.
Therefore, to be safe for use with these modes,
assembly sources should typically avoid CX except between memory references.
</p>
<h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>
<p>
The two architectures behave largely the same at the assembler level.
Assembly code to access the <code>m</code> and <code>g</code>
pointers on the 64-bit version is the same as on the 32-bit 386,
except it uses <code>MOVQ</code> rather than <code>MOVL</code>:
</p>
<pre>
get_tls(CX)
MOVQ g(CX), AX // Move g into AX.
MOVQ g_m(AX), BX // Move g.m into BX.
</pre>
<p>
Register <code>BP</code> is callee-save.
The assembler automatically inserts <code>BP</code> save/restore when frame size is larger than zero.
Using <code>BP</code> as a general purpose register is allowed,
however it can interfere with sampling-based profiling.
</p>
<h3 id="arm">ARM</h3>
<p>
The registers <code>R10</code> and <code>R11</code>
are reserved by the compiler and linker.
</p>
<p>
<code>R10</code> points to the <code>g</code> (goroutine) structure.
Within assembler source code, this pointer must be referred to as <code>g</code>;
the name <code>R10</code> is not recognized.
</p>
<p>
To make it easier for people and compilers to write assembly, the ARM linker
allows general addressing forms and pseudo-operations like <code>DIV</code> or <code>MOD</code>
that may not be expressible using a single hardware instruction.
It implements these forms as multiple instructions, often using the <code>R11</code> register
to hold temporary values.
Hand-written assembly can use <code>R11</code>, but doing so requires
being sure that the linker is not also using it to implement any of the other
instructions in the function.
</p>
<p>
When defining a <code>TEXT</code>, specifying frame size <code>$-4</code>
tells the linker that this is a leaf function that does not need to save <code>LR</code> on entry.
</p>
<p>
The name <code>SP</code> always refers to the virtual stack pointer described earlier.
For the hardware register, use <code>R13</code>.
</p>
<p>
Condition code syntax is to append a period and the one- or two-letter code to the instruction,
as in <code>MOVW.EQ</code>.
Multiple codes may be appended: <code>MOVM.IA.W</code>.
The order of the code modifiers is irrelevant.
</p>
<p>
Addressing modes:
</p>
<ul>
<li>
<code>R0->16</code>
<br>
<code>R0>>16</code>
<br>
<code>R0<<16</code>
<br>
<code>R0@>16</code>:
For <code><<</code>, left shift <code>R0</code> by 16 bits.
The other codes are <code>-></code> (arithmetic right shift),
<code>>></code> (logical right shift), and
<code>@></code> (rotate right).
</li>
<li>
<code>R0->R1</code>
<br>
<code>R0>>R1</code>
<br>
<code>R0<<R1</code>
<br>
<code>R0@>R1</code>:
For <code><<</code>, left shift <code>R0</code> by the count in <code>R1</code>.
The other codes are <code>-></code> (arithmetic right shift),
<code>>></code> (logical right shift), and
<code>@></code> (rotate right).
</li>
<li>
<code>[R0,g,R12-R15]</code>: For multi-register instructions, the set comprising
<code>R0</code>, <code>g</code>, and <code>R12</code> through <code>R15</code> inclusive.
</li>
<li>
<code>(R5, R6)</code>: Destination register pair.
</li>
</ul>
<h3 id="arm64">ARM64</h3>
<p>
The ARM64 port is in an experimental state.
</p>
<p>
<code>R18</code> is the "platform register", reserved on the Apple platform.
To prevent accidental misuse, the register is named <code>R18_PLATFORM</code>.
<code>R27</code> and <code>R28</code> are reserved by the compiler and linker.
<code>R29</code> is the frame pointer.
<code>R30</code> is the link register.
</p>
<p>
Instruction modifiers are appended to the instruction following a period.
The only modifiers are <code>P</code> (postincrement) and <code>W</code>
(preincrement):
<code>MOVW.P</code>, <code>MOVW.W</code>
</p>
<p>
Addressing modes:
</p>
<ul>
<li>
<code>R0->16</code>
<br>
<code>R0>>16</code>
<br>
<code>R0<<16</code>
<br>
<code>R0@>16</code>:
These are the same as on the 32-bit ARM.
</li>
<li>
<code>$(8<<12)</code>:
Left shift the immediate value <code>8</code> by <code>12</code> bits.
</li>
<li>
<code>8(R0)</code>:
Add the value of <code>R0</code> and <code>8</code>.
</li>
<li>
<code>(R2)(R0)</code>:
The location at <code>R0</code> plus <code>R2</code>.
</li>
<li>
<code>R0.UXTB</code>
<br>
<code>R0.UXTB<<imm</code>:
<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>.
<code>R0.UXTB<<imm</code>: left shift the result of <code>R0.UXTB</code> by <code>imm</code> bits.
The <code>imm</code> value can be 0, 1, 2, 3, or 4.
The other extensions include <code>UXTH</code> (16-bit), <code>UXTW</code> (32-bit), and <code>UXTX</code> (64-bit).
</li>
<li>
<code>R0.SXTB</code>
<br>
<code>R0.SXTB<<imm</code>:
<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>.
<code>R0.SXTB<<imm</code>: left shift the result of <code>R0.SXTB</code> by <code>imm</code> bits.
The <code>imm</code> value can be 0, 1, 2, 3, or 4.
The other extensions include <code>SXTH</code> (16-bit), <code>SXTW</code> (32-bit), and <code>SXTX</code> (64-bit).
</li>
<li>
<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>.
</li>
</ul>
<p>
Reference: <a href="/pkg/cmd/internal/obj/arm64">Go ARM64 Assembly Instructions Reference Manual</a>
</p>
<h3 id="ppc64">PPC64</h3>
<p>
This assembler is used by GOARCH values ppc64 and ppc64le.
</p>
<p>
Reference: <a href="/pkg/cmd/internal/obj/ppc64">Go PPC64 Assembly Instructions Reference Manual</a>
</p>
</ul>
<h3 id="s390x">IBM z/Architecture, a.k.a. s390x</h3>
<p>
The registers <code>R10</code> and <code>R11</code> are reserved.
The assembler uses them to hold temporary values when assembling some instructions.
</p>
<p>
<code>R13</code> points to the <code>g</code> (goroutine) structure.
This register must be referred to as <code>g</code>; the name <code>R13</code> is not recognized.
</p>
<p>
<code>R15</code> points to the stack frame and should typically only be accessed using the
virtual registers <code>SP</code> and <code>FP</code>.
</p>
<p>
Load- and store-multiple instructions operate on a range of registers.
The range of registers is specified by a start register and an end register.
For example, <code>LMG</code> <code>(R9),</code> <code>R5,</code> <code>R7</code> would load
<code>R5</code>, <code>R6</code> and <code>R7</code> with the 64-bit values at
<code>0(R9)</code>, <code>8(R9)</code> and <code>16(R9)</code> respectively.
</p>
<p>
Storage-and-storage instructions such as <code>MVC</code> and <code>XC</code> are written
with the length as the first argument.
For example, <code>XC</code> <code>$8,</code> <code>(R9),</code> <code>(R9)</code> would clear
eight bytes at the address specified in <code>R9</code>.
</p>
<p>
If a vector instruction takes a length or an index as an argument then it will be the
first argument.
For example, <code>VLEIF</code> <code>$1,</code> <code>$16,</code> <code>V2</code> will load
the value sixteen into index one of <code>V2</code>.
Care should be taken when using vector instructions to ensure that they are available at
runtime.
To use vector instructions a machine must have both the vector facility (bit 129 in the
facility list) and kernel support.
Without kernel support a vector instruction will have no effect (it will be equivalent
to a <code>NOP</code> instruction).
</p>
<p>
Addressing modes:
</p>
<ul>
<li>
<code>(R5)(R6*1)</code>: The location at <code>R5</code> plus <code>R6</code>.
It is a scaled mode as on the x86, but the only scale allowed is <code>1</code>.
</li>
</ul>
<h3 id="mips">MIPS, MIPS64</h3>
<p>
General purpose registers are named <code>R0</code> through <code>R31</code>,
floating point registers are <code>F0</code> through <code>F31</code>.
</p>
<p>
<code>R30</code> is reserved to point to <code>g</code>.
<code>R23</code> is used as a temporary register.
</p>
<p>
In a <code>TEXT</code> directive, the frame size <code>$-4</code> for MIPS or
<code>$-8</code> for MIPS64 instructs the linker not to save <code>LR</code>.
</p>
<p>
<code>SP</code> refers to the virtual stack pointer.
For the hardware register, use <code>R29</code>.
</p>
<p>
Addressing modes:
</p>
<ul>
<li>
<code>16(R1)</code>: The location at <code>R1</code> plus 16.
</li>
<li>
<code>(R1)</code>: Alias for <code>0(R1)</code>.
</li>
</ul>
<p>
The value of <code>GOMIPS</code> environment variable (<code>hardfloat</code> or
<code>softfloat</code>) is made available to assembly code by predefining either
<code>GOMIPS_hardfloat</code> or <code>GOMIPS_softfloat</code>.
</p>
<p>
The value of <code>GOMIPS64</code> environment variable (<code>hardfloat</code> or
<code>softfloat</code>) is made available to assembly code by predefining either
<code>GOMIPS64_hardfloat</code> or <code>GOMIPS64_softfloat</code>.
</p>
<h3 id="unsupported_opcodes">Unsupported opcodes</h3>
<p>
The assemblers are designed to support the compiler so not all hardware instructions
are defined for all architectures: if the compiler doesn't generate it, it might not be there.
If you need to use a missing instruction, there are two ways to proceed.
One is to update the assembler to support that instruction, which is straightforward
but only worthwhile if it's likely the instruction will be used again.
Instead, for simple one-off cases, it's possible to use the <code>BYTE</code>
and <code>WORD</code> directives
to lay down explicit data into the instruction stream within a <code>TEXT</code>.
Here's how the 386 runtime defines the 64-bit atomic load function.
</p>
<pre>
// uint64 atomicload64(uint64 volatile* addr);
// so actually
// void atomicload64(uint64 *res, uint64 volatile *addr);
TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
MOVL ptr+0(FP), AX
TESTL $7, AX
JZ 2(PC)
MOVL 0, AX // crash with nil ptr deref
LEAL ret_lo+4(FP), BX
// MOVQ (%EAX), %MM0
BYTE $0x0f; BYTE $0x6f; BYTE $0x00
// MOVQ %MM0, 0(%EBX)
BYTE $0x0f; BYTE $0x7f; BYTE $0x03
// EMMS
BYTE $0x0F; BYTE $0x77
RET
</pre>
|