一個有趣的過程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
是合法的
相關文章
- 編譯過程編譯
- 編譯通過的 foo函式返回一個int編譯函式
- 痛苦的過程,編譯glomap編譯
- 編譯連結過程編譯
- C++ 編譯過程C++編譯
- 編譯過程簡介編譯
- JavaScript的預編譯過程分析JavaScript編譯
- ios底層 編譯過程iOS編譯
- GCC編譯和連結過程GC編譯
- 預編譯過程(AO+GO)編譯Go
- 詳解Linux 程式編譯過程Linux編譯
- go語言編譯過程概述Go編譯
- GCC編譯過程(預處理->編譯->彙編->連結)GC編譯
- 編譯原理入門篇|一篇文章理解編譯全過程編譯原理
- 2.深入一點理解C源程式的編譯過程編譯
- [轉]:xmake編譯配置過程詳解編譯
- 3- C語言編譯過程C語言編譯
- Ubuntu20.04linux核心(5.4.0版本)編譯準備與實現過程-編譯過程(2)UbuntuLinux編譯
- Linux 程式編譯過程的來龍去脈Linux編譯
- Hive SQL的底層編譯過程詳解HiveSQL編譯
- vue原理:diff、模板編譯、渲染過程等Vue編譯
- C語言的編譯連結執行過程C語言編譯
- Oracle儲存過程編譯卡死的解決方法Oracle儲存過程編譯
- 一個專案 兩個cgo依賴編譯不通過Go編譯
- uni-app 通過命令列編譯打包APP命令列編譯
- Android編譯通過,執行編譯錯誤問題總結Android編譯
- 【譯】通過css,用一個div做一個芝士漢堡CSS
- https的通訊過程HTTP
- 深入wepy原始碼:wpy檔案編譯過程原始碼編譯
- Oracle 編譯儲存過程卡死解決方法Oracle編譯儲存過程
- Azure DevOps (八) 通過流水線編譯Docker映象dev編譯Docker
- MDK編譯過程及檔案型別全解編譯型別
- VS2017平臺編譯 zmq-4.2.5 過程編譯MQ
- C語言編譯和連結過程簡介C語言編譯
- cesium原始碼編譯除錯及呼叫全過程原始碼編譯除錯
- 帶你深入 Dart 解析一個有趣的引用和編譯實驗Dart編譯
- Android Apk 檔案反編譯和重新打包的過程分析AndroidAPK編譯
- SQL 儲存過程裡呼叫另一個儲存過程SQL儲存過程