看板 C_and_CPP 關於我們 聯絡資訊
edit:由於x64下cdecl會學fastcall把特定型別的args放register去傳 所以這問題應該是無解。 簡單的說,以下方的code為例子,根本不可能拿到正確的&a 編譯器在發現你試圖取址a/b的時候 會把他們從esi/edi(都是x64的register) 拷貝出來以後隨意丟在一個無法預期的位置讓你去取址 以這邊來講,就是丟一個離function frame stack 16byte的位置 所以本題應該是無解,而且當args不是int的時候他傳法不見得會相同 重點asm放在這給大家參考一下 movl $30, %esi movl $20, %edi call _Z8testCallii -------以下是本來的原文 我嘗試解了一下這題,中間gcc -S的部分就不贅述了 在osx下這個是可以過關的 先假設大家都知道call convention,function frame的基本概念 另外__builtin都是gcc的東西 我不確定cl.exe能不能認得出來 所以請都用g++去compile https://gist.github.com/Rayer/7ba704f442fa10bc326d OSX : Function pointer frame : 0x7fff5c472960 Param a pointer = 0x7fff5c47295c Param b pointer = 0x7fff5c472958 a = 20, at address : 0x7fff5c47295c b = 30, at address : 0x7fff5c472958 記憶體資料結構長這樣 |====|====| b a frame pointer(請注意他是往後長的,原因不贅述) 4 4 但是我放到我主機(CentOS)以後,這個就不work了 可以發現傳進去真正的a/b跟用__builtin_frame_address(0)拿到位置的差16 bytes Function pointer frame : 0x7fff72b63990 Param a pointer = 0x7fff72b6397c Param b pointer = 0x7fff72b63978 a = 32767, at address : 0x7fff72b6398c b = 1924544904, at address : 0x7fff72b63988 記憶體結構看起來變這樣 |====|====|================| b a (不知道是啥) frame pointer 4 4 16 __builtin_frame_address基本上應該是正解,但是看起來還是有很多問題 在同一台機器下硬用offset去拿應該是可以拿到正確解答 但是在不同平台下似乎會有很多其他的問題 另外這些都是cdecl下,stdcall我就懶得測了,我又不用windows... XD 不過stdcall下參數放進frame stack的順序是反過來的 所以我猜應該ab會互調就是 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.160.25.44 ※ 文章網址: http://www.ptt.cc/bbs/C_and_CPP/M.1403037600.A.C65.html ※ 編輯: Killercat (118.160.25.44), 06/18/2014 04:55:01
chuckAI:謝謝 killer大 雖然很多專業名詞看不懂 但文中的意思是原 06/18 09:25
chuckAI:宣告的參數a,b 位置會有offset的現象 但會隨著硬體有所不 06/18 09:27
chuckAI:同.. 我這樣的理解應該是對的吧.. 06/18 09:28
Killercat:簡單的說 a b都會跟__builtin_frame_address有一段固定 06/18 09:50
Killercat:的距離 你可以試試看用這段距離去取值 06/18 09:50
Killercat:但是我不知道他因為什麼而不同就是 06/18 09:50
Jockey66666:好文 06/18 11:21
AstralBrain:你的測試環境是linux x64吧, int應該會用register傳 06/18 13:48
AstralBrain:a本來放在rdi, b在rsi 06/18 13:50
AstralBrain:因為你要取址, compiler才在stack上隨便找個地方放a,b 06/18 13:53
AstralBrain:要放在哪裡已經不歸calling convention管了 06/18 13:54
Killercat:所以gcc會因為我執行__builtin_frame_address(0)所以隨 06/18 14:18
Killercat:便找一個地方先把arg stack dump出來嗎? 好詭異的行為 06/18 14:19
AstralBrain:因為你要&a, 所以把a從rdi搬到stack上 06/18 14:22
Killercat:我懂了 你是說他在compile time發現我要對a取址所以會多 06/18 14:27
Killercat:作一些額外的行為,把他從真正的frame stack搬出來對吧? 06/18 14:27
Killercat:因為就我理解用register傳應該只有fastcall會這樣玩... 06/18 14:28
Killercat:我回去試試看用別的型別 感謝 06/18 14:28
Killercat:欸 仔細看了一下 -S 你是對的 不過我這邊是放esi/edi 06/18 14:32
AstralBrain:x64因為多了一大堆register, 前幾個參數會跟fastcall 06/18 14:32
AstralBrain:一樣用register傳 06/18 14:32
Killercat:了解 看了一下.s的確也是如此.... 感謝! 06/18 14:33
AstralBrain:rsi/rdi是筆誤XD int是32bit所以會用e開頭的register 06/18 14:36
Killercat:不過這樣說的話 其實本來問題應該是無解了... 06/18 14:46
Killercat:因為型別不同他會用不同方法去傳 很傷腦筋 06/18 14:47
※ 編輯: Killercat (59.124.251.135), 06/18/2014 14:56:59 ※ 編輯: Killercat (59.124.251.135), 06/18/2014 14:58:26
AstralBrain:所以交給gdb去撈debug symbol又快又方便 XD 06/18 14:58
azureblaze:http://ideone.com/P2QxLN 印參數從caller比較簡單吧.. 06/18 15:08
Killercat:可是request是說要從callee... 所以才有這篇文章囧 06/18 15:08
azureblaze:我覺得他不見得只能改callee,可能只是想偏了... 06/18 15:15
azureblaze:如果型態不定數量不定那麻煩事還更多 06/18 15:16
azureblaze:沒reflection做這種事吃力不討好 06/18 15:17
Killercat:callee確定是不可行的了 這年頭連直接對frame stack hac 06/18 15:17
Killercat:k的最後希望都沒了 還能怎麼搞 :D 06/18 15:17
Killercat:大概就剩下Astral說的拿debug symbol拖出來鞭屍了 06/18 15:18