linux 64位兼容32位,linux的64位操作系统对32位程序的兼容-全面分析
1.結構體ioctl_trans:
struct ioctl_trans {
unsigned long cmd;
ioctl_trans_handler_t handler;
struct ioctl_trans *next;
};
該結構體提供了一個粘合層,用戶可以動態注冊一個ioctl_trans以便其提供64位和32位的粘合:
extern int register_ioctl32_conversion(unsigned int cmd,
ioctl_trans_handler_t handler);
extern int unregister_ioctl32_conversion(unsigned int cmd);
整個系統的ioctl_trans連接成一個哈希表,放在ioctl32_hash_table變量中。每一個ioctl_trans的handler都是一個回調函數,在其中將64位的數據和32位的數據類型進行統一,統一成64位可以正確識別和處理的,以防在后續的64位代碼中出錯,比如一個32位的signed int為-1,需要將之轉化成64個1而不是32個0加上32個1。
2.一套完整的系統調用:
如果不這樣的話,32位程序的系統調用如何被路由到通過ioctl_trans們進行粘合的代碼就成了問題,要知道x86-64已經不使用int 0x80作為觸發系統調用的機制了,而使用syscall指令來觸發。那么原來的32位程序都是用int 0x80來觸發的,這下怎么辦?辦法就是仍然保留0x80號中斷號,將其處理程序設置成ia32_syscall,它在ia32_sys_call_table中找具體的系統調用處理函數,具體在arch/x86_64/ia32/ia32entry.S中:
ENTRY(ia32_syscall)
CFI_STARTPROC
swapgs
sti
movl %eax,%eax
pushq %rax
cld
SAVE_ARGS 0,0,1
GET_THREAD_INFO(%r10)
testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)
jnz ia32_tracesys
ia32_do_syscall:
cmpl $(IA32_NR_syscalls),%eax
jae? ia32_badsys
IA32_ARG_FIXUP
call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
...
ia32_sys_call_table:
.quad sys_restart_syscall
.quad sys_exit
.quad stub32_fork
.quad sys_read
...
.quad compat_sys_ioctl
...
在arch/x86_64/kernel/traps.c的trap_init函數中將ia32_syscall設置成0x80號中斷的處理程序:
set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);//#define IA32_SYSCALL_VECTOR 0x80
那么使用sysenter的怎么辦呢? 這是通過在exec的時候由內核檢測到其是32位程序是動態將處理代碼map到gate處的,要知道x86-64也不使用sysenter機制進行系統調用。那64位的x86-64怎么系統調用呢?在arch/x86-64/kernel/entry.S中有ENTRY(system_call)這個標志,在arch/x86_64/kernel/setup64.c中的syscall_init函數中有以下一行:
wrmsrl(MSR_LSTAR, system_call);
可見64位的x86-64是通過一個MSR寄存器來保存系統調用處理地址的,而不再是通過中斷。至于說機器如何處理這個信息以及這個寄存器如何影響系統運行,這已經到x86-64體系的cpu實現硬件問題了,和本文的linux系統的要旨無關,此處簡略(再說不簡略也不行啊,我也不會啊)。
3.總結
由于硬件指令的兼容,32位的程序在用戶態不受任何影響的運行,由于內核保留了0x80號中斷作為32位程序的系統調用服務,因此32位程序可以安全觸發0x80號中斷使用系統調用,由于內核為0x80中斷安排了另一套全新的系統調用表,因此可以安全地轉換數據類型成一致的64位類型,再加上應用級別提供了兩套c庫,可以使64位和32位程序鏈接不同的庫。因此linux的64-32兼容搞得非常好。
為了看一下在x86-64上64位程序和32位程序是如何執行系統調用的,寫一個最簡單的測試程序:
#include
#include
int main()
{
getpid();
}
之所以選擇getpid是因為它沒有參數,最簡單,將之在Red Hat 32位機器上按照如下命令行編譯:
gcc test.c -o test-32 -g
然后再將之在64位機器上同樣方式編譯,只是可執行文件名字變為test-64。接下來首先gdb test-32:
(gdb) b main
...
(gdb) r
...
(gdb) b getpid
Breakpoint 2 at 0xf7f3d430
(gdb) disassemble? 0xf7f3d430 0xf7f3d43a
0xf7f3d430 :? mov??? $0x14,%eax??? #0x14是20,正是getpid的系統調用號
0xf7f3d435 :? int??? $0x80??? ???? #32位程序以int 0x80觸發系統調用
0xf7f3d437 :? ret
0xf7f3d438 :? nop
0xf7f3d439 :? nop
End of assembler dump.
(gdb)
結果全部在,可見即使在64位機器上,32位程序仍然使用int 0x80觸發系統調用,在內核中已經注冊了0x80的中斷處理函數。接下來再試一下64位的程序如何觸發系統調用,執行gdb test-64:
(gdb) b main
...
(gdb) r
...
(gdb) b getpid
Breakpoint 2 at 0x32fbf90f40
(gdb) disassemble 0x32fbf90f40 0x32fbf90f70
Dump of assembler code from 0x32fbf90f40 to 0x32fbf90f70:
0x00000032fbf90f40 :? mov??? %fs:0x94,%edx
0x00000032fbf90f48 :? test?? %edx,%edx
0x00000032fbf90f4a : mov??? %edx,%eax
0x00000032fbf90f4c : jle??? 0x32fbf90f50
0x00000032fbf90f4e : repz retq
0x00000032fbf90f50 : jne??? 0x32fbf90f5e
0x00000032fbf90f52 : mov??? %fs:0x90,%eax
0x00000032fbf90f5a : test?? %eax,%eax
0x00000032fbf90f5c : jne??? 0x32fbf90f4e
0x00000032fbf90f5e : mov??? $0x27,%eax #系統調用號裝入eax
0x00000032fbf90f63 : syscall?? ??? ? #執行系統調用
0x00000032fbf90f65 : test?? %edx,%edx
0x00000032fbf90f67 : jne??? 0x32fbf90f4e
0x00000032fbf90f69 : mov??? %eax,%fs:0x90
值得注意的是,在2.6.9內核的x86-64機器上,getpid和32位機器的getpid系統調用號有所不同,在64位上是39號,定義在include/asm-x86_64/unistd.h:
#define __NR_getpid???????????????????????????? 39
__SYSCALL(__NR_getpid, sys_getpid)
而剛才看到過,32位兼容的getpid的系統調用號為20,定義在arch/x86_64/ia32/ia32entry.S中:
ia32_sys_call_table:
...
.quad sys_getpid??????????????? /* 20 */
...
PS:千萬不要覺得test.c很簡單然后就stepi單指令跟蹤哦,因為這會涉及到一大堆跳轉,如果你不明白鏈接的知識,不了解GOT和PIC的話,那就麻煩大了,因此還是直接在getpid處下斷比較直觀,如果你想順便把代碼重定位和GOT等玩意兒搞了的話,也可以試一下,反正在調試器面前,整個地址空間都會暴露,想看什么都行,當然,要學會讓/proc//maps等文件幫忙哦。
再分享一下我老師大神的人工智能教程吧。零基礎!通俗易懂!風趣幽默!還帶黃段子!希望你也加入到我們人工智能的隊伍中來!https://blog.csdn.net/jiangjunshow
標簽:ia32,調用,x86,32,64,getpid,linux
來源: https://www.cnblogs.com/ksiwnhiwhs/p/10390736.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的linux 64位兼容32位,linux的64位操作系统对32位程序的兼容-全面分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux生成公钥实现ssh,linux
- 下一篇: linux调用qt生成静态库文件下载,C