Saturday 1 March 2014

汇编 - python 进制转换器

我最近又回到汇编的怀抱, 在学习过程涉及不少的 2 进制数目, 16 进制数目, 需要好的进制转换器来帮助学习。

网上有不少进制转换器, 但有些 output 是不准确的, 有些放太大的数目会 不准确/hang掉, 再者, 没有分空行, 101111111 连在一起不是人看的。



不准确的 output:




放太大的数目等很久, copy hang掉, 111--..111 也是错误的。




我用 python 撰写了 2, 10, 16 位进制转换器, output 自己喜欢的 style。

#Author: <limkokhole@facebook.com>
#Reference: http://stackoverflow.com/questions/3258330/converting-from-hex-to-binary-without-losing-leading-0s-python

'''
Valid input for all function:
1. No space in between
e.g. b('10 10')
e.g. x('10 10')

Valid input for x():
1. Don't put 0x infront
e.g. x(0x1010), x('0x1010')
2. Always surround by string, bcoz it would error if consists of a, b, c, d, e, f
e.g. x('a')
3. print eflags
e.g. x('1a', f=1)
4. Prettyprint to 3 bits
e.g. x('1a', n=3)
Binary 32 -bit(Pretty): 0000,0000 0000,0000 0000,0000 0001,1010
become
Binary 32 -bit(Pretty): 00 000 000 000 000 000 000 000 000 011 010

Valid input for b():
'''

def chunks(l, n):
return [l[i:i+n] for i in range(0, len(l), n)]

def x(h, n=8, f=False):
#h = 'FA'
split_token = " "
sh = str(h).replace("L", "")
ii = int('1'+str(sh), 16)
orig_b = bin(ii)[3:]
b = orig_b.zfill(32)
br1 = b[::-1]
c = split_token.join(chunks(br1, n))
br2 = c[::-1]
print "Hex:", h, "\n"
if n > 4:
t1 = br2.split(split_token)
t3 = ""
for t2 in t1:
t3 = t3 + ",".join(chunks(t2, 4)) + split_token
br2 = t3
print "Binary ", len(orig_b), "-bit:", orig_b, "\n"
print "Binary ", len(b), "-bit:", b, "\n"
print "Binary ", len(b), "-bit(Pretty):", br2, "\n"
print "Decimal:", int(sh, 16), "\n"
if f:
print flags

def d(di, n=8, f=False):
dx = hex(int(di))
dx = dx.replace("0x", "", 1)
x(dx, n=n, f=f)

def b(bi, n=8, f=False):
bx = hex(int(str(bi), 2))
bx = bx.replace("0x", "", 1)
x(bx, n=n, f=f)

flags = "\
._._ID_VIP VIF_AC_VM_RF ._NT_IOPL_IOPL OF_DF_IF_TF SF_ZF_._AF ._PF_._CF \n\
\n\
CF - Carry flag \n\
PF - Parity flag \n\
AF - Adjust flag \n\
ZF - Zero flag \n\
SF - Sign flag \n\
TF - Trap flag(single step) \n\
IF - Interrupt enable flag \n\
DF - Direction flag \n\
OF - Overflow flag \n\
\n\
IOPL - I/O privilege level (286+ only), always 1 on 8086 and 186 \n\
NT - Nested task flag (286+ only), always 1 on 8086 and 186 \n\
RF - Resume flag \n\
VM - Virtual 8086 mode flag (386+ only) \n\
AC - Alignment check (486SX+ only) \n\
VIF - Virtual interrupt flag (Pentium+) \n\
VIP - Virtual interrupt pending (Pentium+) \n\
ID - Able to use CPUID instruction (Pentium+) \n\
"

用法很简单, 假设 hole.py 是我的 python 文件名字, from hole import *




总共 3 个 functions, 分别是 x() , b(), 以及 d(),个别代表着 heXadecimal, Binary, Decimal。

如果你要输入的是 2 进制, 那就用 b(1011)




如果你要输入的是 10 进制, 那就用 d(65535)




如果你要输入的是 16 进制, 那就用 x('1011'),最好习惯用引号, 因为有时你要输入的是 abc

支持 0x会让程序复杂化,所以没有支持 0x 开头, 所以不要放 x(0x1010), x('0x1010')




从 output 可以得知 2, 10, 以及 16 进制的表达方式,

Prettyprint 的 2 进制默认是分开用空格分开 byte, 用逗号分开 nibble (4 bits)

如果你要用空格分开每 3 bits, 可以加上 n=3




如果 2 进制 Output 是 在 32 bits 范围内, 还可以细分成 4 bits, 8 bits, 12 bits, 16 bits, 20 bits, 24 bits, 28 bits

如图所示,细分成 Binary 12-bit




支持非常大的数目, 如图所示, 2808 bits, 不需要 1 秒, 如果网站的转换器早 hang 了。




你 debug 汇编的时候, 常看见 eflags, 0x202 代表 IF flag 是set了。




通过这个装换器, 你可以非常了解 EFLAGS 在 2 进制的情况, 有助学习。

如图所示,  0010 代表 ._PF_.CF ,  由于点号就是 Reserved 的, 所以有没有 1 都不会增加 flag。




 干杯 :)