程序本質回憶上次內容
我們把python源文件
詞法分析 得到 詞流(token stream)
語法分析 得到 抽象語法樹(Abstract Syntax Tree)
編譯 得到 字節碼 (bytecode)
字節碼我們看不懂
所以反編譯 得到 指令文件(opcode)
指令文件是基於python虛擬機的虛擬cpu的指令集
什麼是python虛擬機呢?🤔
在了解虛擬cpu之前
我們先看看真實的cpu
真實的cpu
無論手機還是計算機
最核心器件的器件就是cpu
這個東西是個實實在在存在的實體
我們所說的python虛擬機能看到麼?
就是用來運行py文件的
python3 到底是個啥?which python3ll /usr/bin/python3
這個 python3
是一個符號鏈接文件
只有9字節
他指向 python3.8
python3.8
也在 /usr/bin 裡面
就是/usr/bin/python3.8
python3.8是一個5.3M的文件
可以看得見
可以直接運行這個phthon3.8嗎?
直接運行/usr/bin/python3.8
python3.8 就在硬盤裡呆着
usr 是 unix software resource
bin 是二進制 binary
python3.8 是這個文件的名稱
位置就在/usr/bin/python3.8
在運行命令的時候
把這個文件從硬盤裝載到內存
然後用 cpu 開始逐行執行文件中的0101指令
可以把他複製到shiyanlou用戶的宿主文件夾下嗎?
複製
複製到shiyanlou下
再觀察
#把/usr/bin/python3這個py文件的解釋器拷貝到~(當前用戶文件夾)#cp的意思是copycp /usr/bin/python3 ~#確認python3已經拷到~(當前用戶文件夾)#ls的意思是listls ~/python3.8#查看python3文件細節ls -lah ~/python3.8
python3 指向的 python3.8 只有 5.3M
這個可執行文件怎麼這么小?
5.3M 這也就是一張照片的大小
以前的 Python3.5 只有 4.3M
更小
目前這 5.3M 的 Python3 裡面到底有什麼呢?🤔
研究 python3#用vi打開這個剛拷貝過來的python3vi ~/python3.8
這個樣子看起來
全是亂碼
完全看不懂啊
這個東西我們確實看不懂
但是有人能看懂
誰呢?
cpu
cpu能看懂!!!
這些我們看不懂的亂碼
cpu能看懂
這是屬於cpu的機器語言
這就是cpu的一條條的機器指令(instruction)
機器指令碼都是二進制形式的
我們嘗試把python3.8轉化為字節表現形式
以字節形式觀察python3.8vi ~/python3.8
用vim打開~/python3.8
:
進入命令行模式
:%!xxd我們可以看到這個文件的二進制形態
%是指的對於所有行的範圍
!是執行外部命令
xxd指的是轉化為 16 進制形式
什麼是xxd命令呢?
xxd
xxd 可以查看文件的二進制形態
dump的本意是(傾倒垃圾)
這裡指的是轉儲
把文件轉儲為16進制形式匯編代碼形式
:xxd –r 可以還原回去 😉
:%!xxd 轉成字節形態
:%!xxd –r 轉回文本形態
反覆橫跳...
另存為python3.8hex
一行是(16)10 進制 個字節
G到最後一行
總共有 343148 行
這就是 真正的機器語言🤭
cpu能執行的東西
真真切切看到了的
真的存在硬盤上 01010 的二進制可執行指令!!
這些指令執行出來就是我們的遊樂場!!!
或者說是我們的python虛擬機
可是這個指令我們看不懂怎麼辦?🤔
先把他另存出來
:w python3.8hex
把當前緩存(buffer)另存(write)為
python3.8hex
對python3.8強制退出
:q!
不保存修改強制退出
python3.8hex就是我們要的機器語言的字節形態
可是這字節形態我們看不懂啊
匯編語言助記符#先把~/python3對應的機器語言輸出為匯編指令形式(反匯編)objdump -d python3.8 > python3.8.asmvi python3.8.asm
這次真的可以看懂了
減法(sub)
移動(mov)
這些指令
可以發現當前系統的架構(指令集)是x86-64
這些和我們剛才的字節形態有關係嗎?
對比
用vi分窗口分別打開打開python3 和 python3.asm
vi -o python3.8hex python3.8.asm
下圖中上半部分是機器語言
上圖下半部分是機器語言對應的匯編指令助記符
ctrl+j、ctrl+k可以上下切換
我們來試着找找
python3文件中
機器語言的0101和cpu的匯編指令的對應關係🧐
找到了
先跳過下面窗格的第8行
endbr64 意味着 64位結束分支
下面的sub執行的是減法
下面窗格的 第9行
/48 83 找到上下的對應關係
也就是第一條執行的匯編指令減法(sub)
匯編指令是計算機 cpu 機器指令的助記符
查找對應關係
423000 就是初始化(init)的 cpu 開始執行指令的地址
我們在上面查找48 83 有沒有對應的字節
/4883 ec08 488b...
在上面的窗格中
搜索這些字節形態
好像找到了對應關係
具體怎麼對應的呢?
這台計算機用的是什麼指令集呢?
什麼是指令集來着?
指令集
指令集就是指令的集合
指令集也叫計算機的架構
不同架構的 cpu 有不同的指令集
我們目前的這個瀏覽器裡面的系統用的是 x86-64
除此之外 arm、MIPS、RISC-V 也是常用的指令集
指令助記符和機器語言到底是則怎麼對應的呢?
回到代碼
代碼會有不同的 section 模塊
入口是 init
作用是初始化initialization
模塊裡面是具體的指令
比如第一句 48 83 ec 08
為什麼48 83 就可以代表減法
這是誰規定的呢?
查看指令集
這是cpu架構規定的
首先要明確到當前機器cpu的架構
反匯編裡面說是x86-64
到shell裡面驗證一下
當前機器所用的架構指令集確實是x86_64
這是誰的架構呢?
搜索
不會了就去搜索😄
去intel官網找指令集
查詢x86_64指令集
找到cpu的手冊
https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
可以找到指令和二進制狀態之間的關係麼?
先要找到x86-64指令集中 48 83 這條指令
注意上圖中
100B中的B是0或1
100B可以是1000
也可以是1001
這確實是一條減法指令
而且是8位立即數和寄存器的減法運算
逐步搜索
找起來真的很費勁
48 83 ec 08 對應 sub $0x8,%rsp
確實是一條減法指令
確實是8位立即數和寄存器的減法運算
和objdump的結果是一致的
廢話!!!😠
除了減法指令sub之外
還有什麼別的指令呢?
各種cpu指令
指令那可還有很多的
有運算的
有移位的
加減乘除都有
這些指令的集合就是指令集
指令集就是cpu運行的基礎!
這些機器語言的指令不能在別的指令集架構上運行麼?
移植 port
想在別的指令集架構上運行程序
就需要移植(port)
移植(port)指的是從一種指令集移植到另一種指令集
從這個詞的詞源
移植
port 港口
可以看出歐美的航海文化基礎
也可以看出我們的農耕文化基礎
不移植會如何呢?
不移植
這是playstation2的架構圖
cpu是mips架構的
不移植的話
就是讓x86架構的pc
去直接執行這些基於mips架構的的0101...
就像讓一個意大利泥瓦匠看一份中文寫成的烹飪書來砌牆
雞同鴨講
驢唇不對馬嘴
0101的文件執行出來全是亂的
完全不能用
而且不全是軟件的問題
也涉及到硬件等方面
可能某個寄存器在新架構中根本就不存在
架構師
這個時候架構師要解決相當多的問題
很不容易的
落實到我們的python3.8遊樂場
我們的python3.8就是這樣的一系列的cpu指令
可以解釋py文件的
python3.8 又是如何解釋py文件的來着?
python3 執行過程
不管是python3這個遊樂場
還是hello.py這個python程序
都在我們的硬盤上
先得把文件從硬盤讀到內存
python3 執行的過程大致是這樣
先把python3.8這個主解釋器加載到內存中
然後在x86-64的cpu上執行
模擬出一台python虛擬機
準備開始對py文件解釋執行
先編譯
然後把參數 hello.py 這個需要執行的程序加載到內存
詞法分析 得到 詞流(token stream)
語法分析 得到 抽象語法樹(Abstract Syntax Tree)
編譯 得到 字節碼 (bytecode)
也就是編譯後的pyc文件
解釋執行
不過這個pyc指令文件
是基於python虛擬機的虛擬cpu的指令集的
需要放到模擬好的python虛擬機中
一條條指令進行執行
換句話說
簡化版的 hello.py 的執行過程是:
給了 python3 一個參數 hello.py
使用 python3 這個解釋器來解釋執行 hello.py
hello.py中的語句一句句地依次解釋執行
全解釋完成後
退出python這個程序
把控制權交回到shell
這些都是基於解釋器python3.8的
先編譯成python虛擬機的字節碼
然後用python虛擬機解釋直接執行
所謂的解釋器也是
而解釋器(python3)是在不同系統不同架構的cpu語言上運行的
那不同的系統、cpu架構
python都能正確地解釋麼?
架構的層次
不同架構的 cpu 都可以運行 python
risc-v
arm
x64
mips
龍芯
不同系統的環境都可以運行 python
win
mac
linux
freebsd
跨架構跨平台原理
由於python3可以運行在不同的cpu架構和系統上
所以同樣的py文件被加載之後
python程序可以對py文件跨架構、跨系統進行解釋執行
一次編寫到處運行
不同的架構
二進制對應的匯編指令都不一樣
怎麼能正確解釋執行同樣的python程序呢?
跨架構跨平台原理
/usr/bin/python3.8 本身是二進制文件
是基於當前操作系統當前架構編譯出來的可執行二進制文件
不同的架構有不同的編譯器
不同的編譯器編譯出來的python3.8
是不同的二進制指令序列
python3.8 構建了一個運行時環境
這個環境可以解釋讀到的python語句
把python語句翻譯成系統能讀懂輸入輸出
翻譯成當前架構能夠執行的代碼
然後邊解釋邊執行
恭喜您完成了非常燒腦一個實驗!
我們去總結吧!!!
總結
python3 的程序是一個 5.3M 的可執行文件
objdump -d ~/python3 > python3.asm
python3 裡面全都是 cpu 指令
可以執行的那種
我們可以把指令對應的匯編找到
匯編語句是和當前機器架構的指令集相關的
uname -a可以查詢指令集
我們執行的過程其實就
系統執行python3這個可執行文件
給了python3一個參數hello.py
python3對於hello.py一句句的解釋執行
在顯示器輸出了hello world
python3執行完畢
把控制權交回給 shell
這就是我們執行hello.py的過程
為什麼我們學編程總是從hello world開始呢?🤔
我們下次再說!👋
藍橋->https://www.lanqiao.cn/teacher/3584
github->https://github.com/overmind1980/oeasy-python-tutorial
gitee->https://gitee.com/overmind1980/oeasypython
視頻->https://www.bilibili.com/video/BV1CU4y1Z7gQ