热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

/src/pkg/math/abs.go源码阅读兼谈golang与汇编

开头的碎碎念:对接微信公众平台的时候,开始有个字符串排序,我接触golang毕竟时间尚浅,很多东西都是能从网上找到就直接从网上找,结果就是找了好几个示例代码都不好用,好容易一个好用的,从头开始实现

开头的碎碎念:

对接微信公众平台的时候,开始有个字符串排序,我接触golang毕竟时间尚浅,很多东西都是能从网上找到就直接从网上找,结果就是找了好几个示例代码都不好用,好容易一个好用的,从头开始实现的,代码太多了。我就想,google应该把这些玩意都封装好了吧,不然一个新出的语言只有基础语法,没有强大的标准库,谁用这玩意啊。也就是那时候第一次接触src文件夹,后来发现pkg里的那些go文件是绝好的学习资料。

那么多文件、文件夹从哪开始看呢,我的原则,先找没有依赖性的,也就是没有import的,这么寻摸着就找到了math文件夹。笨方法,从a开始按顺序来呗,这不就碰到了abs.go

难以理解的第12行:

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package math

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

func abs(x float64) float64 {
switch {
case x <0:
return -x
case x == 0:
return 0 // return correctly abs(-0)
}
return x
}

孤零零的一行,一个方法声明,别的啥都没有,完全不解其意。

下面那个abs()不用我说了吧,很简单的,取绝对值。

不管了,先到math文件夹看看,abs_386.s、abs_amd64.s、abs_arm.s有这三个文件估计跟那行不知道哪来的代码有关系,.s结尾的,汇编语言文件,继续发动google的威力,golang、汇编混编,如此便找到了http://www.mikespook.com/2013/02/%E7%BF%BB%E8%AF%91go-%E5%92%8C%E6%B1%87%E7%BC%96/

让程序跑起来:

先让这段程序跑起来吧,因为我的机器是64位的,所以我把abs.go、abs_amd64.s两个文件拷贝到别处,abs.go的包改成了mymath,另外写了一个简单的测试程序

package main

import(
"fmt"
"mymath"
)

func main(){
fmt.Println(mymath.Abs(
-12.00))
}

在/pkg/tool/windows_amd64下有很多有用的工具,6g、6l啥的,不过常用的都被go命令给封装了,直接go build、go install等命令就解决了。

涉及到汇编的,主要是6a,上面的代码按如下顺序编译:

6a abs_amd64.s(生成abs_amd64.6)

6g –o _go_.6 abs.go(生成_go_.6)

pack grc abs.a  _go_.6 abs_amd64.6(生成abs.a)

本来是想直接让主程序调用目录下的库的,import “./mymath”,不过,windows下提示出错import path contains invalid characte ‘:’:”c:/xxx/xxx”,所以只得将abs.a扔到pkg/windows_amd64文件夹中。

剩下的就是:

6g test.go(生成test.6)

6l test.6(生成6.out.exe)

从简单的golang编译器自动生成的汇编入手:

先看一个新的命令,golang编译器自动生成汇编中间代码的命令,go tool 6g –S XXX.go,其实上面的那些命令也都可以用go tool XXX来代替,go命令把那些命令都封装进去了。

来个最简单的代码吧:

package asm

func Asm(i
int)int{
return i
}

go tool 6g –S asm.go:

--- prog list "Asm" ---
0000 (asm.go:3) TEXT Asm+0(SB),$0-16
0001 (asm.go:3) LOCALS ,$0
0002 (asm.go:3) TYPE i+0(FP){int},$8
0003 (asm.go:3) TYPE ~anon1+8(FP){int},$8
0004 (asm.go:4) MOVQ i+0(FP),BX
0005 (asm.go:4) MOVQ BX,~anon1+8(FP)
0006 (asm.go:4) RET ,

plan9汇编,语法跟AT&T颇为类似,传值是前面是源,后面是目的,这点跟masm、nasm啥的都是反的。

000行:TEXT相当于定义了一个函数,Asm函数名,+0(SB)golang生成的都有这玩意;$0-16,经过我的反复尝试,起码对于int、float64这两者而言,是(参数个数+返回值个数)*8(这都是我自己验证的,没啥科学依据,相关文档我也翻阅过一些,不过鸟语不过关,将把能看懂的东西里没有我需要的,大胆假设,小心论证现在还做不到)。

001行:我估计是执行指令的位置,不过这都不重要,关键是后头的。

002、003行:i是变量名,~anon1其实也是变量名(系统自动生成的)

稍微修改下

func Asm(i int) (j int){
j
=i
return
}

则003行,就变成了j+8(FP)

至于0(FP)、8(FP),对于int来说,每个数字占8个字节(64位下),所以传入的参数,第一个就是+0(FP),第二个+8(FP),第三个+16(FP),第四个+24(FP)…

返回值,如果有多个返回值,第一个+(8+最后一个传入参数的数值)(FP),后面都是依次+8

{int}标明了数据类型,$8表明占据8个字节

004行:将参数值传给寄存器BX,MOVQ,传递四字

005行:将BX中的值传给返回值

006行:RET

看看float64又是啥样的:

package asm

func Asm(f float64
)float64{
return f
}
--- prog list "Asm" ---
0000 (asm.go:3) TEXT Asm+0(SB),$0-16
0001 (asm.go:3) LOCALS ,$0
0002 (asm.go:3) TYPE i+0(FP){int},$8
0003 (asm.go:3) TYPE ~anon1+8(FP){float64},$8
0004 (asm.go:4) MOVQ i+0(FP),X0
0005 (asm.go:4) MOVQ X0,~anon1+8(FP)
0006 (asm.go:4) RET ,

可以看出与前面用int去尝试大致相同,只是BX寄存器变成了X0,可以推测X0就是浮点数寄存器,有X0,大胆推测会有X1、X2、X3…

试试吧

package asm

func Asm(f1,f2 float64) float64{
return f1+f2
}
--- prog list "Asm" ---
0000 (asm.go:3) TEXT Asm+0(SB),$0-24
0001 (asm.go:3) LOCALS ,$0
0002 (asm.go:3) TYPE f1+0(FP){float64},$8
0003 (asm.go:3) TYPE f2+8(FP){float64},$8
0004 (asm.go:3) TYPE ~anon2+16(FP){float64},$8
0005 (asm.go:4) MOVSD f1+0(FP),X0
0006 (asm.go:4) MOVSD f2+8(FP),X1
0007 (asm.go:4) ADDSD X1,X0
0008 (asm.go:4) MOVSD X0,~anon2+16(FP)
0009 (asm.go:4) RET ,

abs_amd64.s:

// Copyright 2010 The Go Authors.  All rights reserved.

// Use of this source code is governed by a BSD-style

// license that can be found in the LICENSE file.


// func Abs(x float64) float64

TEXT ·Abs(SB),
7,$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

折腾一番终于到这了。

第一行就当固定格式吧,函数名替换下就好。

MOVQ   $(1<<63), BX
MOVQ BX, X0

1右移动63位,传给X0,此时X0二进制表示是1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

MOVSD  x+0(FP), X1

MOVSD移动标量双精度浮点值,将参数x的值传给X1

ANDNPD X1, X0

ANDNPD压缩双精度浮点值逻辑位与非,将目标操作数的取反,再与源操作数执行逻辑位“与”操作,结果存储到目标操作数

即对X0取反,再与X1相与,最后结果存储到X0中

以上操作所完成的也就是将符号位置0,由此完成取绝对值的任务。


推荐阅读
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了三种方法来实现在Win7系统中显示桌面的快捷方式,包括使用任务栏快速启动栏、运行命令和自己创建快捷方式的方法。具体操作步骤详细说明,并提供了保存图标的路径,方便以后使用。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Windows 7 部署工具DISM学习(二)添加补丁的步骤详解
    本文详细介绍了在Windows 7系统中使用部署工具DISM添加补丁的步骤。首先需要将光驱中的安装文件复制到指定文件夹,并进行挂载。然后将需要的MSU补丁解压并集成到系统中。文章给出了具体的命令和操作步骤,帮助读者完成补丁的添加过程。 ... [详细]
  • 如何搭建Java开发环境并开发WinCE项目
    本文介绍了如何搭建Java开发环境并开发WinCE项目,包括搭建开发环境的步骤和获取SDK的几种方式。同时还解答了一些关于WinCE开发的常见问题。通过阅读本文,您将了解如何使用Java进行嵌入式开发,并能够顺利开发WinCE应用程序。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
    文章目录引言开发环境和库流程设计张嘴和闭眼的检测引言(1)利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68个点标定 ... [详细]
  • CEPH LIO iSCSI Gateway及其使用参考文档
    本文介绍了CEPH LIO iSCSI Gateway以及使用该网关的参考文档,包括Ceph Block Device、CEPH ISCSI GATEWAY、USING AN ISCSI GATEWAY等。同时提供了多个参考链接,详细介绍了CEPH LIO iSCSI Gateway的配置和使用方法。 ... [详细]
  • 本文介绍了在Mac上安装Xamarin并使用Windows上的VS开发iOS app的方法,包括所需的安装环境和软件,以及使用Xamarin.iOS进行开发的步骤。通过这种方法,即使没有Mac或者安装苹果系统,程序员们也能轻松开发iOS app。 ... [详细]
author-avatar
淡逸幽悠
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有