Location>code7788 >text

Go plan9 assembly: handwritten assembly

Popularity:229 ℃/2024-09-01 17:17:09

0. Preface

existGo plan9 compilation: Getting through the application to the ground floor The article describes the conversion from an application program to assembly instructions. In this article, we will combine assembly and Go program implementations to handwrite basic assembly instructions to deepen our understanding of Go plan9 assembly.

1. Handwriting compilation

1.1 Global variables

First write a function that prints an integer variable as follows:

// ex1/
package main

var a = 9527

func main() {
	print(a)
}

utilizationgo tool compile -S -N -l Assembly code for the output program:

# go tool compile -S -N -l  
 STEXT size=50 args=0x0 locals=0x10 funcid=0x0 align=0x0
    ...
 SNOPTRDATA size=8
        0x0000 37 25 00 00 00 00 00 00                          7%......

Omitted here compilation output, focusing on the This variable. The output of the denotes the identifier of the compilation.SNOPTRDATA Indicates that the variable is pointer-excluded, which is for the garbage collector, which skips the recycling of this variable when it is scanned.size=8 is the size of this variable. The focus is on the0x0000 37 25 00 00 00 00 00 00This is the arrangement of 9527 in memory, and 0x2537 is the hexadecimal representation of 9527.

1.1.1 Assembly Implementation of Global Variables

We can write assembly to realize the output of global variables. Note that this article is not a tutorial on assembly, and will not go into too much detail about the syntax of Go plan9 assembly, you can read Cao Da'sAdvanced Programming in Go: Assembly Language(That was really well written!) .

First of all, the Go plan9 assembly is required to work with Go files. Here

// ex1/
package main

import (
	"ex1/pkg"
)

func main() {
	println()
}

existmain Print the Id variable of the pkg package in the package.

// ex1/pkg/
package pkg

var Id int

We can write assembly to implement the definition of the Id variable as follows:

// ex1/pkg/pkg_amd64.s
#include ""

GLOBL ·Id(SB),NOPTR,$8

DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
DATA ·Id+2(SB)/1,$0x00
DATA ·Id+3(SB)/1,$0x00
DATA ·Id+4(SB)/1,$0x00
DATA ·Id+5(SB)/1,$0x00
DATA ·Id+6(SB)/1,$0x00
DATA ·Id+7(SB)/1,$0x00

NOPTR denotes that the variable Id does not include the pointer, and $8 denotes that the variable occupies 8 bytes.DATA Declare that the variable is stored in memorydata segments, the segments in memory are as follows.

image

Run the above program:

# go run 
9527

The output variable 9527 has the following memory distribution:

image

From the variable memory distribution, we can see that only 2 bytes of the int (8 bytes) memory we requested are actually used, and the other bytes are 0. We can save space by requesting 2 bytes of Id as follows. The other bytes are 0. We can save space by requesting 2 bytes for Id as follows:

// ex1/pkg/
package pkg

var Id int16


// ex1/pkg/pkg_amd64.s
#include ""

GLOBL ·Id(SB),NOPTR,$8

DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25

Output:

# go run  
9527

rewritepkg_amd64.s

#include ""

GLOBL ·Id(SB),NOPTR,$2

DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
DATA ·Id+2(SB)/1,$0x20

Output:

# go run  
9527

exist0x2537 1 byte above0x20 It will not be addressed by the CPU, but the CPU will read 2 bytes of the Id variable from memory according to the variable declaration and send it to the registers for processing.

1.2 Strings

Combines Go and assembly to print strings:

// ex2/
package main

import (
	"ex2/pkg"
	"fmt"
)

func main() {
	()
}

// ex2/pkg/
package pkg

var Name string

string (computer science)Name is declared in the pkg package, using the assembly definition variableName

// ex2/pkg/pkg_amd64.s
#include ""

GLOBL string<>(SB),NOPTR,$16
DATA string<>+0(SB)/8,$"Hello Wo"
DATA string<>+8(SB)/8,$"rld!"

GLOBL ·Name(SB),NOPTR|RODATA,$16
DATA ·Name+0(SB)/8,$string<>(SB)
DATA ·Name+8(SB)/8,$12

Here the string variable is actually a 16-byte structure including length and pointer. The variable is defined in:

GLOBL ·Name(SB),NOPTR|RODATA,$16
DATA ·Name+0(SB)/8,$string<>(SB)
DATA ·Name+8(SB)/8,$12

The first 8 bytes point to the memory address where the actual string is stored, and the last 8 bytes are the length of the string. The real string is stored in a data segment in memory. Herestring<> denote the variablestring No variables can be exported, otherwise external Go programs can access the string variables directly.

Draw the memory distribution as follows:

image

2. Summary

We can continue with the assembly implementation of functions along the above lines, but the point of this article is to understand how assembly is written, not to actually write it. We have two simple global variables and strings through the compilation of the example, to understand the assembly code to write. In the actual application will almost never write themselves, the emphasis is on understanding. For more on assembly implementation you can refer to Cao Da'sGo Advanced Programming