MicroPython字节码文件——mpy文件解析

MicroPython字节码文件——mpy文件解析比如字节码为 0a416c 第一个字节 0a 最高位为 0 表示无后续字节 则 qstr 长度为 a 2 5

大家好,欢迎来到IT知识分享网。

参考文档:MicroPython .mpy files

前置注意点

  • mpy文件的二进制文件是一种嵌套格式。先描述外层模块,然后描述子模块。
  • 使用vint(变长编码)表示整数,当前字节最高位置1表示还有后续字节。
  • 不同版本的MicroPython对应的mpy文件格式不一定兼容。

MicroPython项目提供了一个脚本mpy-tool.py来解析mpy文件的内容,所以想知道mpy文件的结构、具体包含了哪些信息,可以阅读下这个脚本源码。

mpy文件内容概览

Header

qstr and constant objects tables

在这里插入图片描述

qstr表

在这个表中,每个qstr对象都由一个表示长度的vint和后续数据组成。

qstr unit

在这里插入图片描述
注意,mpy文件里的len是实际qstr长度的2倍。这是由于最低位用来判别是否为static qstr。比如字节码为 0a 416c 6963 6500,第一个字节0a最高位为0,表示无后续字节,则qstr长度为a/2 = 5。后面跟着5个字节为qstr的内容“Alice”,第六个字节00表示字符串的结束。

def read_qstr(reader, segments): start_pos = reader.tell() ln = reader.read_uint() if ln & 1: # static qstr q = global_qstrs.get_by_index(ln >> 1) segments.append(MPYSegment(MPYSegment.META, q.str, start_pos, start_pos)) return q ln >>= 1 start_pos = reader.tell() data = str_cons(reader.read_bytes(ln), "utf8") reader.read_byte() # read and discard null terminator segments.append(MPYSegment(MPYSegment.QSTR, data, start_pos, reader.tell())) return global_qstrs.add(data) 

obj表 //todo: 待补充

def read_obj(reader, segments): obj_type = reader.read_byte() if obj_type == MP_PERSISTENT_OBJ_FUN_TABLE: return MPFunTable() elif obj_type == MP_PERSISTENT_OBJ_NONE: return None elif obj_type == MP_PERSISTENT_OBJ_FALSE: return False elif obj_type == MP_PERSISTENT_OBJ_TRUE: return True elif obj_type == MP_PERSISTENT_OBJ_ELLIPSIS: return Ellipsis elif obj_type == MP_PERSISTENT_OBJ_TUPLE: ln = reader.read_uint() return tuple(read_obj(reader, segments) for _ in range(ln)) else: ln = reader.read_uint() start_pos = reader.tell() buf = reader.read_bytes(ln) if obj_type in (MP_PERSISTENT_OBJ_STR, MP_PERSISTENT_OBJ_BYTES): reader.read_byte() # read and discard null terminator if obj_type == MP_PERSISTENT_OBJ_STR: obj = str_cons(buf, "utf8") if len(obj) < PERSISTENT_STR_INTERN_THRESHOLD: if not global_qstrs.find_by_str(obj): global_qstrs.add(obj) elif obj_type == MP_PERSISTENT_OBJ_BYTES: obj = buf elif obj_type == MP_PERSISTENT_OBJ_INT: obj = int(str_cons(buf, "ascii"), 10) elif obj_type == MP_PERSISTENT_OBJ_FLOAT: obj = float(str_cons(buf, "ascii")) elif obj_type == MP_PERSISTENT_OBJ_COMPLEX: obj = complex(str_cons(buf, "ascii")) else: raise MPYReadError(reader.filename, "corrupt .mpy file") segments.append(MPYSegment(MPYSegment.OBJ, obj, start_pos, reader.tell())) return obj 

obj对象类型

raw code header

在这里插入图片描述
字节码的头部是一个vint类型,最低两位表示代码类型

kind_len = reader.read_uint() # 读取一个vint kind = (kind_len & 3) + MP_CODE_BYTECODE # 取低2位加上MP_CODE_BYTECODE个偏移量 

4种代码类型定义如下

MP_CODE_BYTECODE = 2 MP_CODE_NATIVE_PY = 3 MP_CODE_NATIVE_VIPER = 4 MP_CODE_NATIVE_ASM = 5 

低第三位表示有无子模块,0表示无子模块,1表示有子模块。

has_children = (kind_len >> 2) & 1 

示例

最后放个py源码和生成的mpy字节码供大家参考学习。

class Wallet: def __init__(self, owner_name, balance=0): self.owner_name = owner_name self.balance = balance def deposit(self, amount): if amount > 0: self.balance += amount print(f"Deposited ${ 
      amount}. New balance: ${ 
      self.balance}") else: print("Invalid deposit amount.") def withdraw(self, amount): if amount > 0 and self.balance >= amount: self.balance -= amount print(f"Withdrew ${ 
      amount}. New balance: ${ 
      self.balance}") else: print("Invalid or insufficient funds for withdrawal.") def transfer(self, recipient_wallet, amount): if self.balance >= amount and recipient_wallet is not self: if amount > 0: self.withdraw(amount) recipient_wallet.deposit(amount) print(f"Transferred ${ 
      amount} to { 
      recipient_wallet.owner_name}.") else: print("Invalid transfer amount.") else: print("Insufficient funds or invalid recipient.") def check_balance(self): print(f"Current balance: ${ 
      self.balance}") # Example usage: # Create two wallet instances wallet1 = Wallet("Alice", 100) wallet2 = Wallet("Bob", 50) # Deposit money into wallet1 wallet1.deposit(50) # Withdraw money from wallet1 wallet1.withdraw(20) # Transfer money from wallet1 to wallet2 wallet1.transfer(wallet2, 30) # Check balance of wallet1 and wallet2 wallet1.check_balance() wallet2.check_balance() 
00000000: 4d06 001f 1608 1c77 616c 6c65 745f 7465 M......wallet_te wallet_test.py 00000010: 7374 2e70 7900 0f0c 5761 6c6c 6574 000a st.py...Wallet.. <module> Wallet 00000020: 416c 6963 6500 0642 6f62 000e 6465 706f Alice..Bob..depo Alice Bob deposit 00000030: 7369 7400 1077 6974 6864 7261 7700 1074 sit..withdraw..t withdraw transfer 00000040: 7261 6e73 6665 7200 1a63 6865 636b 5f62 ransfer..check_b check_balance 00000050: 616c 616e 6365 0023 146f 776e 6572 5f6e alance.#.owner_n __init__ owner_name 00000060: 616d 6500 0e62 616c 616e 6365 0081 290e ame..balance..). balance format 00000070: 7761 6c6c 6574 3100 0e77 616c 6c65 7432 wallet1..wallet2 wallet1 wallet2 00000080: 002f 2d35 8213 0c61 6d6f 756e 7400 8177 ./-5...amount..w __name__ __module__ __qualname__ self amount print 00000090: 2072 6563 6970 6965 6e74 5f77 616c 6c65 recipient_walle recipient_wallet 000000a0: 7400 051f 4465 706f 7369 7465 6420 247b t...Deposited ${ Deposited ${}. New balance: ${ 
    } 000000b0: 7d2e 204e 6577 2062 616c 616e 6365 3a20 }. New balance: 000000c0: 247b 7d00 0517 496e 7661 6c69 6420 6465 ${ 
    }...Invalid de Invalid deposit amount. 000000d0: 706f 7369 7420 616d 6f75 6e74 2e00 051e posit amount.... 000000e0: 5769 7468 6472 6577 2024 7b7d 2e20 4e65 Withdrew ${ 
    }. Ne Withdrew ${ 
    }. New balance: ${ 
    } 000000f0: 7720 6261 6c61 6e63 653a 2024 7b7d 0005 w balance: ${ 
    }.. 00000100: 2d49 6e76 616c 6964 206f 7220 696e 7375 -Invalid or insu Invalid or insufficient funds for withdrawal. 00000110: 6666 6963 6965 6e74 2066 756e 6473 2066 fficient funds f 00000120: 6f72 2077 6974 6864 7261 7761 6c2e 0005 or withdrawal... 00000130: 1654 7261 6e73 6665 7272 6564 2024 7b7d .Transferred ${ 
    } Transferred ${ 
    } to { 
    }. 00000140: 2074 6f20 7b7d 2e00 0518 496e 7661 6c69 to { 
    }....Invali Invalid transfer amount. 00000150: 6420 7472 616e 7366 6572 2061 6d6f 756e d transfer amoun 00000160: 742e 0005 2849 6e73 7566 6669 6369 656e t...(Insufficien Insufficient funds or invalid recipient. 00000170: 7420 6675 6e64 7320 6f72 2069 6e76 616c t funds or inval 00000180: 6964 2072 6563 6970 6965 6e74 2e00 0514 id recipient.... 00000190: 4375 7272 656e 7420 6261 6c61 6e63 653a Current balance: Current balance: ${ 
    } 000001a0: 2024 7b7d 0085 2418 1201 8923 2b6a 6968 ${ 
    }..$....#+jih <module> 000001b0: 6a27 5432 0010 0234 0216 0211 0210 0322 j'T2...4......." 000001c0: 8064 3402 160d 1102 1004 2232 3402 160e .d4......."24... 000001d0: 110d 1405 2232 3601 5911 0d14 0694 3601 ...."26.Y.....6. 000001e0: 5911 0d14 0711 0e9e 3602 5911 0d14 0836 Y.......6.Y....6 000001f0: 0059 110e 1408 3600 5951 6301 8274 0814 .Y....6.YQc..t.. Wallet 00000200: 0228 6820 8407 8407 840b 110f 1610 1002 .(h ............ 00000210: 1611 802a 0153 3300 1609 3201 1605 3202 ...*.S3...2...2. 00000220: 1606 3203 1607 3204 1608 5163 0581 18a3 ..2...2...Qc.... __init__ 00000230: 010c 0912 0a0b 4024 b1b0 180a b2b0 180b ......@$........ 00000240: 5163 8310 3210 0512 1360 6025 2951 b180 Qc..2....``%)Q.. deposit 00000250: d844 5ab0 5713 0bb1 e55a 180b 1214 2300 .DZ.W....Z....#. 00000260: 140c b1b0 130b 3602 3401 5942 4712 1423 ......6.4.YBG..# 00000270: 0134 0159 5163 8348 3210 0612 1380 0d2c .4.YQc.H2......, withdraw 00000280: 2951 b180 d844 61b0 130b b1db 445a b057 )Q...Da.....DZ.W 00000290: 130b b1e6 5a18 0b12 1423 0214 0cb1 b013 ....Z....#...... 000002a0: 0b36 0234 0159 4247 1214 2303 3401 5951 .6.4.YBG..#.4.YQ 000002b0: 6385 083b 1807 1215 1380 142d 2527 2751 c..;.......-%''Q transfer 000002c0: 49b0 130b b2db 4473 b1b0 ded3 446d b280 I.....Ds....Dm.. 000002d0: d844 5fb0 1406 b236 0159 b114 05b2 3601 .D_....6.Y....6. 000002e0: 5912 1423 0414 0cb2 b113 0a36 0234 0159 Y..#.......6.4.Y  000002f0: 4247 1214 2305 3401 5942 4712 1423 0634 BG..#.4.YBG..#.4  00000300: 0159 5163 8130 2108 0812 801f 1214 2307 .YQc.0!.......#. check_balance 00000310: 140c b013 0b36 0134 0159 5163 .....6.4.YQc mpy_source_file: wallet_test.mpy source_file: wallet_test.py header: 4d:06:00:1f qstr_table[22]: wallet_test.py <module> Wallet Alice Bob deposit withdraw transfer check_balance __init__ owner_name balance format wallet1 wallet2 __name__ __module__ __qualname__ self amount print recipient_wallet obj_table: ['Deposited ${}. New balance: ${}', 'Invalid deposit amount.', 'Withdrew ${}. New balance: ${}', 'Invalid or insufficient funds for withdrawal.', 'Transferred ${} to {}.', 'Invalid transfer amount.', 'Insufficient funds or invalid recipient.', 'Current balance: ${}'] simple_name: <module> raw bytecode: 84 18:12:01:89:23:2b:6a:69:68:6a:27:54:32:00:10:02:34:02:16:02:11:02:10:03:22:80:64:34:02:16:0d:11:02:10:04:22:32:34:02:16:0e:11:0d:14:05:22:32:36:01:59:11:0d:14:06:94:36:01:59:11:0d:14:07:11:0e:9e:36:02:59:11:0d:14:08:36:00:59:11:0e:14:08:36:00:59:51:63 prelude: (4, 0, 0, 0, 0, 0) args: [] line info: 89:23:2b:6a:69:68:6a:27 54 LOAD_BUILD_CLASS 32:00 MAKE_FUNCTION 0 10:02 LOAD_CONST_STRING Wallet 34:02 CALL_FUNCTION 2 16:02 STORE_NAME Wallet 11:02 LOAD_NAME Wallet 10:03 LOAD_CONST_STRING Alice 22:80:64 LOAD_CONST_SMALL_INT 100 34:02 CALL_FUNCTION 2 16:0d STORE_NAME wallet1 11:02 LOAD_NAME Wallet 10:04 LOAD_CONST_STRING Bob 22:32 LOAD_CONST_SMALL_INT 50 34:02 CALL_FUNCTION 2 16:0e STORE_NAME wallet2 11:0d LOAD_NAME wallet1 14:05 LOAD_METHOD deposit 22:32 LOAD_CONST_SMALL_INT 50 36:01 CALL_METHOD 1 59 POP_TOP 11:0d LOAD_NAME wallet1 14:06 LOAD_METHOD withdraw 94 LOAD_CONST_SMALL_INT 20 36:01 CALL_METHOD 1 59 POP_TOP 11:0d LOAD_NAME wallet1 14:07 LOAD_METHOD transfer 11:0e LOAD_NAME wallet2 9e LOAD_CONST_SMALL_INT 30 36:02 CALL_METHOD 2 59 POP_TOP 11:0d LOAD_NAME wallet1 14:08 LOAD_METHOD check_balance 36:00 CALL_METHOD 0 59 POP_TOP 11:0e LOAD_NAME wallet2 14:08 LOAD_METHOD check_balance 36:00 CALL_METHOD 0 59 POP_TOP 51 LOAD_CONST_NONE 63 RETURN_VALUE children: ['Wallet'] simple_name: Wallet raw bytecode: 46 08:14:02:28:68:20:84:07:84:07:84:0b:11:0f:16:10:10:02:16:11:80:2a:01:53:33:00:16:09:32:01:16:05:32:02:16:06:32:03:16:07:32:04:16:08:51:63 prelude: (2, 0, 0, 0, 0, 0) args: [] line info: 28:68:20:84:07:84:07:84:0b 11:0f LOAD_NAME __name__ 16:10 STORE_NAME __module__ 10:02 LOAD_CONST_STRING Wallet 16:11 STORE_NAME __qualname__ 80 LOAD_CONST_SMALL_INT 0 2a:01 BUILD_TUPLE 1 53 LOAD_NULL 33:00 MAKE_FUNCTION_DEFARGS 0 16:09 STORE_NAME __init__ 32:01 MAKE_FUNCTION 1 16:05 STORE_NAME deposit 32:02 MAKE_FUNCTION 2 16:06 STORE_NAME withdraw 32:03 MAKE_FUNCTION 3 16:07 STORE_NAME transfer 32:04 MAKE_FUNCTION 4 16:08 STORE_NAME check_balance 51 LOAD_CONST_NONE 63 RETURN_VALUE children: ['__init__', 'deposit', 'withdraw', 'transfer', 'check_balance'] simple_name: __init__ raw bytecode: 19 a3:01:0c:09:12:0a:0b:40:24:b1:b0:18:0a:b2:b0:18:0b:51:63 prelude: (5, 0, 0, 3, 0, 1) args: ['self', 'owner_name', 'balance'] line info: 40:24 b1 LOAD_FAST 1 b0 LOAD_FAST 0 18:0a STORE_ATTR owner_name b2 LOAD_FAST 2 b0 LOAD_FAST 0 18:0b STORE_ATTR balance 51 LOAD_CONST_NONE 63 RETURN_VALUE children: [] simple_name: deposit raw bytecode: 50 32:10:05:12:13:60:60:25:29:51:b1:80:d8:44:5a:b0:57:13:0b:b1:e5:5a:18:0b:12:14:23:00:14:0c:b1:b0:13:0b:36:02:34:01:59:42:47:12:14:23:01:34:01:59:51:63 prelude: (7, 0, 0, 2, 0, 0) args: ['self', 'amount'] line info: 60:60:25:29:51 b1 LOAD_FAST 1 80 LOAD_CONST_SMALL_INT 0 d8 BINARY_OP 1 __gt__ 44:5a POP_JUMP_IF_FALSE 26 b0 LOAD_FAST 0 57 DUP_TOP 13:0b LOAD_ATTR balance b1 LOAD_FAST 1 e5 BINARY_OP 14 __iadd__ 5a ROT_TWO 18:0b STORE_ATTR balance 12:14 LOAD_GLOBAL print 23:00 LOAD_CONST_OBJ 'Deposited ${}. New balance: ${}' 14:0c LOAD_METHOD format b1 LOAD_FAST 1 b0 LOAD_FAST 0 13:0b LOAD_ATTR balance 36:02 CALL_METHOD 2 34:01 CALL_FUNCTION 1 59 POP_TOP 42:47 JUMP 7 12:14 LOAD_GLOBAL print 23:01 LOAD_CONST_OBJ 'Invalid deposit amount.' 34:01 CALL_FUNCTION 1 59 POP_TOP 51 LOAD_CONST_NONE 63 RETURN_VALUE children: [] simple_name: withdraw raw bytecode: 57 32:10:06:12:13:80:0d:2c:29:51:b1:80:d8:44:61:b0:13:0b:b1:db:44:5a:b0:57:13:0b:b1:e6:5a:18:0b:12:14:23:02:14:0c:b1:b0:13:0b:36:02:34:01:59:42:47:12:14:23:03:34:01:59:51:63 prelude: (7, 0, 0, 2, 0, 0) args: ['self', 'amount'] line info: 80:0d:2c:29:51 b1 LOAD_FAST 1 80 LOAD_CONST_SMALL_INT 0 d8 BINARY_OP 1 __gt__ 44:61 POP_JUMP_IF_FALSE 33 b0 LOAD_FAST 0 13:0b LOAD_ATTR balance b1 LOAD_FAST 1 db BINARY_OP 4 __ge__ 44:5a POP_JUMP_IF_FALSE 26 b0 LOAD_FAST 0 57 DUP_TOP 13:0b LOAD_ATTR balance b1 LOAD_FAST 1 e6 BINARY_OP 15 __isub__ 5a ROT_TWO 18:0b STORE_ATTR balance 12:14 LOAD_GLOBAL print 23:02 LOAD_CONST_OBJ 'Withdrew ${}. New balance: ${}' 14:0c LOAD_METHOD format b1 LOAD_FAST 1 b0 LOAD_FAST 0 13:0b LOAD_ATTR balance 36:02 CALL_METHOD 2 34:01 CALL_FUNCTION 1 59 POP_TOP 42:47 JUMP 7 12:14 LOAD_GLOBAL print 23:03 LOAD_CONST_OBJ 'Invalid or insufficient funds for withdrawal.' 34:01 CALL_FUNCTION 1 59 POP_TOP 51 LOAD_CONST_NONE 63 RETURN_VALUE children: [] simple_name: transfer raw bytecode: 81 3b:18:07:12:15:13:80:14:2d:25:27:27:51:49:b0:13:0b:b2:db:44:73:b1:b0:de:d3:44:6d:b2:80:d8:44:5f:b0:14:06:b2:36:01:59:b1:14:05:b2:36:01:59:12:14:23:04:14:0c:b2:b1:13:0a:36:02:34:01:59:42:47:12:14:23:05:34:01:59:42:47:12:14:23:06:34:01:59:51:63 prelude: (8, 0, 0, 3, 0, 0) args: ['self', 'recipient_wallet', 'amount'] line info: 80:14:2d:25:27:27:51:49 b0 LOAD_FAST 0 13:0b LOAD_ATTR balance b2 LOAD_FAST 2 db BINARY_OP 4 __ge__ 44:73 POP_JUMP_IF_FALSE 51 b1 LOAD_FAST 1 b0 LOAD_FAST 0 de BINARY_OP 7 <is> d3 UNARY_OP 3 <not> 44:6d POP_JUMP_IF_FALSE 45 b2 LOAD_FAST 2 80 LOAD_CONST_SMALL_INT 0 d8 BINARY_OP 1 __gt__ 44:5f POP_JUMP_IF_FALSE 31 b0 LOAD_FAST 0 14:06 LOAD_METHOD withdraw b2 LOAD_FAST 2 36:01 CALL_METHOD 1 59 POP_TOP b1 LOAD_FAST 1 14:05 LOAD_METHOD deposit b2 LOAD_FAST 2 36:01 CALL_METHOD 1 59 POP_TOP 12:14 LOAD_GLOBAL print 23:04 LOAD_CONST_OBJ 'Transferred ${} to {}.' 14:0c LOAD_METHOD format b2 LOAD_FAST 2 b1 LOAD_FAST 1 13:0a LOAD_ATTR owner_name 36:02 CALL_METHOD 2 34:01 CALL_FUNCTION 1 59 POP_TOP 42:47 JUMP 7 12:14 LOAD_GLOBAL print 23:05 LOAD_CONST_OBJ 'Invalid transfer amount.' 34:01 CALL_FUNCTION 1 59 POP_TOP 42:47 JUMP 7 12:14 LOAD_GLOBAL print 23:06 LOAD_CONST_OBJ 'Insufficient funds or invalid recipient.' 34:01 CALL_FUNCTION 1 59 POP_TOP 51 LOAD_CONST_NONE 63 RETURN_VALUE children: [] simple_name: check_balance raw bytecode: 22 21:08:08:12:80:1f:12:14:23:07:14:0c:b0:13:0b:36:01:34:01:59:51:63 prelude: (5, 0, 0, 1, 0, 0) args: ['self'] line info: 80:1f 12:14 LOAD_GLOBAL print 23:07 LOAD_CONST_OBJ 'Current balance: ${}' 14:0c LOAD_METHOD format b0 LOAD_FAST 0 13:0b LOAD_ATTR balance 36:01 CALL_METHOD 1 34:01 CALL_FUNCTION 1 59 POP_TOP 51 LOAD_CONST_NONE 63 RETURN_VALUE children: [] 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/134840.html

(0)
上一篇 2025-07-09 13:20
下一篇 2025-07-09 13:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信