oeasy教您玩轉(zhuǎn)python - 005 - # 程序本質(zhì) - 這是個(gè)勸退高峰,堅(jiān)持到下次hello world。
程序本質(zhì)
回憶上次內(nèi)容
py
的程序是按照順序一行行挨排解釋執(zhí)行的
我們可以
python3 -m pdb hello.py
來(lái)對(duì)程序調(diào)試調(diào)試的目的是去除
bug
別害怕
bug
bug
會(huì)有提示我們也就知道如何
debug
調(diào)試python3
到底是個(gè)啥呢???python3
又是怎么解釋hello.py
的?我們得先來(lái)看看 游樂(lè)場(chǎng)
python3
到底是個(gè)啥?
python3
到底是個(gè)啥?
什么是python3
sudo whatis python3
如果不能解釋
sudo unminimize
更新manual更新時(shí)間比較長(zhǎng),更新結(jié)束后再
sudo whatis python3


幫助手冊(cè)告訴我們
python3 是一種解釋性的、可交互的、面向?qū)ο蟮木幊陶Z(yǔ)言
python3 在哪?
python3在哪里?
whereis python3
可執(zhí)行的這個(gè)東西到底在哪?
which python3

系統(tǒng)告訴我們
python3 這個(gè)游樂(lè)場(chǎng)在硬盤(pán)上
路徑是/usr/bin/python3
在文件管理器中查看

這個(gè) python3 是一個(gè)軟鏈接文件
他指向 python3.8
python3 就是 python3.8
他倆存在一個(gè)位置
都在 /usr/bin 里面
python3.8
就在硬盤(pán)里呆著usr 是 unix software resource
bin 是二進(jìn)制 binary
python3.8 是這個(gè)文件的名稱
位置就在/usr/bin/python3.8
在運(yùn)行命令的時(shí)候
把這個(gè)文件從硬盤(pán)裝載到內(nèi)存
然后用 cpu 開(kāi)始逐行執(zhí)行文件內(nèi)容中的指令
研究 python3
把python3拷貝到~(當(dāng)前用戶文件夾)
cp /usr/bin/python3 ~
確認(rèn)python3已經(jīng)拷到~(當(dāng)前用戶文件夾)
ls ~/python3
查看python3文件細(xì)節(jié)
ls -lah ~/python3

#試著運(yùn)行用戶文件夾下的這個(gè)剛考過(guò)來(lái)的python3~/python3
python3 指向的 python3.8 只有 5.3M
這個(gè)可執(zhí)行文件怎么這么小?
5.3M 這也就是一張照片的大小
一年前的 Python3.5 只有 4.3M
更小
目前這 5.3M 的 Python3 里面到底有什么呢???
打開(kāi)看看!?。??
打開(kāi) python3
用vi打開(kāi)這個(gè)剛拷貝過(guò)來(lái)的python3vi ~/python3
這個(gè)樣子看起來(lái)
全是亂碼
完全看不懂啊

這個(gè)東西我們確實(shí)看不懂
但是有人能看懂
誰(shuí)呢?
機(jī)器指令
這個(gè)亂碼我們看不懂
但是cpu能看懂
這就是cpu的一條條的指令
都是二進(jìn)制形式的
我們嘗試把這種文本形式轉(zhuǎn)化為二進(jìn)制

左下角:進(jìn)入命令行模式
:%!xxd
我們可以看到這個(gè)文件的二進(jìn)制形態(tài)%
是指的對(duì)于所有行的范圍!是執(zhí)行外部命令
xxd
指的是轉(zhuǎn)化為 16 進(jìn)制形式這個(gè) xxd 命令 到底什么意思??
:q!
退回到 shell 來(lái)看一下
關(guān)于 xxd
man xxd
查詢 xxd 的幫助手冊(cè)

xxd 可以查看文件的二進(jìn)制形態(tài)
:xxd –r
可以還原回去 ??進(jìn)入
vi ~/python3
:%!xxd
:%!xxd –r
反復(fù)橫跳
對(duì)比
重新
vi ~/python3
:%!xxd
一行是(16)10 進(jìn)制 ?個(gè)字節(jié)
G到最后一行
總共有 343148 行
這就是 真正的機(jī)器語(yǔ)言??
cpu對(duì)應(yīng)的指令和數(shù)據(jù)
存在硬盤(pán)上 01010 的二進(jìn)制可執(zhí)行指令??!
這些指令其實(shí)都能執(zhí)行?。?!
可是這個(gè)指令我們看不懂怎么辦???
查看 python3 匯編指令
把python3對(duì)應(yīng)的機(jī)器語(yǔ)言輸出為匯編指令形式objdump -d ~/python3 > ~/python3.asm分窗口分別打開(kāi)打開(kāi)python3 和 python3.asmvi -o python3 python3.asm
下圖中上半部分是機(jī)器代碼
執(zhí)行
:%!xxd
以 16 進(jìn)制形式顯示

下半部分是得到的相應(yīng)匯編指令
這個(gè)過(guò)程就是反匯編??
查找對(duì)應(yīng)關(guān)系

423000
就是初始的 cpu 開(kāi)始執(zhí)行指令的地址第一行
endbr64 意味著 64位結(jié)束分支
下面的是cpu指令對(duì)應(yīng)的機(jī)器語(yǔ)言
前面可以是數(shù)據(jù)
第二行
/4883
找到上下的對(duì)應(yīng)關(guān)系也就是第一條執(zhí)行的匯編指令
匯編指令是計(jì)算機(jī) cpu 指令的助記符
指令的集合就是計(jì)算機(jī)的架構(gòu)
架構(gòu)也叫指令集
那什么叫做指令集呢?
架構(gòu)
不同架構(gòu)的 cpu 會(huì)有不同的指令集
我們目前的這個(gè)是
x86-64
除此之外
arm
、MIPS
、RISC-V
也是常用的指令集不同的架構(gòu)想運(yùn)行相同的程序就需要移植
就像讓一個(gè)意大利泥瓦匠看一份中文寫(xiě)成的烹飪書(shū)來(lái)砌墻
雞同鴨講
驢唇不對(duì)馬嘴
如果不移植的話

這里會(huì)有不同的
section
模塊最初的是
init
作用是初始化initialization
模塊里面是具體的指令
這是一條什么樣的指令呢?
比如第一句
48 83 ec 08
查看指令集
想要指定機(jī)器語(yǔ)言對(duì)應(yīng)的指令
首先要了解到當(dāng)前機(jī)器所用的指令集
可以在
shell
用uname -a
進(jìn)行查看本機(jī)所用的指令集

當(dāng)前機(jī)器所用的架構(gòu)指令集是x86_64
那么48 83 ec 08 對(duì)應(yīng) 什么指令呢?
查詢x86_64指令集
找到cpu的手冊(cè)
https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
查找
48 83 ec 08
對(duì)應(yīng)哪一條指令

找起來(lái)真的很費(fèi)勁
48 83 ec 08
對(duì)應(yīng)sub $0x8,%rsp
是一條減法指令
和objdump的結(jié)果是一致的
廢話?。。?/p>
除了減法指令sub之外,還有什么指令呢?
各種cpu指令

有運(yùn)算的
有移位的
加減乘除都有
這就是cpu運(yùn)行的基礎(chǔ)!
那么python3 運(yùn)行 hello.py的過(guò)程又是如何的呢?
python3 執(zhí)行過(guò)程
不管是python3這個(gè)游樂(lè)場(chǎng)
還是hello.py這個(gè)python程序
都在我們的硬盤(pán)上
從硬盤(pán)讀到內(nèi)存
python3 執(zhí)行的過(guò)程大致是這樣
首先把python3這個(gè)主程序加載到內(nèi)存中
然后把參數(shù)
hello.py
這個(gè)需要執(zhí)行的程序加載到內(nèi)存并生成一棵語(yǔ)法樹(shù)比如 print("hello")
這就是一個(gè)語(yǔ)句
分析
hello.py
詞法結(jié)構(gòu)把文件分成一個(gè)個(gè)
單詞
通過(guò)單詞組成表達(dá)式
通過(guò)表達(dá)式組成語(yǔ)句
對(duì)于生成的語(yǔ)法樹(shù)
進(jìn)行解釋并且執(zhí)行

換句話說(shuō)
簡(jiǎn)化版的 hello.py 的執(zhí)行過(guò)程是:
也就是把硬盤(pán)上的文件裝載到內(nèi)存
python3
完成后續(xù)工作系統(tǒng)執(zhí)行
python3
這個(gè)可執(zhí)行文件給了
python3
一個(gè)參數(shù)hello.py
使用
python3
這個(gè)解釋器來(lái)解釋hello.py
一句句地依次解釋執(zhí)行
全解釋完成后
退出python這個(gè)程序
把控制權(quán)交回到shell

這些都是基于解釋器python3.8的
而解釋器是用目標(biāo)架構(gòu)的機(jī)器語(yǔ)言直接在cpu上運(yùn)行的
那不同的cpu架構(gòu)、不同的系統(tǒng),python都能正確地解釋么?
架構(gòu)的層次

不同架構(gòu)的 cpu 都可以運(yùn)行 python
risc-v
arm
x64
mips
龍芯
不同系統(tǒng)的環(huán)境都可以運(yùn)行 python
win
mac
linux
由于python3可以運(yùn)行在不同的cpu架構(gòu)和系統(tǒng)上
python程序可以跨架構(gòu)、跨系統(tǒng)進(jìn)行解釋執(zhí)行
不同的架構(gòu)
二進(jìn)制對(duì)應(yīng)的匯編指令都不一樣
怎么能正確解釋執(zhí)行同樣的python程序呢?
跨架構(gòu)跨平臺(tái)原理
因?yàn)?
/usr/bin/python3.8
本身是二進(jìn)制文件是基于當(dāng)前操作系統(tǒng)當(dāng)前架構(gòu)編譯出來(lái)的可執(zhí)行二進(jìn)制文件
不同的架構(gòu)有不同的編譯器
不同的編譯器編譯出來(lái)的python解釋器對(duì)應(yīng)不同的二進(jìn)制指令序列
python3.8
構(gòu)建了一個(gè)運(yùn)行時(shí)環(huán)境這個(gè)環(huán)境可以解釋讀到的
python語(yǔ)句
把
python語(yǔ)句
翻譯成系統(tǒng)能讀懂輸入輸出翻譯成當(dāng)前物理架構(gòu)能夠執(zhí)行的代碼
然后邊解釋邊執(zhí)行
總結(jié)
python3
的程序是一個(gè) 5.3M 的可執(zhí)行文件objdump -d ~/python3 > python3.asm
python3
里面全都是 cpu 指令可以執(zhí)行的那種
我們可以把指令對(duì)應(yīng)的匯編找到
匯編語(yǔ)句是和當(dāng)前機(jī)器架構(gòu)的指令集相關(guān)的
uname -a
可以查詢指令集我們執(zhí)行的過(guò)程其實(shí)就
系統(tǒng)執(zhí)行
python3
這個(gè)可執(zhí)行文件給了
python3
一個(gè)參數(shù)hello.py
python3
對(duì)于hello.py
一句句的解釋執(zhí)行在顯示器輸出了
hello world
python3
執(zhí)行完畢把控制權(quán)交回給 shell
這就是我們執(zhí)行
hello world
的過(guò)程為什么我們學(xué)編程總是從
hello world
開(kāi)始呢???我們下次再說(shuō)!*