[英]how to make small binaries using assembly?
我正在為我的某個項目編寫一些匯編代碼,我看到了一些有趣的東西。 鏈接時二進制的大小是如此之大。 所以我測試和測試,即使用盡可能小的代碼行,輸出Elf二進制文件也是如此之大。 例如:
.section .text
.global _start
_start:
movl $1,%eax
movl $0,%ebx
int $0x80
組裝和鏈接上面的代碼后,結果二進制文件超過4kb ! 有趣的是,大多數二進制文件都填充了零。
我嘗試了很多東西,找出沒有成功的原因。
有人可以向我解釋一下這里有什么問題嗎?
我只是匯編並鏈接文件:
as -o <OBJ_NAME> <SOURCE NAME>
ld -o <ELF_NAME> <OBJ_NAME>
推薦任何形式的資源進一步閱讀將是很好的。
你可能猜到,我使用的是64位GNU / Linux
謝謝。
這與對齊有關。 請參閱readelf -eW <ELF_NAME>
。 有趣的是
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 0000000000401000 001000 00000c 00 AX 0 0 1
注意Off
列。 這是文件中的偏移量, .text
部分以0x1000
開頭,即4K。
如果查看程序頭文件,請查看相同的圖片。 填充零的空間位於ELF標頭的末尾和0x1000之間。
為什么是這樣?
首先,因為ELF標准規定了這一點
可加載的進程段必須具有p_vaddr和p_offset的全等值,以頁面大小為模。
(見man elf
)。 系統上的頁面大小(我的)也是4K。 這是您在p_align
看到的值。
其次,鏈接器分配給“文本”段開頭的虛擬地址 - 與此處的.text
部分相同,因為這里包含的所有部分 - 是0x0000000000401000
。 因此,文件中“文本”段的偏移量的十六進制表示必須以000
結尾。 但是包含ELF頭的readonly段(文件的最開頭)已經采用了0。 第二個選擇是0x1000
。
為什么鏈接器選擇0x401000作為文本部分的虛擬地址? 我不知道。 我想,如果你稍微調整鏈接器腳本,你將能夠擁有一個較小的重新執行可執行文件。
正如彼得和其他人所指出的那樣,可以使用-n
鏈接器選項禁用頁面大小對齊:
'-n'
'--nmagic'
Turn off page alignment of sections, and disable linking against
shared libraries[…]
那樣我就明白了
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 1] .text PROGBITS 0000000000400078 000078 00000c 00 AX 0 0 1
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000078 0x0000000000400078 0x0000000000400078 0x00000c 0x00000c R E 0x1
並且可執行文件的大小低至664字節( strip
ping后為344)。
使用GNU ld,您可以使用鏈接描述文件來精確控制鏈接器輸出文件的布局。 ld.bfd
(通常也稱為ld
)解釋默認鏈接描述文件(如果用戶未指定)。 它可以用ld --verbose
獲得。 然后,您可以編輯它並使用-T <your-script>
提供您的版本而不是默認版本。
我編輯了第一次出現
. = ALIGN(CONSTANT (MAXPAGESIZE));
(在.text
之前)並獲得720(400 strip
)字節。 這與使用-n
選項的結果不同。 你仍然得到2個可加載的segmemts,它們的p_align
仍然是0x1000
。
p_align
< MAX_PAGE_SIZE
對我不完全理解有效率影響。 (由於地址計算較難,頁面的加載速度不會很快?我認為應該有更好的解釋。)如果你對此有所了解或者解釋的地方,請隨意編輯答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.