x86-16机器码(DOS),16个字节
B4 02 mov ah, 2
B2 30 mov dl, '0'
B9 1F 00 mov cx, 31
PrintZeros:
CD 21 int 0x21
E2 FC loop PrintZeros
00 CA add dl, bl
CD 21 int 0x21
C3 ret
上面的函数在BL
寄存器(的低字节)中接收一个布尔值(0 ==伪,1 ==真BX
),并将“冗余布尔”字符串打印到标准输出。
它通过调用中断(0x21)进行DOS函数调用(通过设置AH
为2进行选择)来工作,该函数将单个字符(输入DL
)打印到标准输出中。
首先,将ASCII字符“ 0”装入DL
,将计数器(CX
)设置为31,然后循环打印“冗余”字节。然后,将输入布尔值添加到DL
(如果BL
为false,则添加0将DL
保持BL
ASCII'0 '不变;如果为true,DL
则将其递增为ASCII'1 '),并打印最后一个字节。
该函数不返回值。
对于一种不会真正使用字符串的语言来说,这相当不错。
完整程序,21字节
如果要使其成为完整程序,则仅需要5个字节。而不是将输入传递给寄存器,而是在调用应用程序时从命令行上传递的参数中读取输入。参数0解释为false,完全缺少参数也解释为false。大于0的参数将被解释为真实。
只需将以下代码汇编为COM程序,然后在命令行上执行即可。
B4 02 mov ah, 2
B2 30 mov dl, '0'
B9 1F 00 mov cx, 31
PrintZeros:
CD 21 int 0x21
E2 FC loop PrintZeros
3A 16 82 00 cmp dl, BYTE PTR [0x82] ; compare to 2nd arg, at offset 0x82 in PSP
D6 salc ; equivalent to sbb al, al
28 C2 sub dl, al
CD 21 int 0x21
C3 ret ; you can simply 'ret' to end a COM program
样本输出:
C:\>bool.com
00000000000000000000000000000000
C:\>bool.com 0
00000000000000000000000000000000
C:\>bool.com 1
00000000000000000000000000000001
C:\>bool.com 2
00000000000000000000000000000001
C:\>bool.com 7
00000000000000000000000000000001
它是如何工作的?好吧,这基本上是同一回事,直到您深入CMP
说明为止。这会将命令行参数与DL
寄存器的值(您记得,它包含ASCII'0')进行比较。在COM程序中,代码字节以偏移量0x100加载。之前是程序段前缀(PSP),其中包含有关DOS程序状态的信息。具体来说,在偏移量0x82处,您会找到在调用程序时在命令行上指定的第一个(实际上是第二个,因为第一个是空格)参数。因此,我们只是将此字节与ASCII'0'进行比较。
比较会设置这些标志,然后如果两个值相等,则该SALC
指令(奔腾之前的未公开操作码,等效于sbb al, al
,但只有1个字节而不是2个字节)将设置AL
为0;如果两个值不同,则设置为-1。显然,当我们从减去AL
时DL
,这将导致ASCII'0'或'1'适当。
(请注意,具有讽刺意味的是,如果在命令行中传递前导0的参数,则将其破坏,因为它仅查找第一个字符。因此01
将被视为false。:-)