日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 64位兼容32位,linux的64位操作系统对32位程序的兼容-全面分析

發布時間:2024/9/30 linux 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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位程序的兼容-全面分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。