![](/img/trans.png)
[英]Writing a putchar in Assembly for x86_64 with 64 bit Linux?
[英]x86_64 Assembly Linux System Call Confusion
我目前正在 Linux 上學習匯編語言。 我一直在使用“從頭開始編程”這本書,所有的例子都是 32 位的。 我的操作系統是 64 位的,我一直在嘗試用 64 位來做所有的例子。 但是,我遇到了麻煩:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rbx
int $0x80
這只是調用 Linux 退出系統調用或者它應該調用。 相反,它會導致 SEG FAULT,而當我這樣做時
.section .data
.section .text
.global _start
_start:
movq $1, %rax
movq $2, %rbx
int $0x80
有用。 顯然問題是我移動到 %rax 的值。 我在第二個示例中使用的值 $1 是“從頭開始編程”所說的使用值,但是 Internet 上的多個來源表示 64 位系統調用號是 $60。 參考我做錯了什么? 另外我應該注意哪些其他問題以及我應該使用什么作為參考? 以防萬一你需要知道,我在從頭開始編程的第 5 章。
您在 i386 和 x86_64 之間遇到了一個令人驚訝的差異:它們不使用相同的系統調用機制。 正確的代碼是:
movq $60, %rax
movq $2, %rdi ; not %rbx!
syscall
中斷0x80
總是調用 32 位系統調用。 它用於允許 32 位應用程序在 64 位系統上運行。
出於學習目的,您可能應該嘗試完全按照教程進行操作,而不是立即將其轉換為 64 位——您可能會遇到其他一些重要的行為差異。 一旦你熟悉了 i386,那么你就可以單獨拿起 x86_64。
請閱讀此x86-64 上 UNIX 和 Linux 系統調用的調用約定是什么
請注意,在 x64 系統上使用int 0x80
進行系統調用是一個舊的兼容層。 您應該在 x64 系統上使用syscall
指令。
您仍然可以使用這種舊方法,但是您需要在 x86 模式下編譯二進制文件,有關詳細信息,請參閱您的編譯器/匯編器手冊。
duskwuff的回答正確地指出了 64 位 x86 Linux 與 32 位 Linux 的系統調用機制不同。
但是,由於以下幾個原因,此答案不完整且具有誤導性:
int 0x80
在 Pentium 4 上非常慢。 Linus Torvalds使用SYSENTER
/ SYSEXIT
指令編寫了一個解決方案(英特爾在 Pentium Pro 時代引入了這些指令,但這些指令有問題並且沒有實際好處)。 所以現代 32 位 Linux 系統實際上使用SYSENTER
,而不是int 0x80
。SYSENTER
和SYSEXIT
。 它們實際上使用非常相似的SYSCALL
/ SYSRET
指令。 正如評論中指出的那樣, SYSENTER
實際上不適用於許多 64 位 Linux 系統——即64 位AMD系統。
這是一個公認的令人困惑的情況。 血腥的細節在這里,但歸結為:
對於 32 位內核,SYSENTER/SYSEXIT 是唯一的兼容對[AMD 和 Intel CPU 之間]
僅對於長模式下的 64 位內核...... SYSCALL/SYSRET 是唯一兼容的對[AMD 和 Intel CPU 之間]
似乎在 64 位模式下的Intel CPU 上,您可以使用SYSENTER
因為它與SYSCALL
執行相同的SYSCALL
,但是對於 AMD 系統,情況並非如此。
底線:始終在 64 位 x86 系統上的 Linux 上使用SYSCALL
。 這是 x86-64 ABI 實際指定的內容。 (有關更多詳細信息,請參閱這個很棒的wiki 答案。)
i386 和 x86_64 之間發生了很多變化,包括用於進入內核的指令和用於攜帶系統調用參數的寄存器。 這是與您的代碼等效的代碼:
.section .data
.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall
引用這個對相關問題的回答:
系統調用號位於 arch/x86/include/asm/unistd_64.h 下的 Linux 源代碼中。 系統調用號在 rax 寄存器中傳遞。 參數在rdi、rsi、rdx、r10、r8、r9中。 使用“syscall”指令調用該調用。 系統調用會覆蓋 rcx 寄存器。 回報是 rax。
如果您檢查/usr/include/asm/unistd_32.h
exit 對應於1
但在/usr/include/asm/unistd_64.h
exit 對應於60
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.