第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

在x86機(jī)器代碼中調(diào)用絕對(duì)指針

在x86機(jī)器代碼中調(diào)用絕對(duì)指針

慕容森 2020-02-02 15:33:42
call在x86機(jī)器代碼中指向絕對(duì)指針的“正確”方法是什么?有一個(gè)好的方法可以在一條指令中完成嗎?我想做什么:我正在嘗試基于“子例程線程”構(gòu)建一種簡(jiǎn)化的mini-JIT(仍然)。從根本上講,這是從字節(jié)碼解釋器開(kāi)始的最短步驟:每個(gè)操作碼都是作為單獨(dú)的函數(shù)實(shí)現(xiàn)的,因此可以將每個(gè)基本字節(jié)碼塊“ JITted”到它自己的新過(guò)程中,如下所示:{prologue}call {opcode procedure 1}call {opcode procedure 2}call {opcode procedure 3}...etc{epilogue}因此,我們的想法是每個(gè)塊的實(shí)際機(jī)器代碼都可以從模板中粘貼(根據(jù)需要擴(kuò)展中間部分),唯一需要“動(dòng)態(tài)”處理的位是將每個(gè)操作碼的功能指針復(fù)制到正確的地方,作為每個(gè)呼叫說(shuō)明的一部分。我遇到的問(wèn)題是了解call ...模板部分要使用什么。x86似乎沒(méi)有考慮到這種用法,而是支持相對(duì)和間接調(diào)用。它看起來(lái)像我可以使用FF 15 EFBEADDE或2E FF 15 EFBEADDE在假設(shè)調(diào)用函數(shù)DEADBEEF(通過(guò)把東西變成一個(gè)匯編和反匯編,看到什么產(chǎn)生有效的結(jié)果,基本上發(fā)現(xiàn)了這些未通過(guò)了解他們?cè)谧鍪裁矗?,但我不理解的東東細(xì)分和特權(quán)以及相關(guān)信息,足以看出差異,或者它們與更常見(jiàn)的call指令之間的行為會(huì)有何不同。英特爾架構(gòu)手冊(cè)還建議這些僅在32位模式下有效,而在64位模式下“無(wú)效”。有人可以解釋這些操作碼,以及為此目的如何或是否將其使用?(通過(guò)寄存器使用間接調(diào)用也有明顯的答案,但這似乎是“錯(cuò)誤的”方法-假設(shè)實(shí)際存在直接調(diào)用指令。)
查看完整描述

2 回答

?
LEATH

TA貢獻(xiàn)1936條經(jīng)驗(yàn) 獲得超7個(gè)贊

這里的所有內(nèi)容也適用于jmp絕對(duì)地址,并且用于指定目標(biāo)的語(yǔ)法相同。該問(wèn)題詢問(wèn)有關(guān)JITing的問(wèn)題,但我還添加了NASM和AT&T語(yǔ)法以擴(kuò)大范圍。


另請(qǐng)參閱在JIT中處理對(duì)遙遠(yuǎn)的內(nèi)在函數(shù)的調(diào)用,以獲取分配“附近”內(nèi)存的方法,以便您可以用來(lái)rel32從JITed代碼中調(diào)用提前編譯的函數(shù)。


x86沒(méi)有對(duì)指令中的普通(近)call或jmp絕對(duì)地址進(jìn)行編碼的編碼。 沒(méi)有絕對(duì)的直接調(diào)用/ jmp編碼,除非jmp far您不需要。請(qǐng)參閱英特爾的insn set ref手冊(cè)條目call。(有關(guān)文檔和指南的其他鏈接,另請(qǐng)參見(jiàn)x86標(biāo)簽wiki。)大多數(shù)計(jì)算機(jī)體系結(jié)構(gòu)都使用相對(duì)編碼來(lái)進(jìn)行正常跳轉(zhuǎn),例如x86,BTW。


最好的選擇(如果可以使位置依賴的代碼知道其自身的地址)是使用normalcall rel32,E8 rel32直接近距離調(diào)用編碼,該rel32字段為target - end_of_call_insn(2的補(bǔ)碼二進(jìn)制整數(shù))。


請(qǐng)參閱$在NASM中如何工作?以手動(dòng)編碼call指令為例;在JITing期間執(zhí)行此操作應(yīng)該同樣容易。


在AT&T語(yǔ)法中: call 0x1234567

在NASM語(yǔ)法中:call 0x1234567

也適用于具有絕對(duì)地址的命名符號(hào)(例如使用equ或創(chuàng)建.set)。MASM沒(méi)有等效功能,它顯然只接受標(biāo)簽作為目的地,因此人們有時(shí)會(huì)使用低效的解決方法來(lái)解決工具鏈(和/或目標(biāo)文件格式重定位類型)的限制。


這些匯編和鏈接恰好在位置相關(guān)的代碼中(而不是共享的lib或PIE可執(zhí)行文件)。但不是在x86-64 OS X中,該文本段映射在4GiB上方,因此無(wú)法通過(guò)到達(dá)低地址rel32。


在要調(diào)用的絕對(duì)地址范圍內(nèi)分配JIT緩沖區(qū)。 例如,mmap(MAP_32BIT)在Linux上,可以在2GB的低內(nèi)存中分配內(nèi)存,其中+ -2GB可以到達(dá)該區(qū)域中的任何其他地址,或者在跳轉(zhuǎn)目標(biāo)所在的位置附近提供非NULL的提示地址。(MAP_FIXED不過(guò),不要使用;如果您的提示與任何現(xiàn)有映射重疊,則最好讓內(nèi)核選擇一個(gè)不同的地址。)


(Linux非PIE可執(zhí)行文件在2GB的虛擬地址空間中進(jìn)行了映射,因此它們可以使用[disp32 + reg]帶有符號(hào)擴(kuò)展的32位絕對(duì)地址的數(shù)組索引,或?qū)㈧o態(tài)地址放入具有mov eax, imm32零擴(kuò)展的絕對(duì)地址的寄存器中。因此,2GB的低地址是,不低于4GB, 但PIE可執(zhí)行文件正在成為常態(tài),因此,除非您確保與之建立+鏈接,否則請(qǐng)不要假設(shè)主可執(zhí)行文件中的靜態(tài)地址位于32位以下-no-pie -fno-pie。并且其他操作系統(tǒng)(如OS X)始終將可執(zhí)行文件的容量設(shè)置為4GB以上)


如果您無(wú)法call rel32使用

但是,如果您需要制作不知道其絕對(duì)地址的與位置無(wú)關(guān)的代碼,或者您需要調(diào)用的地址與調(diào)用者之間的距離大于+ -2GiB(可能為64位,但是最好放置)代碼足夠接近),則應(yīng)使用間接注冊(cè)call


; use any register you like as a scratch

mov   eax, 0xdeadbeef               ; 5 byte  mov r32, imm32

     ; or mov rax, 0x7fffdeadbeef   ; for addresses that don't fit in 32 bits

call  rax                           ; 2 byte  FF D0

或AT&T語(yǔ)法


mov   $0xdeadbeef, %eax

# movabs $0x7fffdeadbeef, %rax      # mov r64, imm64

call  *%rax

很明顯,你可以使用任何寄存器,比如r10或r11這是呼叫重挫,但不用于ARG-傳遞的x86-64系統(tǒng)V. AL = XMM參數(shù)的個(gè)數(shù)數(shù)的可變參數(shù)函數(shù),所以你需要在AL = 0之前的固定值x86-64 System V調(diào)用約定中對(duì)可變參數(shù)函數(shù)的調(diào)用。


如果確實(shí)需要避免修改任何寄存器,則可以將絕對(duì)地址保持為內(nèi)存中的常數(shù),并使用call具有RIP相對(duì)尋址模式的間接內(nèi)存,例如


NASM call [rel function_pointer] ; 如果您無(wú)法破壞

AT&T的任何法規(guī)call *function_pointer(%rip)


請(qǐng)注意,間接調(diào)用/跳轉(zhuǎn)會(huì)使您的代碼容易受到Spectre攻擊,尤其是在同一流程中將JIT作為不信任代碼的沙箱的一部分時(shí)。(在那種情況下,僅內(nèi)核補(bǔ)丁將無(wú)法保護(hù)您)。


您可能希望使用“ retpoline”而不是普通的間接分支來(lái)減輕Spectre的性能。


間接跳轉(zhuǎn)的分支錯(cuò)誤預(yù)測(cè)懲罰也比直接(call rel32)稍差。普通直接callinsn 的目的地一經(jīng)解碼就被知道,一旦它檢測(cè)到根本沒(méi)有分支,就在管道中更早地知道。


間接分支通??梢栽诂F(xiàn)代x86硬件上很好地預(yù)測(cè),并且通常用于對(duì)動(dòng)態(tài)庫(kù)/ DLL的調(diào)用。這并不可怕,但是call rel32絕對(duì)更好。


但是,即使直接也call需要一些分支預(yù)測(cè)來(lái)完全避免管道氣泡。(在解碼之前需要進(jìn)行預(yù)測(cè),例如,假設(shè)我們剛剛獲取了該塊,則提取階段接下來(lái)應(yīng)獲取該塊。jmp next_instruction 當(dāng)用完分支預(yù)測(cè)器條目時(shí),速度會(huì)變慢)。 即使具有完美的分支預(yù)測(cè),mov間接+ call reg也更糟糕,因?yàn)樗哂懈蟮拇a大小和更多的微指令,但是效果很小。如果有其他mov問(wèn)題,如果可能的話,內(nèi)聯(lián)代碼而不是調(diào)用它是一個(gè)好主意。


有趣的事實(shí):call 0xdeadbeef它將在Linux上匯編但不會(huì)鏈接到64位靜態(tài)可執(zhí)行文件中,除非您使用鏈接程序腳本將.textsection / text segment 放在靠近該地址的位置。該.text部分通常從0x400080靜態(tài)可執(zhí)行文件(或非PIE動(dòng)態(tài)可執(zhí)行文件)開(kāi)始,即從虛擬地址空間的低2GiB開(kāi)始,所有靜態(tài)代碼/數(shù)據(jù)都駐留在默認(rèn)代碼模型中。但是0xdeadbeef在低32位的高半部分(即在低4G而不是低2G中),因此可以將其表示為零擴(kuò)展的32位整數(shù),而不是符號(hào)擴(kuò)展的32位。并且0x00000000deadbeef - 0x0000000000400080不適合將正確擴(kuò)展為64位的有符號(hào)32位整數(shù)。(負(fù)數(shù)可以到達(dá)的地址空間部分rel32從低位地址回繞的是64位地址空間的頂部2GiB;通常,地址空間的前一半保留給內(nèi)核使用。)


它確實(shí)可以與組裝yasm -felf64 -gdwarf2 foo.asm,并objdump -drwC -Mintel顯示:


foo.o:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:

    0:   e8 00 00 00 00       call   0x5   1: R_X86_64_PC32        *ABS*+0xdeadbeeb

但是,當(dāng)ld嘗試真正在那里的.text開(kāi)始于它鏈接到一個(gè)靜態(tài)可執(zhí)行文件0000000000400080,ld -o foo foo.o說(shuō)foo.o:/tmp//foo.asm:1:(.text+0x1): relocation truncated to fit: R_X86_64_PC32 against '*ABS*'。


在32位代碼中,call 0xdeadbeef匯編和鏈接很好,因?yàn)閍 rel32可以從任何地方到達(dá)任何地方。相對(duì)位移不必將符號(hào)擴(kuò)展為64位,而只需32位二進(jìn)制加法即可。


直接遠(yuǎn)call編碼(慢,不使用)

您可能會(huì)在的手冊(cè)條目中注意到,call并且jmp其中的編碼帶有絕對(duì)目標(biāo)地址,直接編碼在指令中。但那些只存在于“遠(yuǎn)” call/ jmp也設(shè)置CS一個(gè)新的代碼段選擇,這是緩慢的(見(jiàn)昂納霧指南)。


CALL ptr16:32(“在操作數(shù)中給出的遠(yuǎn),絕對(duì)地址調(diào)用”)具有6個(gè)字節(jié)的段:將偏移量直接編碼到指令中,而不是將其作為數(shù)據(jù)從普通尋址模式下的位置加載。因此,這是對(duì)絕對(duì)地址的直接調(diào)用。


Far call還將Push CS:EIP作為返回地址,而不僅僅是EIP,因此它甚至與call僅推送EIP的普通(附近)兼容。這不是問(wèn)題jmp ptr16:32,只是緩慢和弄清楚段部分的內(nèi)容。


更改CS通常僅對(duì)從32位模式更改為64位模式有效,反之亦然。通常,只有內(nèi)核才能執(zhí)行此操作,盡管您可以在大多數(shù)普通的OS(在GDT中保留32位和64位段描述符)下的用戶空間中執(zhí)行此操作。但是,那將是更多愚蠢的計(jì)算機(jī)技巧,而不是有用的東西。(帶有iret或帶有的64位內(nèi)核將返回到32位用戶空間sysexit。大多數(shù)操作系統(tǒng)在引導(dǎo)過(guò)程中僅使用遠(yuǎn)jmp一次即可切換到內(nèi)核模式下的64位代碼段。)


主流操作系統(tǒng)使用的平面內(nèi)存模型不需要更改cs,并且cs對(duì)于用戶空間進(jìn)程將使用什么值還沒(méi)有標(biāo)準(zhǔn)化。即使您想使用far jmp,也必須找出要在細(xì)分選擇器部分中輸入的值。(易而JIT編譯:剛讀當(dāng)前cs有mov eax, cs,但很難提前-的即時(shí)編譯可移植的。)


call ptr16:64不存在,遠(yuǎn)距離直接編碼僅適用于16位和32位代碼。在64位模式下,您只能call使用10字節(jié)的m16:64內(nèi)存操作數(shù),例如call far [rdi]?;?qū)egment:offset推入堆棧并使用retf。


查看完整回答
反對(duì) 回復(fù) 2020-02-02
?
小唯快跑啊

TA貢獻(xiàn)1863條經(jīng)驗(yàn) 獲得超2個(gè)贊

您僅憑一條指令就無(wú)法做到。一個(gè)不錯(cuò)的方法是使用MOV + CALL:


0000000002347490: 48b83412000000000000  mov rax, 0x1234

000000000234749a: 48ffd0                call rax

如果要調(diào)用的過(guò)程的地址發(fā)生更改,請(qǐng)更改從偏移2開(kāi)始的八個(gè)字節(jié)。如果調(diào)用0x1234的代碼的地址發(fā)生更改,則無(wú)需執(zhí)行任何操作,因?yàn)樵搶ぶ肥墙^對(duì)的。


查看完整回答
反對(duì) 回復(fù) 2020-02-02
  • 2 回答
  • 0 關(guān)注
  • 885 瀏覽
慕課專欄
更多

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)