четверг, 27 мая 2021 г.

Краткое руководство по ассемблеру Go

Эта серия постов представляет собой краткое описание необычной формы языка ассемблера, используемого компилятором gc Go.

Ассемблер основан на стиле ввода ассемблеров Plan 9.

Самое важное, что нужно знать об ассемблере Go, - это то, что он не является прямым представлением базовой машины. Некоторые детали точно соответствуют машине, а некоторые нет. Это связано с тем, что пакет компилятора не требует передачи ассемблера в обычном конвейере. Вместо этого компилятор работает с полуабстрактным набором инструкций, и выбор инструкций происходит частично после генерации кода. Ассемблер работает с полуабстрактной формой, поэтому, когда вы видите такую инструкцию, как MOV, то, что фактически генерирует инструментальная цепочка для этой операции, может быть вовсе не инструкцией перемещения, возможно, очисткой или загрузкой. Или он может точно соответствовать машинной инструкции с таким именем. В общем, машинно-зависимые операции имеют тенденцию появляться сами по себе, в то время как более общие концепции, такие как перемещение памяти, вызов и возврат подпрограмм, являются более абстрактными. Детали меняются в зависимости от архитектуры, и возможны неточности; ситуация не совсем ясна.

Программа на ассемблере - это способ проанализировать описание этого полуабстрактного набора инструкций и превратить его в инструкции для ввода компоновщику (linker). Если вы хотите увидеть, как выглядят инструкции в сборке для данной архитектуры, скажем amd64, есть много примеров в исходных кодах стандартной библиотеки, в таких пакетах, как runtime и math/big. Вы также можете проверить, что компилятор испускает как ассемблерный код (фактический результат может отличаться от того, что вы видите здесь):

$ 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
...

Директивы FUNCDATA и PCDATA содержат информацию для использования сборщиком мусора; они вводятся компилятором.

Чтобы увидеть, что помещается в двоичный файл после компоновки, используйте go tool objdump:

$ 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)


Читайте также:


Комментариев нет:

Отправить комментарий