close

程序本質回憶上次內容

我們把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

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 鑽石舞台 的頭像
    鑽石舞台

    鑽石舞台

    鑽石舞台 發表在 痞客邦 留言(0) 人氣()