成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Linux下被我誤解的gcc,軟件可執行文件的跨系統版本兼容性沒有那么差,如果你也是這樣處理

開發 前端
因為C/C++開發的軟件占比很大,即使開發業務中不直接使用,也會在運行中依賴到C/C++的庫或可執行文件的功能。

以上是近期發布的這3篇文章,圍繞Linux下的可執行文件究竟是采用靜態鏈接還是動態鏈接方式發布,從不同角度做了分析??雌饋淼?、2篇的觀點是相反的。現在對這兩個看似矛盾的說法加以解釋,以期讀者能對Linux的動態庫、靜態編譯可執行文件的理解,和我一樣在學習進步,形成總體符合實際的認知。

也得到了讀者的很多反饋,現舉例其一:

為什么要盯住gcc呢?因為Linux的軟件生態中,C/C++開發的軟件,特別是基礎型軟件、需要高性能的軟件,往往歷史原因都以這兩種語言為主,在此不贅述。

總之,因為C/C++開發的軟件占比很大,即使開發業務中不直接使用,也會在運行中依賴到C/C++的庫或可執行文件的功能。搞懂動態庫的特性,對于解決一些軟件依賴問題、開發編譯鏈接失敗問題,都有幫助。所以開發者和運維仍然有必要增進這方面的理解。

1.動態鏈接適合插件化開發、插件化升級、希望打包發布的可執行文件盡量小的場景;而靜態鏈接方式適合易部署、不想處理第三方動態庫依賴問題的場景。

2.gcc/g++ 作為Linux下主要的編譯器,支持動態鏈接、靜態鏈接方式。如最基本的main.c 代碼可通過gcc -o main_dynamic_link main.c 和 gcc -static -o main_static main.c 分別得到兩類可執行文件。這是大學生在學校初學Linux下的gcc C/C++編程的時候就了解的。

3.gcc 動態鏈接生成的可執行文件,因為代碼必然使用到c/c++的標準庫提供的函數,那么可執行文件必然要與libc.so庫動態庫鏈接(如下圖)。

4.gcc編譯得到的可執行文件,運行時會以進程方式在用戶態、內核態的內存中布局。如果可執行文件是動態鏈接方式的,則運行時由 Linux內核負責載入ELF格式的可執行文件后,內核通過 ld-linux.so (64位系統下則為 ld-linux-x86-64.so ) 分析可執行文件依賴的其他動態庫信息,由ld-linux.so 負責逐個載入其他動態庫到該進程的虛擬內存的代碼段位置中。這里就發揮了動態庫和虛擬內存的優勢:熱門的動態庫被很多其他進程依賴,那么這種可執行文件實際只占用物理內存的一塊空間,無論被多少個進程依賴。

所以達到了提高內存利用率的效果,這對于需要運行大量軟件的場景(如Linux桌面),收益還是可觀的。可執行文件從被調起到執行完畢,我們可以用 strace 命令看到全過程,包括需要讀取的其他庫文件的過程。比如下面的可執行文件可以用strace 看到執行全流程(功能只調用printf函數打印字符串)。

root@localhost:~# file  ./main
./main: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=82e7afc31da1cdbdd374658c2724dce983ccedab, for GNU/Linux 3.2.0, not stripped


root@localhost:~# ldd  ./main
        not a dynamic executable   #說明當前是靜態鏈接的
        
        
root@localhost:~# strace ./main
execve("./main", ["./main"], 0x7ffe6fd2a090 /* 25 vars */) = 0
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffe7ada0370) = -1 EINVAL (Invalid argument)
brk(NULL)                               = 0x1a12000
brk(0x1a12dc0)                          = 0x1a12dc0
arch_prctl(ARCH_SET_FS, 0x1a123c0)      = 0
set_tid_address(0x1a12690)              = 27080
set_robust_list(0x1a126a0, 24)          = 0
rseq(0x1a12d60, 0x20, 0, 0x53053053)    = 0
uname({sysname="Linux", nodename="localhost", ...}) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
readlink("/proc/self/exe", "/root/main", 4096) = 10
getrandom("\xa1\xe6\x48\xa4\x1d\x32\xef\x0e", 8, GRND_NONBLOCK) = 8
brk(0x1a33dc0)                          = 0x1a33dc0
brk(0x1a34000)                          = 0x1a34000
mprotect(0x4c1000, 16384, PROT_READ)    = 0
newfstatat(1, "", {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0
write(1, "111", 3111)                      = 3
exit_group(3)                           = ?
+++ exited with 3 +++

## 下面按動態鏈接生成可執行文件
root@localhost:~# gcc  -o main main.c


## strace 顯示可執行文件 執行時需要加載 `/lib/x86_64-linux-gnu/libc.so.6` 文件。
root@localhost:~# strace ./main
execve("./main", ["./main"], 0x7ffec2fb69c0 /* 25 vars */) = 0
brk(NULL)                               = 0x55fd3f1bc000
root@localhost:~#
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa3491dd000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=87359, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 87359, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa3491c7000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0 =\340\2563\265?\356\25x\261\27\313A#\350"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2216304, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2260560, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa348f9f000
mmap(0x7fa348fc7000, 1658880, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x28000) = 0x7fa348fc7000
mmap(0x7fa34915c000, 360448, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7fa34915c000
mmap(0x7fa3491b4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x214000) = 0x7fa3491b4000
mmap(0x7fa3491ba000, 52816, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa3491ba000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa348f9c000
arch_prctl(ARCH_SET_FS, 0x7fa348f9c740) = 0
set_tid_address(0x7fa348f9ca10)         = 27089
set_robust_list(0x7fa348f9ca20, 24)     = 0
rseq(0x7fa348f9d0e0, 0x20, 0, 0x53053053) = 0
mprotect(0x7fa3491b4000, 16384, PROT_READ) = 0
mprotect(0x55fd3e9e1000, 4096, PROT_READ) = 0
mprotect(0x7fa34921d000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7fa3491c7000, 87359)           = 0
newfstatat(1, "", {st_mode=S_IFCHR|0600, st_rdev=makedev(0x88, 0), ...}, AT_EMPTY_PATH) = 0
getrandom("\x84\x8c\x06\x16\x25\xe5\x97\x97", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0x55fd3f1bc000
brk(0x55fd3f1dd000)                     = 0x55fd3f1dd000
write(1, "111", 3111)                      = 3
exit_group(3)                           = ?
+++ exited with 3 +++
root@localhost:~#

可以看到 動態鏈接的C可執行文件運行時確實需要加載 /lib/x86_64-linux-gnu/libc.so.6 文件。而靜態鏈接的可執行文件沒有加載任何.so文件,包括libc.so也不需要。因為靜態文件的代碼指令已完整在文件中。

root@localhost:~# gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


root@localhost:~# gcc -static -o main_static main.c  # 靜態鏈接
root@localhost:~# gcc  -o main_shared_link main.c    # 動態鏈接
root@localhost:~# ls -lht
total 1.8M
-rwxr-xr-x 1 root root  16K Dec 17 23:58 main_shared_link
-rwxr-xr-x 1 root root 880K Dec 17 23:58 main_static
-rw-r--r-- 1 root root   54 Dec 17 22:30 main.c

root@localhost:~# file main_static   # 查看靜態鏈接文件的屬性
main_static:      ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=82e7afc31da1cdbdd374658c2724dce983ccedab, for GNU/Linux 3.2.0, not stripped

root@localhost:~# main_shared_link  # 查看動態鏈接文件的屬性
main_shared_link: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f14401e673b52624535874f2e1a8488a0edbc891, for GNU/Linux 3.2.0, not stripped

root@localhost:~# ls -lht /lib/x86_64-linux-gnu/libc.so.6
-rwxr-xr-x 1 root root 2.2M Nov 22 21:18 /lib/x86_64-linux-gnu/libc.so.6

這里看到:880K Dec 17 23:58 main_static靜態文件大小880K,而libc.so大小2.2M 。靜態文件大小比C標準庫動態文件的大小還小很多。

說明gcc并不只是把libc.so的所有函數完全包含進靜態可執行文件,而這是我之前對gcc的誤解。

實際gcc對靜態的鏈接是做了精簡優化的,只保留了有被調用的函數代碼到最終可執行文件內。

5.所以本文最初提到的《為什么不建議交付靜態鏈接的可執行文件給用戶?》 中的不建議,是只從靜態文件的分發方式降低了系統基礎庫的重用率的角度出發的。當然隨著技術的進步,也許以后內核的可執行文件加載器能做到識別出靜態文件中的某些可替代的公共部分就自動剔除對物理內存的占用,而借助系統已有的已載入內存的公共代碼實現替代,而不影響軟件功能,就結合了動態和靜態的兩種優勢。這只是一個猜想,并非合理完美的方案。

6.而《為什么Golang開發的軟件單文件直接丟到各種Linux系統就能運行?》中golang能做到的,gcc也能做到,所以C/C++靜態鏈接的可執行文件的跨系統版本兼容性沒有那么差,跟Golang生成的靜態可執行文件是一樣能丟到各種Linux發行版的運行的。

7.但跨系統兼容性的前提是32位、64位系統和軟件的數位,要匹配。除非32位的系統內核支持PAE特性或Linux系統額外安裝了 multilib 庫,以實現32位系統下運行64位的軟件,或64位系統下運行32位的軟件。

責任編輯:趙寧寧 來源: 深入理解Linux
相關推薦

2010-02-22 18:04:27

CentOS mpla

2012-01-05 10:37:40

Java

2015-02-02 11:03:12

2009-06-20 09:21:37

UNIXLINUX

2021-01-06 05:29:57

虛擬內存文件

2023-09-04 07:14:36

2011-08-09 10:24:19

可執行文件病毒病毒

2021-01-08 08:06:19

腳本Shell文件

2022-05-11 14:50:34

Python解包執行文件

2021-01-12 10:10:41

shell腳本Linux命令

2024-08-12 16:42:50

二進制工具系統

2017-02-07 10:22:53

2024-05-06 00:00:00

Go文件瘦身代碼

2009-04-16 10:37:17

Javaexejar

2024-05-21 12:01:39

.NET 6開發

2023-03-31 23:31:06

.go文本文件

2021-01-14 22:17:09

PythonLinux工具

2014-11-04 14:33:33

WebService

2009-02-19 13:59:00

2023-12-18 09:21:22

開發靜態編譯Linux
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 天天干免费视频 | 精品国产一区二区三区在线观看 | 999免费观看视频 | 国产小u女发育末成年 | 中文天堂网 | 精品国产乱码久久久久久88av | 欧美日韩在线观看视频网站 | 国产日韩一区二区 | 一级日韩 | 国产一区二区三区在线 | 国产精品不卡视频 | 91视频正在播放 | 伊人最新网址 | 久久久久99 | 欧美国产精品一区二区三区 | 国产激情一区二区三区 | 中文字幕在线一区 | 亚洲精品一区二区三区丝袜 | 在线看片国产精品 | 国产成人精品午夜 | 最新av在线网址 | 久久在线看 | 午夜精品久久久久99蜜 | 大学生a级毛片免费视频 | 久久久综合| 91精品国产高清一区二区三区 | 国产精品污污视频 | 欧美日韩国产精品一区 | 中文字幕一区在线观看视频 | 北条麻妃一区二区三区在线视频 | 呦呦在线视频 | 亚洲欧美一区二区在线观看 | 97av在线| 操操日 | 午夜日韩| 欧美一级电影免费 | 一区二区三区在线看 | 国产美女一区二区 | 精品成人在线视频 | 精品欧美一区二区在线观看 | 亚洲精品乱码久久久久久9色 |