一個有趣的過程movq%rcx,%gs:0x80000000不能通過編譯
movq %rcx, %gs:0x80000000不能通過編譯
今天有同事提問, 為什麼
movq %rcx, %gs:0x7fffffff //可以通過編譯
movq %rcx, %gs:0x80000000 //不能通過編譯
其實就是一個立即數的差別, 應該是無差的, 好吧, 讓我們來研究一下
第一步
先看一下movq %rcx, %gs:0x7fffffff
的二進位制指令, 因為movq %rcx, %gs:0x80000000
不能通過編譯, 就不是合法指令, 自然也看不了二進位制內容了
1c: 65 48 89 0c 25 ff ff mov %rcx,%gs:0x7fffffff
23: ff 7f
第二步
既然65 48 89 0c 25 ff ff ff 7f是mov %rcx,%gs:0x7fffffff
, 很容易得到前面65 48 89 0c 25是mov %rcx,%gs
, 後面是一個立即數, 那麼我們就看看65 48 89 0c 25 80 00 00 00
是什麼東西
第三步
怎麼知道65 48 89 0c 25 80 00 00 00
是什麼東西呢?
開啟o檔案, 找到指令的編碼位置, 把7f ff ff ff
改成 80 00 00 00
, 然後再objdump, 得到
1c: 65 48 89 0c 25 00 00 mov %rcx,%gs:0xffffffff80000000
23: 00 80
由此我們可以得到, 65 48 89 0c 25
後面的4位元組會被解釋成signed int, 再來驗證一下, 編譯一下mov %rcx,%gs:0xffffffff80000000可以得到65 48 89 0c 25 00 00 00 80
可以得到結論, movq %rcx, %gs:0x80000000
被gcc理解成了movq %rcx, %gs:0x0000000080000000
第四步
下面的問題就是為什麼movq %rcx, %gs:0x0000000080000000
是非法指令
其中一個很容器想到的答案就是, 原來指令65 48 89 0c 25
後面是跟4位元組的, 現在變成8位元組了, 如果還是這種模式的話, 變成了13位元組, 應該是太長了, 所以65 48 89 0c 25
要變成更短的東西, opcode和register的選擇也沒這麼隨意了, 下面的事情就是去查手冊了, 還有一種偷懶的方式就是把rcx換成其他暫存器, 把所有的暫存器都試一遍, 看看行不行
結論
movq %r?x, %gs:0x0000000080000000
只能使用rax
movq %rcx, %gs:0x7fffffff, movq %rcx, %gs:0x80000000是被編碼成64位基地址和32位整數或者64位整數相加,
先討論位編碼成32位整數的情況,
如果我是設計師的話, 也傾向於把後面的這個32位設計成signed, 這樣定址過程中, 又能向前, 又能向後
所以movq %rcx, %gs:0x7fffffff是合法的
movq %rcx, %gs:0x80000000
gcc報告錯誤是因為這個等價於movq %rcx, %gs:0x0000000080000000
, 0x0000000080000000已經超出32位signed的範圍了, 不能編碼成64位基地址和32位整數相加, 只能編碼成64位基地址和64位整數相加
這樣後面的這個64位整數就要被編碼進指令裡面去, 比之前的指令多了4個位元組, 所以前面的暫存器, opcode的編碼就少了, 不能隨意的選擇暫存器, 只能預設rax來操作, 也就是mov變成了movabs
所以movq %rax, %gs:0x80000000
是合法的
相關文章
- 編譯過程編譯
- 一個儲存過程編譯HANG住的分析儲存過程編譯
- 編譯通過的 foo函式返回一個int編譯函式
- 編譯器的編譯基本過程編譯
- Javac編譯過程Java編譯
- 編譯核心過程編譯
- 編譯器的工作過程編譯
- EVC編譯TCPMP的過程編譯TCP
- 編譯連結過程編譯
- 編譯過程簡介編譯
- C++ 編譯過程C++編譯
- JavaScript的預編譯過程分析JavaScript編譯
- 編譯C++ 程式的過程編譯C++
- ios底層 編譯過程iOS編譯
- .NET 程式碼編譯過程編譯
- glade 編譯過程 (轉)編譯
- oracle 儲存過程不能編譯-- (編譯的同時正在訪問所導致的) [轉載]Oracle儲存過程編譯
- 如果一個過程正在執行,這個時候編譯這個過程,會產生library cache pin編譯
- 一個Linux愛好者的2.6.11核心編譯過程(轉)Linux編譯
- vlc-android 的編譯過程Android編譯
- 編譯器的工作過程和原理編譯
- Java程式碼編譯和執行的整個過程Java編譯
- GCC編譯和連結過程GC編譯
- go語言編譯過程概述Go編譯
- 預編譯過程(AO+GO)編譯Go
- C程式編譯過程淺析C程式編譯
- Android 專案編譯過程Android編譯
- Android Makefile 編譯過程分析Android編譯
- Hive SQL 編譯過程詳解HiveSQL編譯
- C語言編譯全過程C語言編譯
- 儲存過程編譯時卡死儲存過程編譯
- GCC編譯過程(預處理->編譯->彙編->連結)GC編譯
- iOS編譯過程的原理和應用iOS編譯
- 初探 Go 的編譯命令執行過程Go編譯
- ASPNet_Compiler的編譯過程Compile編譯
- 編譯原理入門篇|一篇文章理解編譯全過程編譯原理
- 編譯、連結學習筆記(一)簡述編譯連結過程編譯筆記
- 怪事,一個類在jb9下編譯透過但在jb7下就不能透過???編譯