静态链接和动态链接的Golang二进制文件

news2024/9/23 17:58:46

关注TechLead,复旦博士,分享云服务领域全维度开发技术。拥有10+年互联网服务架构、AI产品研发经验、团队管理经验,复旦机器人智能实验室成员,国家级大学生赛事评审专家,发表多篇SCI核心期刊学术论文,阿里云认证的资深架构师,上亿营收AI产品研发负责人。

本文介绍了 Go 语言中静态链接和动态链接的概念,解释了它们的区别和各自优势。通过示例,展示了如何生成静态或动态链接的二进制文件,以及使用工具进行检查。文章还讨论了内部和外部链接器的区别,如何在编译时选择链接方式,以及在交叉编译时处理 cgo 的方法。最后,提到了减小二进制文件大小的技巧和安全性方面的考虑。

file

概述

Go 语言最大的优势之一就是它的编译器,它为程序员抽象了许多细节,让你可以轻松地为几乎任何平台和架构 https://pkg.go.dev/cmd/dist 编译你的程序。

尽管这看起来很简单,但其中有一些细微的差别,同一个程序有多种编译方式,这会导致生成不同的可执行文件。

在本文中,我们将探讨静态链接和动态链接的可执行文件、内部和外部链接器,并使用 fileldldd 等工具检查二进制文件。

什么是静态链接和动态链接?

静态链接是将程序所需的所有库直接复制到最终可执行文件中的做法。

Go 语言非常喜欢并希望在可能的情况下这样做,因为这样生成的二进制文件更加便携,不需要在运行的主机系统上存在库。因此,你的二进制文件可以在任何系统上运行,无论是哪个发行版或版本,而且不依赖任何系统库。

另一方面,动态链接是在运行时按名称将外部或共享库加载到可执行文件中。

动态链接也有其自身的优势。例如,程序可以重用主机系统上可用的常用 libc 库,而不需要重新实现它们,你还可以在不重新链接程序的情况下受益于主机的更新。在许多情况下,它还可以减小可执行文件的大小。

静态链接的程序

让我们来看一个始终进行静态链接的程序。这个程序没有使用 cgo 调用 C 代码,因此所有内容都可以打包在一个静态二进制文件中。

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

什么是二进制文件?

我们可以使用 file 命令首先检查文件类型。

file

它告诉我们这是一个 ELF(可执行和可链接格式)可执行文件,并且是“静态链接”的。

我们不会深入讨论 ELF 是什么,但需要知道的是还有其他可执行文件格式。ELF 是 Linux 上的默认格式,Mach-O 是 macOS 的默认格式,PE/PE32+ 是 Windows 的默认格式,等等。

注意:在本文中,我们将使用 Linux(Ubuntu)及其工具,然而在其他平台上也可以进行类似的操作。

还有一个 Linux 程序 ldd,可以告诉我们二进制文件是静态链接还是动态链接的。

$ ldd main
    not a dynamic executable

动态链接的程序

如前所述,Go 有一个机制叫 cgo,可以从 Go 调用 C 代码,甚至 Go 的标准库在多个地方使用了它。例如,在 net 包中,它使用标准的 C 库来处理 DNS。

默认情况下,导入此类包或在代码中使用 cgo 会生成一个动态链接的二进制文件,链接到那些 libc 库。

file

我们可以再次使用 fileldd 程序来检查第二个二进制文件。

file

file 命令现在显示这是一个动态链接的二进制文件,而 ldd 则显示了二进制文件的动态依赖关系。在这种情况下,它依赖于 libc.so.6ld-linux,后者是 Linux 系统的动态链接器。

我们可以让它静态链接吗?

当你希望二进制文件静态链接时,可能有多种原因,但主要原因是为了简化部署和分发。然而,并不总是有必要这样做。通过链接 libc,你可以从主机更新中受益,并且在使用 net 包的情况下,可以利用 libc 中包含的复杂的 DNS 查找函数。

有趣的是,Go 的 net 包也有一个纯 Go 版本,这使得在编译时禁用 cgo 成为可能。你可以通过指定构建标签或使用 CGO_ENABLED=0 完全禁用 cgo 来实现。

file

上面的截图证明在这两种情况下,我们最终都得到了一个静态二进制文件。

内部链接器 vs 外部链接器

链接器是一个程序,它读取 main 包的 Go 存档或对象,以及它的依赖项,并将它们组合成一个可执行的二进制文件。

默认情况下,Go 的工具链使用其内部链接器(go tool link),但是你可以在编译时指定使用哪个链接器,这样可以让我们在获得静态二进制文件的同时,享受完整的 libc 功能。

在 Linux 上,默认的外部链接器是 gcc 的 ld。我们可以告诉它生成一个静态二进制文件。

file

它能工作,但我们会收到一个警告。在我们的例子中,glibc 使用 libnss 来支持多种地址解析服务提供者,而你无法静态链接 libnss。

其他使用 cgo 的包可能会产生类似的警告,你需要查看文档来判断它们是否严重。

交叉编译

如介绍中所述,交叉编译是 Go 的一个非常好的特性,它允许你为几乎任何平台/架构编译程序。然而,如果你的程序使用了 cgo,这可能会非常棘手,因为交叉编译 C 代码通常很困难。

file

你可以通过为目标操作系统和/或架构安装工具链来解决这个问题。

如果可能,最好在交叉编译时不要使用 cgo。你将得到静态链接的稳定二进制文件。

加分项:减小二进制文件大小

你可能注意到,上面 file 命令的输出包含:“not stripped”。这意味着我们的二进制文件中包含调试信息。但我们通常不需要它,删除它可以减小二进制文件的大小。

file

这将删除调试信息和符号表,减小二进制文件的大小。

当心:LD_PRELOAD 技巧

Linux 系统程序 ld-linux.so(动态链接器/加载器)使用 LD_PRELOAD 来加载指定的共享库。特别是,在加载任何其他库之前,动态加载器将首先加载 LD_PRELOAD 中的共享库。

LD_PRELOAD 技巧是在动态链接的二进制文件中使用的一种强大技术,用于覆盖或拦截对共享库的函数调用。

通过将 LD_PRELOAD 环境变量设置为指向自定义的共享对象文件,用户可以将自己的代码注入程序的执行中,从而有效地替换或增强现有的库函数。

这种方法允许各种应用,例如调试、测试,甚至在不修改原始源代码的情况下改变程序行为。

file

这也表明静态链接的二进制文件更安全,因为它们不存在这个问题,因为它们不依赖任何外部库。此外,还有一个“安全执行模式”——这是由 Linux 系统上的动态链接器实现的安全特性,用于在运行需要提升权限的程序时限制某些行为。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2158129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

李沐 模型选择、过拟合和欠拟合相关代码【动手学深度学习v2】

多项式回归 生成数据集 给定x,我们将使用以下三阶多项式来生成训练和测试数据的标签: y=5+1.2x−3.4+5.6+ϵ where ϵ∼( ). 噪声项ϵ服从均值为0且标准差为0.1的正态分布。 在优化

GraphRAG与VectorRAG我都选:HybridRAG

从金融应用中产生的非结构化文本数据(如财报电话会议记录)提取和解释复杂信息,即使采用当前最佳实践使用检索增强生成(RAG)技术,对于大型语言模型(LLMs)来说仍存在重大挑战。这些挑战…

【游戏党必看】2024年最适合玩游戏的电脑系统推荐!

许多玩家都在问如果在电脑上玩游戏装什么系统好呢?以下系统之家小编给大家推荐两款专门为游戏玩家打造的操作系统,针对大型游戏进行了深度优化,显著提升了系统性能,确保游戏运行更为流畅无阻,能完美兼容各种类型的游戏…

三好夫人|最强“逼”婚神器,送完一次就领证

三好夫人|揭秘最强“逼”婚神器,让你的爱情甜蜜升级,速领见家长通行证! 男人们请记住,如果一个女生给你送三好夫人,那么你赶快带她见家长把婚事定了。 在这个快节奏的时代,爱情似乎也被按下了快…

基于51单片机的电机控制和角度检测

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机,采用滑动变阻器连接ADC0832数模转换器模拟角度传感器,然后通过LCD1602显示数值,然后按键按下不动,电机正转,松开停止。第二…

显示和隐藏图片【JavaScript】

使用 JavaScript 来实现显示和隐藏图片。下面是一个简单的示例&#xff0c;展示如何通过按钮点击来切换图片的可见性。 实现效果: 代码&#xff1a; <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name&…

神奇的交互!Ethernet IP转Profinet网关与发那科机器人的数据交互

在当今的工业领域&#xff0c;随着自动化程度的不断提高&#xff0c;工业化升级已成为必然趋势。在这个过程中&#xff0c;对机器人的联网需求变得日益迫切。机器人作为工业生产中的重要组成部分&#xff0c;其高效运行和与其他设备的协同工作对于提高生产效率至关重要。然而&a…

EI-Bisynch协议

EI-Bisynch&#xff08;Extended Interface-Bisynchronous&#xff09;协议是一种早期用于设备通信的协议&#xff0c;主要用于工业控制系统中的串行通信。随着技术的发展&#xff0c;EI-Bisynch的使用已经大幅减少&#xff0c;逐渐被更现代化、灵活性更高的通信协议&#xff0…

【Linux】手把手教你制作一个简易shell——(进程创建fork进程替换wait与进程等待exec的应用)(自定义shell程序设计)

前言 大家好吖&#xff0c;欢迎来到 YY 滴Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C Linux的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

华为昇腾智算中心-智算中心测试方案与标准

本方案是企业内训课程《华为昇腾智算中心深度技术研修》的一部分授课课件的样例。方案内容中详细阐述了华为昇腾环境下智算中心的测试方案和标准&#xff0c;以确保硬件和软件系统在实际部署和运行中的高效性和稳定性。主要内容包括集群硬件清单、节点拓扑配置以及环境配置。硬…

企业微信oauth2的code换用户身份一直40029解决方案

序&#xff1a; 雪狼的微信表情包&#xff0c;欢迎下载【程序员雪狼】微信表情 - 来自微信表情商店&#xff0c;扫二维码下载表情 正文&#xff1a; 雪狼在用oauth2返回的code要去请求getuserinfo3rd接口的时候&#xff0c;报错如下40029 一样&#xff0c;肝了一天&#xff0c…

本地部署高颜值某抑云音乐播放器Splayer并实现无公网IP远程听歌

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

湖北建筑类初级职称申报的全方位解读

湖北建筑类初级职称申报的全方位解读 湖北工程行业助理工程师/初级职称申报评审 湖北建筑类助理工程师/初级职称正常申报目前都是电子版证书&#xff0c;湖北省政务服务网查询生成&#xff0c;省网查询&#xff0c;后期都会同步G网查询。 湖北建筑类助理工程师纸质版 1.之前申…

kubernetes网络(一)之calico详解

摘要 本文介绍Kubernetes最流行的网络解决方案calico。 kubernetes中不同宿主上的pod需要相互通信&#xff0c;如果按TCP/IP协议分层进行分类&#xff1a; 二层方案&#xff1a;flannel的udp和vxlan模式 三层方案&#xff1a;flannel的host-gw模式&#xff1b;calico的IPIP模…

ReduceLROnPlateau学习率衰减设置

学习率衰减有多种方式&#xff0c;本次采用optim.lr_scheduler.ReduceLROnPlateau&#xff0c;这种方式代表在发现loss不再降低或者acc不再提高之后&#xff0c;降低学习率。 model GRU().to(device) criterion nn.CrossEntropyLoss().to(device) optimizer optim.AdamW(m…

YOLOv10独家改进:红外场景严重遮挡和重叠目标解决方案 | 一种新的自适应算法轻量级通道分割和变换(ALSS)模块,自适应特征提取优化策略

💡💡💡本文解决什么问题:红外检测场景存在严重遮挡和重叠目标时的局限性的问题点。 💡💡💡提出了一种新的自适应算法轻量级通道分割和变换(ALSS)模块。该模块采用自适应信道分裂策略优化特征提取,并集成信道变换机制增强信道间的信息交换。这改善了模糊特征的提…

简单多状态dp第一弹 leetcode -面试题17.16.按摩师 -213.打家劫舍II

a​​​​​​​面试题 17.16. 按摩师 按摩师 题目: 分析: 使用动态规划解决 状态表示: dp[i] 表示&#xff1a;选择到 i 位置时&#xff0c;此时的最长预约时长。 但是我们这个题在 i 位置的时候&#xff0c;会面临 选择 或者 不选择 两种抉择&#xff0c;所依赖的状态需要…

响应式的几种解决方案——媒体查询、flex、grid、多列布局、瀑布流和数据可视化屏幕的缩放处理

media媒体查询 媒体查询入门指南 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document<…

Java面试篇基础部分- Java中的阻塞队列

首先队列是一种前进后出的操作结构,也就是说它只允许从队列前端进入,从队列后端退出。这个前端和后端看个人如何理解,也就是通常所说的入队和出队,队头和队尾。 阻塞队列和一般队列的不同就在于阻塞队列是可以阻塞的,这里所说的并不是说队列中间或者队头队尾被拦截了,而是…

HTML与JavaScript结合实现简易计算器

目录 背景&#xff1a; 过程&#xff1a; 代码: HTML部分解析&#xff1a; body部分解析&#xff1a; JavaScript部分解析&#xff1a; 效果图 &#xff1a; 总结: 背景&#xff1a; 计算器是一个典型的HTML和javaScript结合使用的例子&#xff0c;它展示了如何使用H…