Go no está vinculando mi ensamblaje: función externa indefinida

82

Estoy tratando de escribir algo de SIMD principalmente con fines de aprendizaje. Sé que Go puede vincular el ensamblaje, pero no puedo hacer que funcione correctamente.

Este es el ejemplo más mínimo que puedo hacer (multiplicación de vectores por elementos):

vec_amd64.s (nota: el archivo real tiene una línea de espacio en blanco debajo, RETya que de lo contrario causa errores)

// func mul(v1, v2 Vec4) Vec4
TEXT .mul(SB),4,$0-48
    MOVUPS v1+0(FP),  X0
    MOVUPS v2+16(FP), X1
    MULPS  X1, X0
    // also tried ret+32 since I've seen some places do that
    MOVUPS X0, toReturn+32(FP)
    RET

vec.go

package simd

type Vec4 [4]float32

func (v1 Vec4) Mul(v2 Vec4) Vec4 {
    return Vec4{v1[0] * v2[0], v1[1] * v2[1], v1[2] * v2[2], v1[3] * v2[3]}
}

func mul(v1, v2 Vec4) Vec4

simd_test.go

package simd

import (
    "testing"
)

func TestMul(t *testing.T) {
    v1 := Vec4{1, 2, 3, 4}
    v2 := Vec4{5, 6, 7, 8}

    res := v1.Mul(v2)
    res2 := mul(v1, v2)

    // Placeholder until I get it to compile
    if res != res2 {
        t.Fatalf("Expected %v; got %v", res, res2)
    }
}

Cuando intento ejecutar go testme sale el error:

# testmain
simd.TestMul: call to external function simd.mul
simd.TestMul: undefined: simd.mul

El go envcomando informa que my GOHOSTARCHto be amd64y mi versión Go es 1.3. Para confirmar que no era la arquitectura la que causaba el problema, encontré otro paquete que usa ensamblaje y eliminé todos los archivos de ensamblaje excepto _amd64.suno y sus pruebas funcionaron bien.

También intenté cambiarlo a un identificador exportado en caso de que eso estuviera causando rarezas, pero sin dados. Creo que seguí bastante de cerca la plantilla en paquetes como math/big, así que espero que sea algo simple y obvio que me falta.

Sé que Go al menos está intentando usar el ensamblaje porque si introduzco un error de sintaxis en el archivo .s, la herramienta de compilación se quejará al respecto.

Editar:

Para ser claros, go buildse compilará limpiamente, pero go testhace que aparezca el error.

LinealZoetropo
fuente
go buildterminado limpiamente, go testfalla.
LinearZoetrope
1
¿Cómo se compila? No respondiste la pregunta.
fuz
1
¿Qué comandos ingresó desde qué directorio en relación con sus archivos de origen? Lo compilo usando la goherramienta de construcción. es muy vago. Podría significar cualquier cosa.
fuz
1
Hay una diferencia entre llamar a go buildy go build foo.go, etc. También es posible que tenga configuraciones extravagantes en su $GOPATH, etc. Cuanto más escriba sobre lo que hizo exactamente , más fácil será ayudarlo. Lo mejor es publicar transcripciones de sesiones de shell en lugar de prosa.
fuz
12
El lenguaje Go realmente parece tener un fetiche por el carácter de punto medio. Relacionado: ¿ barras y puntos en nombres de funciones y prototipos?
Cody Gray

Respuestas:

96

Estás usando el punto incorrecto. en vez de

TEXT .mul(SB),4,$0-48

escribir

TEXT ·mul(SB),4,$0-48

y todo funciona bien.

fuz
fuente
11
Bueno, ESO fue sutil, no me di cuenta de que era un punto medio. Gracias.
LinearZoetrope
13
¿Cómo escribe la gente eso en un teclado QWERTY americano? ¿O no es este un caso de uso común, en el que podría simplemente buscar en Google el símbolo según sea necesario?
Seiyria
9
Como este . Los sistemas operativos que no apestan (es decir, no Windows) asignan capas no utilizadas del diseño QWERTY para que se puedan ingresar caracteres como el interpunto.
fuz
7
@FUZxxl FYI Alt-0183 (usando el teclado numérico) todavía funciona para Windows. No es tan agradable y suele ser difícil en las computadoras portátiles, pero funciona.
Intermernet
4
En Linux (Ubuntu, al menos) si tiene la clave de<compose> ^ .·
redacción