oeasy教您玩转python - 005 - # 程序本质 - 这是个劝退高峰,坚持到下次hello world。
程序本质
回忆上次内容
py
的程序是按照顺序一行行挨排解释执行的
我们可以
python3 -m pdb hello.py
来对程序调试调试的目的是去除
bug
别害怕
bug
bug
会有提示我们也就知道如何
debug
调试python3
到底是个啥呢?🤔python3
又是怎么解释hello.py
的?我们得先来看看 游乐场
python3
到底是个啥?
python3
到底是个啥?
什么是python3
sudo whatis python3
如果不能解释
sudo unminimize
更新manual更新时间比较长,更新结束后再
sudo whatis python3


帮助手册告诉我们
python3 是一种解释性的、可交互的、面向对象的编程语言
python3 在哪?
python3在哪里?
whereis python3
可执行的这个东西到底在哪?
which python3

系统告诉我们
python3 这个游乐场在硬盘上
路径是/usr/bin/python3
在文件管理器中查看

这个 python3 是一个软链接文件
他指向 python3.8
python3 就是 python3.8
他俩存在一个位置
都在 /usr/bin 里面
python3.8
就在硬盘里呆着usr 是 unix software resource
bin 是二进制 binary
python3.8 是这个文件的名称
位置就在/usr/bin/python3.8
在运行命令的时候
把这个文件从硬盘装载到内存
然后用 cpu 开始逐行执行文件内容中的指令
研究 python3
把python3拷贝到~(当前用户文件夹)
cp /usr/bin/python3 ~
确认python3已经拷到~(当前用户文件夹)
ls ~/python3
查看python3文件细节
ls -lah ~/python3

#试着运行用户文件夹下的这个刚考过来的python3~/python3
python3 指向的 python3.8 只有 5.3M
这个可执行文件怎么这么小?
5.3M 这也就是一张照片的大小
一年前的 Python3.5 只有 4.3M
更小
目前这 5.3M 的 Python3 里面到底有什么呢?🤔
打开看看!!!👊
打开 python3
用vi打开这个刚拷贝过来的python3vi ~/python3
这个样子看起来
全是乱码
完全看不懂啊

这个东西我们确实看不懂
但是有人能看懂
谁呢?
机器指令
这个乱码我们看不懂
但是cpu能看懂
这就是cpu的一条条的指令
都是二进制形式的
我们尝试把这种文本形式转化为二进制

左下角:进入命令行模式
:%!xxd
我们可以看到这个文件的二进制形态%
是指的对于所有行的范围!是执行外部命令
xxd
指的是转化为 16 进制形式这个 xxd 命令 到底什么意思🤔
:q!
退回到 shell 来看一下
关于 xxd
man xxd
查询 xxd 的帮助手册

xxd 可以查看文件的二进制形态
:xxd –r
可以还原回去 😉进入
vi ~/python3
:%!xxd
:%!xxd –r
反复横跳
对比
重新
vi ~/python3
:%!xxd
一行是(16)10 进制 个字节
G到最后一行
总共有 343148 行
这就是 真正的机器语言🤭
cpu对应的指令和数据
存在硬盘上 01010 的二进制可执行指令!!
这些指令其实都能执行!!!
可是这个指令我们看不懂怎么办?🤔
查看 python3 汇编指令
把python3对应的机器语言输出为汇编指令形式objdump -d ~/python3 > ~/python3.asm分窗口分别打开打开python3 和 python3.asmvi -o python3 python3.asm
下图中上半部分是机器代码
执行
:%!xxd
以 16 进制形式显示

下半部分是得到的相应汇编指令
这个过程就是反汇编🧐
查找对应关系

423000
就是初始的 cpu 开始执行指令的地址第一行
endbr64 意味着 64位结束分支
下面的是cpu指令对应的机器语言
前面可以是数据
第二行
/4883
找到上下的对应关系也就是第一条执行的汇编指令
汇编指令是计算机 cpu 指令的助记符
指令的集合就是计算机的架构
架构也叫指令集
那什么叫做指令集呢?
架构
不同架构的 cpu 会有不同的指令集
我们目前的这个是
x86-64
除此之外
arm
、MIPS
、RISC-V
也是常用的指令集不同的架构想运行相同的程序就需要移植
就像让一个意大利泥瓦匠看一份中文写成的烹饪书来砌墙
鸡同鸭讲
驴唇不对马嘴
如果不移植的话

这里会有不同的
section
模块最初的是
init
作用是初始化initialization
模块里面是具体的指令
这是一条什么样的指令呢?
比如第一句
48 83 ec 08
查看指令集
想要指定机器语言对应的指令
首先要了解到当前机器所用的指令集
可以在
shell
用uname -a
进行查看本机所用的指令集

当前机器所用的架构指令集是x86_64
那么48 83 ec 08 对应 什么指令呢?
查询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
查找
48 83 ec 08
对应哪一条指令

找起来真的很费劲
48 83 ec 08
对应sub $0x8,%rsp
是一条减法指令
和objdump的结果是一致的
废话!!!
除了减法指令sub之外,还有什么指令呢?
各种cpu指令

有运算的
有移位的
加减乘除都有
这就是cpu运行的基础!
那么python3 运行 hello.py的过程又是如何的呢?
python3 执行过程
不管是python3这个游乐场
还是hello.py这个python程序
都在我们的硬盘上
从硬盘读到内存
python3 执行的过程大致是这样
首先把python3这个主程序加载到内存中
然后把参数
hello.py
这个需要执行的程序加载到内存并生成一棵语法树比如 print("hello")
这就是一个语句
分析
hello.py
词法结构把文件分成一个个
单词
通过单词组成表达式
通过表达式组成语句
对于生成的语法树
进行解释并且执行

换句话说
简化版的 hello.py 的执行过程是:
也就是把硬盘上的文件装载到内存
python3
完成后续工作系统执行
python3
这个可执行文件给了
python3
一个参数hello.py
使用
python3
这个解释器来解释hello.py
一句句地依次解释执行
全解释完成后
退出python这个程序
把控制权交回到shell

这些都是基于解释器python3.8的
而解释器是用目标架构的机器语言直接在cpu上运行的
那不同的cpu架构、不同的系统,python都能正确地解释么?
架构的层次

不同架构的 cpu 都可以运行 python
risc-v
arm
x64
mips
龙芯
不同系统的环境都可以运行 python
win
mac
linux
由于python3可以运行在不同的cpu架构和系统上
python程序可以跨架构、跨系统进行解释执行
不同的架构
二进制对应的汇编指令都不一样
怎么能正确解释执行同样的python程序呢?
跨架构跨平台原理
因为
/usr/bin/python3.8
本身是二进制文件是基于当前操作系统当前架构编译出来的可执行二进制文件
不同的架构有不同的编译器
不同的编译器编译出来的python解释器对应不同的二进制指令序列
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 world
的过程为什么我们学编程总是从
hello world
开始呢?🤔我们下次再说!*