在汇编中调用Go函数

作者: 027f63d16800 | 来源:发表于2018-01-22 14:30 被阅读47次

这次我们来实现,在一个汇编函数中调用Go方法
先看一下我们的包结构:

+assembly
 -stub.go
    echo方法
    Hello方法声明
 -hello.s
    Hello方法实现
+main
 -main.go

我们先声明一个go方法:

func echo(msg string) int64{
    fmt.Println(msg)
    return int64(len(msg))
}

我们想要做的就是在汇编程序中调用这个方法。这个方法有一个 string 类型的参数和一个 int64 的返回值。
我们需要先来了解一下 string 的内存布局,不同于 Cstringgolangstring 是一个结构体:

type stringStruct struct {
    str unsafe.Pointer  //指定底层的byte数组
    len int             //字符串长度
}

如上注释,字符串的长度保存在了 len 字段,而不是使用 \0 来作为字符串的结束标记,因此我们在计算 go 中的 string 长度时,不需要像在 c 语言中那样为 \0 预留一个字节。
一个 string 变量包含一个指针和一个整数,在64位的机器上占用16个字节

在写一个汇编方法之前,我们需要先声明这个函数,才能供其他 Go 方法调用:

func Hello() int64

接着使用汇编代码实现 Hello 函数:

#include "textflag.h"  //引入textflag.h,因为使用到了RODATA这样的预定义值
//数据段声明一个字符串
DATA msg<> +0(SB)/8,$"hello,wo"  
DATA msg<> +8(SB)/4,$"rld!"
GLOBL msg<> +0(SB),RODATA,$12  //GLOBL声明msg<>为全局标记符,RODATA表示 readOnly
//TEXT定义一个函数,包名· 方法名,这里省略包名,默认是当前包
//24表示函数的栈帧大小是24个字节被调用函数的参数和返回值是保存在调用方的栈帧中的
//echo方法需要一个string类型的参数和一个int64类型的返回值,需要24个字节
//8表示该函数的参数和返回值需要占用的空间
TEXT ·Hello(SB),$24-8     
 //不支持指令的两个参数都是 内存地址,因此需要使用寄存器做媒介
    LEAQ msg<> +0(SB),AX          //LEAQ为取址,将msg的地址存入AX
    MOVQ AX,0(SP)                 //存入0(SP),相当于string.str
    MOVQ $12,8(SP)                //string的长度,相当于string.len
    CALL ·echo(SB)                //调用echo函数
    MOVQ 16(SP),AX                //返回值保存在16(SP)
    MOVQ AX,RET+0(FP)             //将返回值保存到RET+0(FP)
    RET                           //返回

在汇编中传递参数,我们需要根据实际类型的内存布局来放置参数。因为我们传递的是一个 string 类型而不是一个 *string,因此我们需要将 string.strstirng.len 分别 mov0(SP)8(SP)
最后看一下我们的 main 函数:

func main() {
    fmt.Println(assembly.Hello())  //打印Hello的返回值,即echo中返回的len(msg)
}

输出:

hello,world!
12

相关文章

  • 在汇编中调用Go函数

    这次我们来实现,在一个汇编函数中调用Go方法先看一下我们的包结构: 我们先声明一个go方法: 我们想要做的就是在汇...

  • Linux boot的第一步:启动汇编调用main函数

    为了讲清原理,我们首先介绍C函数调用机制,然后再介绍汇编调用C函数。 一、C函数调用机制 对于汇编中的函数,其使用...

  • GO调用C函数

    GO调用C函数 在很多场景下,在Go的程序中需要调用c函数或者是用c编写的库(底层驱动,算法等,不想用Go语言再去...

  • 汇编学习(5),函数,栈帧

    本篇介绍 本篇介绍下汇编中的函数,栈帧内容。 函数 汇编也支持函数调用,如下是一个例子: 使用call + 标号就...

  • 7.汇编-汇编中的函数

    7.汇编-汇编中的函数 什么是函数 函数就是一系列指令的几个,为了完成某个会重复使用的特定功能 函数调用 用JMP...

  • Swift中结构体的方法调度&内存分区

    函数方法调度 结构体的方法调度 如下结构体 在汇编模式下,可知结构体的函数调用方式是静态调用(直接调用): 通过在...

  • 汇编语言知多少(三): 函数调用

    接着上一篇文章, 这篇主要讲汇编程序中函数的调用. call 和 ret 指令: 函数的调用. call 标号 :...

  • 汇编(三)

    1.函数的局部变量 定义一个局部变量c,断点查看汇编中c的存储调用 2.函数的嵌套调用 定义2个函数,funcA中...

  • C 调用 Go 函数

    我们之前已经让 Go 调用 C 函数,但有些场景下需要 C 来调用Go函数。 Go 使用 export 关键字导出...

  • Go函数-延迟调用(三)

    在go语言里,defer可是实现延迟函数调用。语句defer向当前函数注册稍后执行的函数调用。这些调用被称做延迟调...

网友评论

    本文标题:在汇编中调用Go函数

    本文链接:https://www.haomeiwen.com/subject/ivulaxtx.html