爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GOT ?)

内核编译和嵌入式产品的设计与开发
回复
头像
dukelec
帖子: 410
注册时间: 2010-08-26 22:20
系统: Gentoo
来自: Canton

爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GOT ?)

#1

帖子 dukelec » 2013-10-18 17:20

如果有兩個 ELF: A, B. A 調用了 B 的 func 與 data, 則 A 需要配備 GOT 來記錄所調用 B 的 func 與 data 的地址。

但如果只有 A 自己,不需要 GOT 也可以實現位置無關啊,就算 A 體積比較大,某些地方超出相對 PC 尋址,但其偏移量始終是固定的數,多用條指令也是可以實現跳轉的啊。

求解。

-------------------------
modify title only
上次由 dukelec 在 2013-10-22 11:41,总共编辑 5 次。
头像
adam8157
帖子: 2794
注册时间: 2009-03-05 16:31
联系:

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?

#2

帖子 adam8157 » 2013-10-22 0:37

好问题, 不过为啥放到水区啊?

答案是因为uboot是个bootloader, 它需要加载kernel header的一些数据, 例如需要加载的内核大小是多少(x86的实模式内核), 它也需要告诉内核一些信息, 例如kernel command line的地址. 这些就是另外一个elf的data咯.

PS, 是我认为的答案
头像
dukelec
帖子: 410
注册时间: 2010-08-26 22:20
系统: Gentoo
来自: Canton

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?

#3

帖子 dukelec » 2013-10-22 9:41

通過解析 vmlinux elf header 便可知其加載大小,入口地址等信息;command line 是 uboot 一開始準備好在內存,然後用寄存器傳遞地址給內核。
這些都與 uboot 自身編譯過程無任何關聯,且查看 uboot GOT 全都是 uboot 自身的部分 func 與 data, 與 kernel 無關。

昨天看了 gcc 有 -fpic 與 -fpie 兩種不同的方式(非連接器 -pie, 誤混淆),主程式應該選用 -fpie 參數來實現位置無關,
這樣 local func 與 local data 就會編譯爲直接 PC 偏移尋址,而不用查 GOT(外部 func 與 data 仍然會用 GOT 來查找)。

應該是 -fpie 比較新,以前無,所以才借用動態庫用的 -fpic 參數來編譯主程式。
但仍然不清楚爲何動態庫 local func 與 local data 亦需要 GOT 查表。

我試過將 uboot 編譯選項改爲 -fpie, 結果編譯出來仍然有 GOT 表,且大小翻倍,不知爲何。
头像
adam8157
帖子: 2794
注册时间: 2009-03-05 16:31
联系:

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#4

帖子 adam8157 » 2013-10-22 12:09

vmlinux elf header里头没有实内核的大小吧, x86比较麻烦需要实模式和保护模式转换.

不过里头都是自身的func和data我不大明白, 难道它自身分成几块儿加载了..........
头像
adam8157
帖子: 2794
注册时间: 2009-03-05 16:31
联系:

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#5

帖子 adam8157 » 2013-10-22 12:16

動態庫內部調用 local func的话如果是extern的它也要做准备被引用吧我猜, 而且动态库要准备被多个进程调用(share), 全局变量啥的要各自维护吧
头像
dukelec
帖子: 410
注册时间: 2010-08-26 22:20
系统: Gentoo
来自: Canton

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#6

帖子 dukelec » 2013-10-22 14:45

不用考慮 x86, 我的 uboot 是 for mipsel 架構。

如果分成多塊就應該有多個 .text 段、.got 段,但實際無。
...內部調用 local func的话如果是extern的它也要做准备被引用吧...
的確有人提到:
[SOLVED] Re: statically linked PIEs without GOT [http://comments.gmane.org/gmane.comp.gcc.help/42112]

裏面說:如果一個 c 文件引用一個 extern 變量(來自另一個 c 文件),需要加上 hidden 修飾來避免生成 GOT 查表:

代码: 全选

extern __attribute__((visibility("hidden"))) int var;
但我寫了測試工程,用 -fpie(or -fPIE) 編出來的 .o 文件,如果用 -static 參數鏈接,不加 hidden 修飾也不會有 GOT 表,
鏈接出來的 ELF 文件 checksum 與不加 -fpie 一樣。

不知道如何才能編譯出 static linked 且 position independent 且無 GOT 的裸跑代碼。
头像
adam8157
帖子: 2794
注册时间: 2009-03-05 16:31
联系:

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#8

帖子 adam8157 » 2013-11-01 17:18

17:15 < adam8157> GOT, 顺便问个问题, uboot的GOT table里为啥都是它自己的func和data, 单个elf为啥要这样?
17:15 < adam8157> GOT不是为了放全局func和data的么, 为啥单个elf的got里都是自己的东西? viewtopic.php?f=15&t=450538
17:16 < amker> 猜测可能是有些代码/数据需要在不同的virtual address运行
17:16 < amker> 比如mmusetup前后, 地址会发生变化
17:17 < adam8157> amker: 哦 有可能 相当于不同的memory map了 所以需要GOT
17:18 < amker> 应该是这个原因
abutter
帖子: 4
注册时间: 2013-01-13 10:56
系统: ubuntu

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#9

帖子 abutter » 2013-12-28 9:39

u-boot GOT 的用法是为了解决内存大小不同所产生的问题。

如果你不用 GOT 表,那么 U-Boot 的链接地址为了便利多数情况下应该是 RAM 空间的地址,这个地址固定的情况下难免跟保存内核镜像的空间、解压缩内核所需要的空间、以及内核运行所需要空间冲突。

使用 GOT 表之后,链接地址为 ROM 地址,U-Boot 会根据 RAM 的大小自动计算其新的代码、数据等段的地址,然后进行修正,通常放在接近于内存空间的最后(或者你指定空间的最后),这样保留足够大的空间以避免冲突;同时,在 ROM 中的代码也不需要非常小心的计算偏移。
abutter
帖子: 4
注册时间: 2013-01-13 10:56
系统: ubuntu

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#10

帖子 abutter » 2013-12-28 9:39

u-boot GOT 的用法是为了解决内存大小不同所产生的问题。

如果你不用 GOT 表,那么 U-Boot 的链接地址为了便利多数情况下应该是 RAM 空间的地址,这个地址固定的情况下难免跟保存内核镜像的空间、解压缩内核所需要的空间、以及内核运行所需要空间冲突。

使用 GOT 表之后,链接地址为 ROM 地址,U-Boot 会根据 RAM 的大小自动计算其新的代码、数据等段的地址,然后进行修正,通常放在接近于内存空间的最后(或者你指定空间的最后),这样保留足够大的空间以避免冲突;同时,在 ROM 中的代码也不需要非常小心的计算偏移。
头像
adam8157
帖子: 2794
注册时间: 2009-03-05 16:31
联系:

Re: 爲什麼 uboot 等單個 ELF 也需要 GOT 表?(爲何動態庫內部調用 local func 也要查 GO

#11

帖子 adam8157 » 2013-12-31 10:08

abutter 写了:u-boot GOT 的用法是为了解决内存大小不同所产生的问题。

如果你不用 GOT 表,那么 U-Boot 的链接地址为了便利多数情况下应该是 RAM 空间的地址,这个地址固定的情况下难免跟保存内核镜像的空间、解压缩内核所需要的空间、以及内核运行所需要空间冲突。

使用 GOT 表之后,链接地址为 ROM 地址,U-Boot 会根据 RAM 的大小自动计算其新的代码、数据等段的地址,然后进行修正,通常放在接近于内存空间的最后(或者你指定空间的最后),这样保留足够大的空间以避免冲突;同时,在 ROM 中的代码也不需要非常小心的计算偏移。
赞, make sense
回复