Можно ли включить встроенную сборку в код Go? - PullRequest
37 голосов
/ 01 июня 2010

Можно ли включить встроенную сборку в код Go?

Ответы [ 5 ]

36 голосов
/ 30 июня 2011

Встроенная сборка не поддерживается, но вы можете связать код, написанный на ассемблере, через C, компилировать с помощью cgo и использовать import "C", как в gmp.go . В качестве альтернативы вы можете написать в стиле сборки, который напрямую совместим с Go, как в asm_linux_amd64.s , который требует, чтобы имена функций начинались с "·".

Или, вы можете использовать nasm и gccgo, мой любимый способ до сих пор. (Обратите внимание, что Nasm, похоже, не поддерживает функции, начинающиеся с "·").

Вот рабочий пример "Hello World":

hello.asm:

; Based on hello.asm from nasm

    SECTION .data       ; data section
msg:    db "Hello World",10 ; the string to print, 10=cr
len:    equ $-msg       ; "$" means "here"
                ; len is a value, not an address

    SECTION .text       ; code section

global go.main.hello        ; make label available to linker (Go)
go.main.hello:

    ; --- setup stack frame
    push rbp            ; save old base pointer
    mov rbp,rsp   ; use stack pointer as new base pointer

    ; --- print message
    mov edx,len     ; arg3, length of string to print
    mov ecx,msg     ; arg2, pointer to string
    mov ebx,1       ; arg1, where to write, screen
    mov eax,4       ; write sysout command to int 80 hex
    int 0x80        ; interrupt 80 hex, call kernel

    ; --- takedown stack frame
    mov rsp,rbp  ; use base pointer as new stack pointer
    pop rbp      ; get the old base pointer

    ; --- return
    mov rax,0       ; error code 0, normal, no error
    ret         ; return

main.go:

package main

func hello();

func main() {
    hello()
    hello()
}

И удобный Makefile:

main: main.go hello.o
    gccgo hello.o main.go -o main

hello.o: hello.asm
    nasm -f elf64 -o hello.o hello.asm

clean:
    rm -rf _obj *.o *~ *.6 *.gch a.out main

Я дважды вызываю hello() в main.go, просто чтобы проверить, правильно ли возвращается hello ().

Обратите внимание, что прямой вызов прерывания 80h не считается хорошим стилем в Linux, и вызов функций, написанных на языке C, является более "перспективным". Также обратите внимание, что это сборка специально для 64-битного Linux, и она не зависит от платформы ни в какой форме, ни в форме.

Я знаю, что это не прямой ответ на ваш вопрос, но это самый простой из известных мне способов использования ассемблера с Go, при отсутствии наложения. Если вам действительно нужно встраивание, можно написать скрипт, который извлекает встроенную сборку из исходных файлов и подготавливает ее так, как показано выше. Достаточно близко? :)

Быстрый пример для Go, C и Nasm: gonasm.tgz

Обновление: В более поздних версиях gccgo требуется флаг -g, и вместо "go.main.hello" нужен только "main.hello". Вот обновленный пример для Go, C и Yasm: goyasm.tgz

24 голосов
/ 01 июня 2010

На языке программирования Go нет средства для поддержки кода на языке встроенного ассемблера, и планов на это нет. Go поддерживает связь с подпрограммами, написанными на ассемблере и C . Есть экспериментальная функция, которая добавляет SWIG поддержку в Go.

17 голосов
/ 07 февраля 2013

Как оказалось, это возможно, см .: http://www.doxsey.net/blog/go-and-assembly.

13 голосов
/ 22 мая 2014

Нет, вы не можете, но легко обеспечить реализацию сборки только одной функции с помощью компилятора go. Для использования сборки не нужно использовать «Импорт C».

Взгляните на пример из математической библиотеки:

http://golang.org/src/pkg/math/abs.go: функция Abs объявлена ​​в этом файле go. (В этом файле также есть реализация abs in go, но она не экспортируется, так как имеет имя в нижнем регистре.)

package math

// Abs returns the absolute value of x.
//
// Special cases are:
//  Abs(±Inf) = +Inf
//  Abs(NaN) = NaN
func Abs(x float64) float64

Затем, в http://golang.org/src/pkg/math/abs_amd64.s, Abs реализован для 64-битной Intel в этом файле:

// func Abs(x float64) float64
TEXT ·Abs(SB),NOSPLIT,$0
    MOVQ   $(1<<63), BX
    MOVQ   BX, X0 // movsd $(-0.0), x0
    MOVSD  x+0(FP), X1
    ANDNPD X1, X0
    MOVSD  X0, ret+8(FP)
    RET
3 голосов
/ 11 января 2012

Оптимизация в стандартном компиляторе Go (то есть: 8g + 8l, а не gccgo) в основном работает с необработанными инструкциями в двоичной форме. В настоящее время компилятор не может (не реализовал) отличить сборку, сгенерированную компилятором, от встроенного кода сборки, предоставленного пользователем - это является основной причиной, по которой компилятор Go не допускает встроенную сборку , Другими словами, компилятор не поддерживает встроенную сборку из-за архитектуры компилятора .

Конечно, в самом языке Go нет ничего, что мешало бы другим реализациям языка Go (то есть другим компиляторам Go) поддерживать встроенную сборку. Встроенная сборка - это решение, зависящее от компилятора - оно не имеет ничего общего с самим языком Go.

В любом случае, встроенная сборка небезопасна, потому что она не может быть проверена на корректность системой типов Go. Кажется, лучше реализовать любую функцию, которая требует использования встроенной сборки на языке, подобном C, и вызывать функцию C из Go.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...