Interpretation and use of golang assembly command

Time:2021-12-31

We can easily convert a golang program into assembly language.

For example, I wrote a main go:


package main


func g(p int) int {
     return p+1;
}

func main() {
     c := g(4) + 1
     _ = c
}

Use command:


GOOS=linux GOARCH=386 go tool compile -S main.go >> main.S

We get main S is main Go assembly version.


"".g t=1 size=16 value=0 args=0x10 locals=0x0
     0x0000 00000 (main.go:4)     TEXT     "".g(SB), $0-16
     0x0000 00000 (main.go:4)     NOP
     0x0000 00000 (main.go:4)     NOP
     0x0000 00000 (main.go:4)     FUNCDATA     $0, gclocals·23e8278e2b69a3a75fa59b23c49ed6ad(SB)
     0x0000 00000 (main.go:4)     FUNCDATA     $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0000 00000 (main.go:5)     MOVQ     "".p+8(FP), BX
     0x0005 00005 (main.go:5)     INCQ     BX
     0x0008 00008 (main.go:5)     MOVQ     BX, "".~r1+16(FP)
     0x000d 00013 (main.go:5)     RET
     0x0000 48 8b 5c 24 08 48 ff c3 48 89 5c 24 10 c3        H.$.H..H.$..
"".main t=1 size=16 value=0 args=0x0 locals=0x0
     0x0000 00000 (main.go:8)     TEXT     "".main(SB), $0-0
     0x0000 00000 (main.go:8)     NOP
     0x0000 00000 (main.go:8)     NOP
     0x0000 00000 (main.go:8)     FUNCDATA     $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0000 00000 (main.go:8)     FUNCDATA     $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0000 00000 (main.go:9)     MOVQ     $4, BX
     0x0007 00007 (main.go:9)     INCQ     BX
     0x000a 00010 (main.go:9)     INCQ     BX
     0x000d 00013 (main.go:11)     RET
     0x0000 48 c7 c3 04 00 00 00 48 ff c3 48 ff c3 c3        H......H..H...
"".init t=1 size=80 value=0 args=0x0 locals=0x0
     0x0000 00000 (main.go:11)     TEXT     "".init(SB), $0-0
     0x0000 00000 (main.go:11)     MOVQ     (TLS), CX
     0x0009 00009 (main.go:11)     CMPQ     SP, 16(CX)
     0x000d 00013 (main.go:11)     JLS     62
     0x000f 00015 (main.go:11)     NOP
     0x000f 00015 (main.go:11)     NOP
     0x000f 00015 (main.go:11)     FUNCDATA     $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x000f 00015 (main.go:11)     FUNCDATA     $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x000f 00015 (main.go:11)     MOVBQZX     "".initdone·(SB), BX
     0x0016 00022 (main.go:11)     CMPB     BL, $0
     0x0019 00025 (main.go:11)     JEQ     47
     0x001b 00027 (main.go:11)     MOVBQZX     "".initdone·(SB), BX
     0x0022 00034 (main.go:11)     CMPB     BL, $2
     0x0025 00037 (main.go:11)     JNE     40
     0x0027 00039 (main.go:11)     RET
     0x0028 00040 (main.go:11)     PCDATA     $0, $0
     0x0028 00040 (main.go:11)     CALL     runtime.throwinit(SB)
     0x002d 00045 (main.go:11)     UNDEF
     0x002f 00047 (main.go:11)     MOVB     $1, "".initdone·(SB)
     0x0036 00054 (main.go:11)     MOVB     $2, "".initdone·(SB)
     0x003d 00061 (main.go:11)     RET
     0x003e 00062 (main.go:11)     CALL     runtime.morestack_noctxt(SB)
     0x0043 00067 (main.go:11)     JMP     0

First of all, this program defines the function according to text, which is divided into three parts


0x0000 00000 (main.go:4)     TEXT     "".g(SB), $0-16 
0x0000 00000 (main.go:8)     TEXT     "".main(SB), $0-0
0x0000 00000 (main.go:11)     TEXT     "".init(SB), $0-0

This “” Represents the namespace of this function.
G (sb) here is a pseudo register of sb. The full name is not static base, which represents g this function address, $0 in $0-16 represents the sum of local variable bytes, and 0 represents that there is no local variable- 16 means that the length of 16 is vacated based on the address of 0 as the incoming and return objects. This is how golang implements multiple return values of functions. When defining functions, it opens up a certain space to store incoming and outgoing objects.

The NOP command is used as a placeholder and is provided to the compiler. You can ignore it.

Here is


 0x0000 00000 (main.go:4)     FUNCDATA     $0, gclocals·23e8278e2b69a3a75fa59b23c49ed6ad(SB)
     0x0000 00000 (main.go:4)     FUNCDATA     $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)

Funcdata here is the instruction provided by the golang compiler. There are no instruction sets in plan9 and x86. It is used to prompt the GC collection. Tips $0 and $1 are parameters for local function calls and need to be recycled.

Here is


  0x0000 00000 (main.go:5)     MOVQ     "".p+8(FP), BX
     0x0005 00005 (main.go:5)     INCQ     BX
     0x0008 00008 (main.go:5)     MOVQ     BX, "".~r1+16(FP)

Here is an FP register. FP is frame pointer, pointing to the bottom of the stack, and SP is pointing to the top of the stack. BX is a temporary register, so the above sentence represents saving the data (parameter P) at FP + 8 to BX. What does FP + 8 represent? According to the above figure, it represents parameters

INCQ is a self increasing algorithm. The number in BX is added by 1, and then the number in BX is stored in FP + 16, which represents the return value.
The following is RET, which returns directly.

Let’s look at main. We will find that there is no call g function in the main function. This is because the go assembler will turn some short functions into embedded functions to reduce function calls.

if

We add a judgment logic in main. The code is:


package main


func g(p int) int {
     return p+1;
}

func main() {
     c := g(4) + 1
     var d bool
     if (c > 4) {
          d = true
     } else {
          d = false
     }
     _ = d
     return
}

The corresponding main assembly is:


  0x0000 00000 (main.go:8)     TEXT     "".main(SB), $0-0
     0x0000 00000 (main.go:8)     NOP
     0x0000 00000 (main.go:8)     NOP
     0x0000 00000 (main.go:8)     FUNCDATA     $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0000 00000 (main.go:8)     FUNCDATA     $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0000 00000 (main.go:9)     MOVQ     $4, BX
     0x0007 00007 (main.go:9)     INCQ     BX
     0x000a 00010 (main.go:9)     INCQ     BX
     0x000d 00013 (main.go:11)     CMPQ     BX, $4
     0x0011 00017 (main.go:11)     JLE     27
     0x0013 00019 (main.go:12)     MOVQ     $1, AX
     0x001a 00026 (main.go:17)     RET
     0x001b 00027 (main.go:14)     MOVQ     $0, AX
     0x001d 00029 (main.go:17)     JMP     26

It can be seen that cmpq is used for comparison. JLE represents the result after CMP comparison. If BX is less than or equal to 4, skip to instruction 27, that is movq $0, ax. Assign ax to 0, that is false, otherwise assign it to 1, true

The JLE here is a conditional transfer instruction:http://baike.baidu.com/link?url=pdfEpBZ-c-owW0YJrAL71MUi1nIlEpBqljD3agfLtB5KrAaFembK6yKKUNycaSUWTTTyynKhNIfw2LXvGFx4euTIgyXQcVLz5HPxS4AO-kVT9wQxlL6_O-1ygTwfshEgas91S14FU3CRU7a1jImTSK

for

Change the procedure to:


package main


func g(p int) int {
     var sum int
     for i := 0; i < p; i++ {
          sum = sum + i
     }
     return sum
}

func main() {
     c := g(4) + 1
     _ = c
}

There is a for loop, and the generated assembly is:


0x0000 00000 (main.go:4)     TEXT     "".g(SB), $0-16
     0x0000 00000 (main.go:4)     NOP
     0x0000 00000 (main.go:4)     NOP
     0x0000 00000 (main.go:4)     MOVQ     "".p+8(FP), DX
     0x0005 00005 (main.go:4)     FUNCDATA     $0, gclocals·23e8278e2b69a3a75fa59b23c49ed6ad(SB)
     0x0005 00005 (main.go:4)     FUNCDATA     $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
     0x0005 00005 (main.go:5)     MOVQ     $0, CX
     0x0007 00007 (main.go:6)     MOVQ     $0, AX
     0x0009 00009 (main.go:6)     CMPQ     AX, DX
     0x000c 00012 (main.go:6)     JGE     $0, 25
     0x000e 00014 (main.go:7)     ADDQ     AX, CX
     0x0011 00017 (main.go:6)     INCQ     AX
     0x0014 00020 (main.go:6)     NOP
     0x0014 00020 (main.go:6)     CMPQ     AX, DX
     0x0017 00023 (main.go:6)     JLT     $0, 14
     0x0019 00025 (main.go:9)     MOVQ     CX, "".~r1+16(FP)
     0x001e 00030 (main.go:9)     RET

Ax stores the variable I, DX stores the parameter P, and CX stores the variable sum. The following commands:


0x0009 00009 (main.go:6)     CMPQ     AX, DX
     0x000c 00012 (main.go:6)     JGE     $0, 25
     0x000e 00014 (main.go:7)     ADDQ     AX, CX
     0x0011 00017 (main.go:6)     INCQ     AX
     0x0014 00020 (main.go:6)     NOP
     0x0014 00020 (main.go:6)     CMPQ     AX, DX
     0x0017 00023 (main.go:6)     JLT     $0, 14

In fact, CMP, jge and JLT are used to continuously control the cycle process.

This is the end of this article on the interpretation of golang assembly commands. For more information about golang assembly commands, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!

Recommended Today

Redis featured Q & A

Redis data type type brief introduction characteristic scene String (string) Binary security It can contain any data, such as JPG pictures or serialized objects. One key can store up to 512M It can be used to do the simplest data. It can cache a simple string or a JSON format string. The implementation of redis […]