理解go工具编译和链接命令

理解go工具编译和链接命令,go,compiler-construction,Go,Compiler Construction,我知道将高级语言代码转换为机器语言或可执行代码需要三个步骤,即编译、组装和链接 根据go docsgo tool编译执行以下操作- 然后写入一个以第一个源文件的basename命名的单一对象文件,并带有.o后缀 因此,最终的目标文件必须包含每个文件的机器语言代码(编译和组装运行后)。如果我在go文件上传递go工具compile-S,它将显示汇编语言go生成 之后,当我在目标文件上运行go tool link时,它必须链接所有必需的目标文件(如果有多个),然后生成最终的机器语言代码(基于GOOS和

我知道将高级语言代码转换为机器语言或可执行代码需要三个步骤,即编译、组装和链接

根据go docsgo tool编译执行以下操作-
然后写入一个以第一个源文件的basename命名的单一对象文件,并带有.o后缀

因此,最终的目标文件必须包含每个文件的机器语言代码(编译和组装运行后)。如果我在go文件上传递go工具compile-S,它将显示汇编语言go生成

之后,当我在目标文件上运行go tool link时,它必须链接所有必需的目标文件(如果有多个),然后生成最终的机器语言代码(基于GOOS和GOARCH)。它生成一个文件a.out

这里有几个基本问题-

我如何知道哪些变量以及何时在堆栈和堆中分配内存?如果我为一台机器生成可执行文件并在另一台具有不同体系结构的机器上运行,这有关系吗

我的测试计划

package main

func f(a *int, b *int) *int { 

    var c = (*a + *b); 
    var d = c;
    return &d;
}

func main() {
    var a = 2;
    var b = 6;

    f(&a,&b);
}
go工具编译-m-l测试的结果。go

test.go:6: moved to heap: d
test.go:7: &d escapes to heap
test.go:3: f a does not escape
test.go:3: f b does not escape
test.go:14: main &a does not escape
test.go:14: main &b does not escape
在哪个步骤中分配内存

它取决于,一些在链接过程中,一些在编译过程中,大多数在运行时(还有一些在加载过程中)

我如何知道哪些变量以及何时在堆栈和堆中分配内存

你根本不知道。编译器决定这一点。如果编译器可以证明变量没有转义,它可能会将其保留在堆栈上。谷歌搜索“golang escape analysis”。如果您对它感兴趣,有一个标志-m使编译器输出他的决定

如果我为一台机器生成可执行文件并在另一台具有不同体系结构的机器上运行,这有关系吗


不,只是因为这根本不起作用:可执行文件与体系结构绑定,不会在不同的体系结构上运行

看来你把编译/链接和内存分配搞混了。后者与前两者大不相同。(从技术上讲,您的链接程序可能包含内存,在加载过程中可能会得到更多内存,但这是高度技术性的和特定于体系结构的,实际上不需要担心)

在哪个步骤中分配内存

它取决于,一些在链接过程中,一些在编译过程中,大多数在运行时(还有一些在加载过程中)

我如何知道哪些变量以及何时在堆栈和堆中分配内存

你根本不知道。编译器决定这一点。如果编译器可以证明变量没有转义,它可能会将其保留在堆栈上。谷歌搜索“golang escape analysis”。如果您对它感兴趣,有一个标志-m使编译器输出他的决定

如果我为一台机器生成可执行文件并在另一台具有不同体系结构的机器上运行,这有关系吗


不,只是因为这根本不起作用:可执行文件与体系结构绑定,不会在不同的体系结构上运行


看来你把编译/链接和内存分配搞混了。后者与前两者大不相同。(从技术上讲,您的链接程序可能包含内存,在加载过程中可能会得到更多内存,但这是高度技术性的和特定于体系结构的,实际上不需要担心)

您可以通过
-x
标志准确地查看Go工具的功能。当然,内存分配是在运行时进行的。通过打印转义分析输出,您可以看到什么是堆栈与堆。内存分配指的是将为某个变量分配堆内存或堆栈内存。我在哪里看到的?哦,它在编译器优化输出中
-m
谢谢@JimB我这样做了,并将结果粘贴到了上面。您可以确切地看到Go工具使用
-x
标志做了什么。当然,内存分配是在运行时进行的。通过打印转义分析输出,您可以看到什么是堆栈与堆。内存分配指的是将为某个变量分配堆内存或堆栈内存。我在哪里看到的?哦,它在编译器优化输出中
-m
谢谢@JimB我这样做了,并将结果粘贴到上面。我使用-m选项编译了。根据输出,如果某个变量转义某个函数,则将在堆上分配该变量,如果该变量未转义,则在堆栈上分配该变量。但它并没有说任何关于temp变量c的内容。用程序和编译输出编辑了我的问题。“可执行文件与体系结构相关,不会在不同的体系结构上运行”——大致准确,但有一定的兼容性;e、 例如,windows-386(32位)应该在windows-amd64(64位)上运行。@Sam很可能编译器只是简单地优化了f的大部分代码。仅仅因为您编写了
var c…
,并不意味着将使用RAM中的实际内存,因为这样的事情可以在寄存器中完成。我确实使用了-m选项进行编译。根据输出,如果某个变量转义某个函数,则将在堆上分配该变量,如果该变量未转义,则在堆栈上分配该变量。但它并没有说任何关于temp变量c的内容。用程序和编译输出编辑了我的问题。“可执行文件与体系结构相关,不会在不同的体系结构上运行”——大致准确,但有一定的兼容性;e、 例如,windows-386(32位)应该在windows-amd64(64位)上运行。@Sam很可能编译器只是简单地优化了f的大部分代码。仅仅因为您编写了
var c…
,并不意味着将使用RAM中的实际内存,因为这样的工作可以在寄存器中完成。