汇编“ hello world”执行文件小于20字节

发布于 2025-02-08 05:26:16 字数 144 浏览 3 评论 0 原文

下面的代码需要20个字节。但是,有一种方法可以通过中断使其更小。如何?

A
MOV AH,9
MOV DX,108
INT 21
RET
DB 'HELLO WORLD$'

R CX
14
N MYHELLO.COM
W 

The code below takes 20 bytes. Yet, there’s a way to make it even smaller through interrupts. How?

A
MOV AH,9
MOV DX,108
INT 21
RET
DB 'HELLO WORLD


R CX
14
N MYHELLO.COM
W 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

百合的盛世恋 2025-02-15 05:26:16

打印较短的消息,例如 db'hi $':p
echo 命令一样,因此它不会占用程序中的空间。

或取决于某些DOS版本在您的程序启动时在寄存器中留下的一些值,如果您不关心可移植性或仅依靠已记录的保证。 (例如,使用 XCHG AX,BP 而不是 MOV AH,9 。)

我不知道您的意思是“ 有一种方法可以使您的意思它通过中断而少。如果您不知道如何,您可以通过中断来使它较小的,同时仍在打印相同的输出字符串?


几乎可以肯定的是, int 21H / ah = 9 是打印多个字节文本的最紧凑方法。您需要以某种方式获得AH = 9,并且DX =指针。如果不依赖于某些DOS版本可能会留下的寄存器或内存中方便的位置的现有字节,则需要2字节 mov ah,9 和3字节 mov dx ,IMM16

您可以使用 XOR DX,DX 设置DX = 0,但是即使您的文件的开始也是一个.com程序中的offset 100H 。 (这意味着让ASCII文本在没有A JMP 的情况下执行为机器代码!)

调用标签/ db“ text” /<代码>标签:POP DX 将是4个字节,将指针输入DX。


使用一些已知DOS版本留下的非初始化寄存器值。

http://www.fysnet.net/yourhelp.htm https://codegolf.stackexchange.com/a/181407/30206"> tips在x86/x64 codegolf.se in codegolf.se 在一系列DOS版本中找到了启动寄存器值。这不是标准化,Afaik,所以这只是偶然的工作。后来版本的Freedos版本变得越来越与MS-DOS相似,因为大概有一些现有软件是故意依靠它来依靠它的,或者因为有些人不知道“在我的机器上工作”不是与“保证将来的证明和便携式”相同,但其他各种DOS版本也有所不同。 这不是您应该依靠的生产使用的东西,只有诸如Code Golf 或“ 演示场景”程序。

大多数DOS版本恰好在程序启动时留下 si = 0100H 。因此,如果我们可以将字符串放在不弄乱机器(或SI)的情况下,我们可以 mov dx,si (2个字节),而不是 mov dx,108H 或<代码> 107H (3个字节)。但是 lea dx,[si + 8] 是3个字节(opcode + modrm + disp8),因此除非我们让字符串执行,否则不保存。

甚至更好的是,如果堆栈上有东西,您可以将 pop dx 使用?或 popa ,如果您非常幸运,也设置 ax = 09xx 。但是我不知道是否有任何DOS版本在堆栈上留下任何已知的东西,除了指向 int 20H 指令的“返回”地址之外。弹出意味着用 int 20H 而不是 ret 手动退出,成本为1个字节。

实际上, XCHG ax,reg 仅1个字节,所以如果任何寄存器都以 09xx 开始,我们可以使用它。 MS-DOS 4.0及以后,Freedos 1.0和IBM PC-DOS 4.0及以后,所有这些都以 bp = 09xxh 开始。因此,我们可以使用 XCHG AX,BP 在AH INIT中保存一个字节,与DX的任何内容分开。 (有趣的事实:这是 90H NOP编码的位置:这只是 XCHG AX,AX 的特殊情况,直到X86-64必须将其作为实际情况进行记录nop,因为在64位模式下,它不会像 xchg eax,eax 那样将EAX零零EAX零零。


让文本执行为代码

以保存任何更多字节,我看到的较短的唯一希望是使用恰好将执行的指令解码的文本,而不会弄乱Si,因此您可以将其放入执行路径。但是,充其量您要保存1个字节,除非文本还包含有用的说明。

但是您的信息对此不起作用。我检查了它如何使用 nasm 制作平坦的二进制和 ndisasm -b16 来拆卸结果的3个资本化将如何拆卸。 (我使用 Align 16 ,所以我可以找到边界,并给出一种NOP幻灯片,因此,如果字符串的最后一个字节不是指令的最后一个字节,它将消耗其中的某些内容填充而不是更改下一个字符串的解码。)我没有dos或debug.exe,所以我在十六进制数字上使用taxling- h 语法。在DOS调试中,所有数字都是隐式的十六进制,这就是为什么 int 21 是正确的数字。我也没有测试过这些,我对过时的16位东西不太感兴趣,但是X86机器代码恶作剧很有趣。虽然true code-golf 挑战问题在堆栈溢出方面,这种单语言优化问题在这里比 https://codegolf.stackexchange.com/上

; just to look at disassembly, to see if there's any hope of letting them execute
DB 'HELLO WORLD
;; DB 'HELLO WORLD

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。

;; 20 bytes, cancelling out saving from  xchg ax,bp
DB 'HELLO WORLD

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW

;; db 'Hello World
;; db 'hello world

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串

;; 18 bytes
DB 'HELLO_WOIY<

18个字节版本,打印与 inc bp 的相同长度分配

00000000  48        dec ax     ; 'H'
00000001  45        inc bp     ; 'E' affects BP, which we want to use later
00000002  4C        dec sp     ; 'L'
00000003  4C        dec sp     ; 'L'  ; SP offset by -2
00000004  4F        dec di     ; 'O'
00000005  5F        pop di     ; '_'  ; restore SP
00000006  57        push di    ; 'W'  ; SP offset by -2
00000007  4F        dec di     ; 'O'
00000008  49        dec cx     ; 'I'
00000009  59        pop cx     ; 'Y'  ; restore SP
0000000A  3C24      cmp al,0x24   ; '<' consumes the '

,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code, returning SP to original position without overwriting return address mov dx, si ; mov dx,0100h MS-DOS (all versions), FreeDOS 1.0, many other DOSes xchg ax, bp ; mov ah,9 MS-DOS 4.0 and later, and FreeDOS 1.0 int 21h ret

18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

as an imm8 0000000C 89F2 mov dx,si ; instructions from the source, as written. 0000000E 95 xchg ax,bp 0000000F CD21 int 0x21 00000011 C3 ret

,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code, returning SP to original position without overwriting return address mov dx, si ; mov dx,0100h MS-DOS (all versions), FreeDOS 1.0, many other DOSes xchg ax, bp ; mov ah,9 MS-DOS 4.0 and later, and FreeDOS 1.0 int 21h ret

18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'Hello World

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

align 16 db 'hello world

nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。


nifty。因此,它实际上并没有对机器造成任何致命的作用(取决于BX指向的位置)。使用来自DOS版本的BX = 0,它给出了我们想要的BP和SI值,它将掩盖 [ds:4f] 中的一些位,该位 psp (程序段前缀)的一部分。如果我们退出之前或在DOS退出电话期间什么都没有看,这可能没事。

但是请注意和al,0x90 结束:字符串本身以 24H ,aka '$'作为指令的开始。这就是和al,IMM8 的opcode,因此作为该指令的一部分,它消耗了1个字节。

因此,在将有用的指令开始之前,您需要一个字节之后。那将杀死1字节的节省。

它会弄乱sp,所以我们不能再 ret 。我们需要 int 20H 退出,除非您可以使用 cc int3 或其他东西纾困。不确定DO在该例外情况。


其他资本是一个问题,涉及'l'作为 6C INSB io指令( https://www.felixcloutier.com/x86/ins:insb:insb:insb:insd:insd ),同样地'o'' 6F OUTSW



再次,24小时的字节被悬空,作为指令的开始。如果之后发生了 nop ,则NDisasm将以 fs和al,0x90 的解码,例如上一个块中。

看起来 Ello 是一个问题,带有IO指令。


我们需要字符串的第二层字节是其他的,例如2字节说明的开始,理想情况下是 3C IB CMP AL,IMM8 之类的东西。那是ASCII &lt;

我们需要它不要搞砸SP。如果它降低了,我们需要递增或弹出虚拟寄存器,因此它再次指向返回地址。

的修改字符串


18个字节版本,打印与 inc bp 的相同长度分配


,修改我们依靠的寄存器之一以获取初始值。但是,除非低字节是 ff 首先,否则它不会包装并更改 09 在高处。在Freedos 1.0上,最初的BP值为 091EH 。在Win9x的MS-DOS版本上,它是 0912H 。关于win-nt派生版本的DOS,它是 09xxh ,它不排除 09ffh

我必须非常认真地敲响字符串以平衡堆栈,并使用偶数 dec sp 指令和弹出以平衡这一点。 1字节 58+ RW pop reg 包括一些晚期字母字母。

还必须避免添加[SI],SP 或类似的内容,因为初始SI指向我们的字符串。 (通常不是最初的BX。)


Hello_wold&lt; 有一个推销太多,但是'ld' part零件取消, dec dec sp / INC SP 。按照该顺序,它不会暂时将返回地址的一部分留在SP下方,中断或调试器可能会抓住它。

如果您真的想认真想出一个字符串,而在视觉上看起来更像 Hello World ,则需要制作一个ASCII角色表和相应的指令。许多上限ASCII字符是单字节指令的opcodes, inc / dec push / pop pop 。

您可以使用%rep < / code> / %分配I i+1 < / code> / db i < / code> / %endrep < /code>块,并通过拆卸器运行。或编写程序以输出二进制文件并拆卸。

或查看 http://ref.x86asm.net/coder32.html使用 https://asciateblecom/


我们可以使用文本作为机器代码至少退出程序吗?不太可能 RET C3 int 20H is cd 20 ,因此这些opcodes均未出现在ASCII文本中。

afaik,您不能在不需要 ret 或同等的代码中的 ret> ret JMP REL16 ,或更可能是JMP,它的字节比 MOV AH,9 的2+2多于2+2 / int 21H 如果我们在谈论 JMP ptr16:16 表单。

Print a shorter message, like db 'hi$' :P
Or as Vitsoft suggests, take the string as an arg like the Unix echo command, so it doesn't take up space in your program.

Or depend on some values that some DOS versions leave in registers when your program starts, if you don't care about portability or only relying on documented guarantees. (e.g. save one byte by using xchg ax, bp instead of mov ah, 9.)

I have no idea what you mean by "There’s a way to make it even smaller through interrupts." I don't think that's true, but you're stating it as a fact, not asking. If you don't know how, what's your source for it being possible to make this smaller via interrupts, while still printing the same output string?


Almost certainly int 21h / ah=9 is the most compact way to print multiple bytes of text. You need to get AH=9 and DX=pointer somehow. Without relying on existing bytes in convenient places in registers or memory that some DOS version might happen to leave lying around, that takes a 2-byte mov ah,9 and a 3-byte mov dx, imm16.

You can set DX=0 with xor dx,dx, but even the very start of your file is at offset 100h in a .com program. (And that would mean letting the ASCII text execute as machine code without a jmp over it!)

call label / db "text" / label: pop dx would be 4 bytes total to get the pointer into DX.


Use uninitialized register values left by some known DOS version.

http://www.fysnet.net/yourhelp.htm linked from Tips for golfing in x86/x64 machine code on codegolf.SE found the startup register values across an array of DOS versions. This is not standardized, AFAIK, so it's just a happens-to-work. Later versions of FreeDOS became more and more similar to MS-DOS, because presumably some existing software was written to rely on it, on purpose, by accident, or because some people didn't know that "works on my machine" isn't the same thing as "guaranteed future proof and portable", but various other DOS versions differ. This is not something you should rely on for production use, only silly computer tricks like code golf or "demo scene" programs.

Most DOS versions happen to leave SI=0100h at program startup. So if we can put our string there without messing up the machine (or SI), we can mov dx, si (2 bytes) instead of mov dx, 108h or 107h (3 bytes). But lea dx, [si+8] is 3 bytes (opcode + modrm + disp8), so no saving unless we let the string execute.

Or even better, if there's something on the stack you could use for pop dx? Or popa, if you're extremely lucky also setting AX=09xx. But I don't know if any DOS versions happen to leave any known stuff on the stack, other than the "return" address which points at an int 20h instruction or something. Popping that would mean exiting manually with int 20h instead of ret, costing 1 more byte.

Actually, xchg ax, reg is only 1 byte, so if any register starts with 09xx, we can use that. MS-DOS 4.0 and later, FreeDOS 1.0, and IBM PC-DOS 4.0 and later, all start with BP=09xxh. So we can save a byte in AH init by using xchg ax, bp, separate from anything with DX. (Fun fact: This is where the 90h NOP encoding comes from: it's just a special case of xchg ax, ax, until x86-64 had to document it as an actual NOP because in 64-bit mode it doesn't zero-extend EAX into RAX like xchg eax, eax would).


Letting the text execute as code

To save any more bytes, the only hope I see for making this shorter is using text that happens to decode as instructions that let execution come out the other side, without messing up SI, so you can put it in the path of execution. But at best you're saving 1 byte, unless the text also contains instructions that do anything useful.

But your message don't work for that. I checked out how 3 capitalizations of it would disassemble, using nasm to make a flat binary and ndisasm -b16 to disassemble the result. (I used align 16 so I could find the boundary, and to give a sort of nop slide so if the last byte of the string was not the last byte of an instruction, it would consume some of that padding instead of changing decoding of the next string.) I don't have DOS or a debug.exe, so I'm using trailing-h syntax on hex numbers. In DOS Debug, all numbers are implicitly hex, that's why int 21 is the right number. I also haven't tested these, I'm not that interested in obsolete 16-bit stuff, but the x86 machine code shenanigans are fun. Although true challenge questions are off-topic on Stack Overflow, this kind of single-language optimization question is a better fit here than on https://codegolf.stackexchange.com/

; just to look at disassembly, to see if there's any hope of letting them execute
DB 'HELLO WORLD
;; DB 'HELLO WORLD

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.

;; 20 bytes, cancelling out saving from  xchg ax,bp
DB 'HELLO WORLD

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.

;; db 'Hello World
;; db 'hello world

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length

;; 18 bytes
DB 'HELLO_WOIY<

Disassembles as

00000000  48        dec ax     ; 'H'
00000001  45        inc bp     ; 'E' affects BP, which we want to use later
00000002  4C        dec sp     ; 'L'
00000003  4C        dec sp     ; 'L'  ; SP offset by -2
00000004  4F        dec di     ; 'O'
00000005  5F        pop di     ; '_'  ; restore SP
00000006  57        push di    ; 'W'  ; SP offset by -2
00000007  4F        dec di     ; 'O'
00000008  49        dec cx     ; 'I'
00000009  59        pop cx     ; 'Y'  ; restore SP
0000000A  3C24      cmp al,0x24   ; '<' consumes the '

This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code, returning SP to original position without overwriting return address mov dx, si ; mov dx,0100h MS-DOS (all versions), FreeDOS 1.0, many other DOSes xchg ax, bp ; mov ah,9 MS-DOS 4.0 and later, and FreeDOS 1.0 int 21h ret

Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

as an imm8 0000000C 89F2 mov dx,si ; instructions from the source, as written. 0000000E 95 xchg ax,bp 0000000F CD21 int 0x21 00000011 C3 ret

This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code, returning SP to original position without overwriting return address mov dx, si ; mov dx,0100h MS-DOS (all versions), FreeDOS 1.0, many other DOSes xchg ax, bp ; mov ah,9 MS-DOS 4.0 and later, and FreeDOS 1.0 int 21h ret

Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000020 68656C push word 0x6c65 00000023 6C insb 00000024 6F outsw 00000025 20776F and [bx+0x6f],dh 00000028 726C jc 0x96 0000002A 64 fs 0000002B 24 db 0x24

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000010 48 dec ax 00000011 656C gs insb ; big problem, IO could crash the machine 00000013 6C insb ; using port=DX, data from [DS:SI] 00000014 6F outsw 00000015 20576F and [bx+0x6f],dl 00000018 726C jc 0x86 ; conditional branch, but AND always clears CF so this will be not-taken 0000001A 642490 fs and al,0x90 ; FS prefix was new with 386 0000001D 90 nop ; the align 16 padding, including previous immediate 0000001E 90 nop 0000001F 90 nop

Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

; executes as machine code without doing anything too bad nop ; but this is needed. It's actually consumed as an immediate for 24h mov dx, si xchg ax, bp ; AH=09 on some DOS versions, in 1 byte instead of 2. int 21 int 20 ; larger than ret, making this a net loss.

Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

00000000 48 dec ax ; early-alphabet upper-case 00000001 45 inc bp ; is all single-byte inc/dec 00000002 4C dec sp ; the same opcodes x86-64 repurposed as REX 00000003 4C dec sp ;; Modified SP breaks RET 00000004 4F dec di 00000005 20574F and [bx+0x4f],dl ;; step on part of the PSP 00000008 52 push dx ; 'R' also modifies SP 00000009 4C dec sp ; 'L' 0000000A 44 inc sp ; 'D' cancel each other's effect on SP 0000000B 2490 and al,0x90 0000000D 90 nop 0000000E 90 nop 0000000F 90 nop

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'Hello World

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

align 16 db 'hello world

Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.


Nifty. So it doesn't actually do anything fatal to the machine (depending on where BX is pointing). With BX=0 from the DOS versions that give the BP and SI values we want, that would mask away some bits in [ds: 4f], which is in the reserved part of the PSP (program segment prefix). This may be fine if nothing else ever looks there before we exit, or during the DOS exit call.

But note the and al, 0x90 ending: the string itself ended with 24h, aka '$', as the start of an instruction. That's the opcode for and al, imm8, so it consumes 1 byte of whatever's next as part of that instruction.

So you'd need a byte of padding after it before you could put the start of a useful instruction. That would kill the 1-byte size saving.

And it messes up SP, so we can't ret anymore. We'd need int 20h to exit, unless you can bail out with CC int3 or something. Not sure what DOS does on that exception.


Other capitalizations are a problem, involving 'l' as 6C insb IO instructions (https://www.felixcloutier.com/x86/ins:insb:insw:insd), and similarly 'o' as 6F outsw.



Again the 24h byte is left dangling, as the start of an instruction. If there'd been a nop after it, ndisasm would have decoded it as fs and al, 0x90 like in the previous block.

Looks like ello is a problem, with IO instructions.


We need the 2nd-last byte of the string to be something else, like the start of a 2-byte instruction, ideally something like 3C ib cmp al, imm8. That's ASCII <.

And we need it not to mess up SP. If it decrements it, we need to increment or pop into dummy registers, so it's once again pointing at the return address.

18 byte version, printing a modified string of same length


Disassembles as


This does inc bp, modifying one of the registers we're relying on for an initial value. But unless the low byte was FF to start with, it won't wrap and change the 09 in the high half. On FreeDOS 1.0 specifically, the initial BP value is 091Eh. On MS-DOS versions from Win9x, it's 0912h. On DOS from Win-NT derived versions, it's 09xxh, which doesn't rule out 09FFh

I had to mangle the string pretty seriously to balance the stack, with an even number of dec sp instructions and pops to balance that. The 1-byte 58+ rw pop reg includes some of the late upper-case alphabet letters.

Also had to avoid add [si], sp or things like that, since the initial SI points at our string. (The initial BX typically doesn't.)


HELLO_WOLD< has one too many pushes, but the 'LD' part cancels out, dec sp / inc sp. In that order so it doesn't temporarily leave part of your return address below SP, where an interrupt or debugger could clobber it.

If you really wanted to get serious about coming up with a string that visually looked more like HELLO WORLD, you'd want to make a table of ASCII character and the corresponding instruction. Many upper-case ASCII characters are opcodes for single-byte instructions, either inc/dec or push/pop.

You could use a good assembler like NASM with a %rep / %assign i i+1 / db i / %endrep block, and run it through a disassembler. Or write a program to output a binary file and disassemble that.

Or look at http://ref.x86asm.net/coder32.html and match it up with https://asciitable.com/


Can we use the text as machine code to at least exit the program? Unlikely; ret is c3, int 20h is CD 20, so neither of those opcodes will appear in ASCII text.

AFAIK, you can't tail-call a DOS routine to have it print and then exit without needing a ret or equivalent in your own code. Or if you can, it would be a 3-byte jmp rel16, or more likely a far jmp, which would take more bytes than 2+2 for mov ah, 9 / int 21h if we're talking about the jmp ptr16:16 form.

旧故 2025-02-15 05:26:16

如果您不介意提供文本作为论点,则可以将其缩短到8个字节:

R:\>debug
-A
0DB2:0100 MOV AH,9
0DB2:0102 MOV DX,82
0DB2:0105 INT 21
0DB2:0107 RET
0DB2:0108
-R CX
CX 0000  :8
-N HELLO8.COM
-W
Writing 0008 bytes
-Q

R:\>HELLO8.COM HELLO WORLD$
HELLO WORLD
R:\>

You can shorten it to 8 bytes if you don't mind providing the text as its argument:

R:\>debug
-A
0DB2:0100 MOV AH,9
0DB2:0102 MOV DX,82
0DB2:0105 INT 21
0DB2:0107 RET
0DB2:0108
-R CX
CX 0000  :8
-N HELLO8.COM
-W
Writing 0008 bytes
-Q

R:\>HELLO8.COM HELLO WORLD$
HELLO WORLD
R:\>
橪书 2025-02-15 05:26:16

仅供参考,这是我尝试编写简短的Hello-World Dos .EXE程序的尝试。

我并不是要重叠代码和消息(例如@peter Cordes在其DOS .COM解决方案中),但是(正如我们稍后会看到的),它无助于减小程序的大小。

当然,dos hello-world .exe程序将比等效的dos .com程序更长,因为dos .exe标题为28个字节(并且dos .com标题为0字节)。

我能够将其挤压到40个字节,包括DOS .EXE标题的28个字节和15个字节的消息,总计43个字节(!),通过制作代码和消息与DOS .EXE标头重叠。这是我的解决方案:

; nasm -O0 -f bin -o prog.exe prog.nasm
exe:  ; DOS .exe header: http://justsolve.archiveteam.org/wiki/MS-DOS_EXE
.signature      db 'MZ'
.lastsize       dw end-exe  ; Number of bytes in the last 0x200-byte block in the .exe file. For us, total file size.
.nblocks        dw 1  ; Number of 0x200-byte blocks in .exe file (rounded up).
.nreloc         dw 0  ; No relocations.
.hdrsize        dw 0  ; Load .exe file to memory from the beginning.
..@code:
%if 1  ; Produces identical .exe output even if we change it to 0.
.minalloc:      mov ax, 0x903  ; AH := 9, AL := junk. The number 3 matters for minalloc, see below.
.ss_minus_1:    mov dx, message+(0x100-exe)  ; (0x100-exe) to make it work with any `org'.
.sp:            int 0x21  ; Print the message to stdout. https://stanislavs.org/helppc/int_21-9.html
.checksum:      int 0x20  ; Exit. Requires CS == PSP. https://stanislavs.org/helppc/int_20.html
%else
.minalloc       dw 0x03b8  ; To have enough room for the stack, we need minalloc >= ss+((sp+0xf)>>4)-0x20 == 0x315. kvikdos verifies it.
.maxalloc       dw 0xba09  ; Actual value doesn't matter.
.ss             dw 0x0118  ; Actual value doesn't matter as long as it matches minalloc. dw message
.sp             dw 0x21cd  ; Actual value doesn't matter. int 0x21
.checksum       dw 0x20cd  ; Actual value doesn't matter. int 0x20
%endif
.ip             dw ..@code+(0x100-exe)  ; Entry point offset. (0x100-exe) to make it work with any `org'.
.cs             dw 0xfff0  ; CS := PSP upon entry.
%if 0
.relocpos       dw ?  ; Doesn't matter, overlaps with 2 bytes of message: 'He'.
.noverlay       dw ?  ; Doesn't matter. overlaps with 2 bytes of message: 'll'.
; End of 0x1c-byte .exe header.
%endif
message         db 'Hello, World!', 13, 10, '

请参阅 https:// github 。

  • mov ds,ax 以初始化 ds 。 (我们需要一个正确的 ds 才能用 ah == 9和 int 0x21 。)这很长,它也使用 @data 的4字节重定位插槽。避免它的一种方法是在.exe标题为0中制作 ss ,然后按SS ,然后是 pop ds 也有效,并且也有效,并且它不使用任何搬迁。更好的是:不要初始化 ds ,请利用DOS将其初始化为PSP段(为0x100字节长,并且就在内存中的程序图像前)的事实,所以只需在打印时将0x100添加到 dx

  • 在.exe标头0xFFF0中设置 cs ,这将将 cs 初始化为PSP段。如果 cs 的值是PSP段,则可以使用 int 0x20 使用退出代码0,而不是更长的 mov ax ax,0x4c00 后跟 int 0x21 。这节省了3个字节。

  • 不幸的是, XCHG bp,ax 设置为 ah 9的技巧在MS-DOS 4.00之前不起作用,因此我的解决方案不使用它。通常的 mov ah,9 是1个字节更长。我的解决方案使用 mov ax,0x903 ,它甚至更长1个字节,看似浪费(因为不使用 al 中的3个字节),但是该空间中有空间该额外字节的重叠DOS .EXE标头,而3的小值则减少了程序的内存使用情况,因为 MOV AX,0x903 指令与 minalloc 重叠.exe标头。

  • relocpos 和 noverlay .exe标头字段在.exe标头的末端被DOS忽略,因此我的解决方案与消息与消息重叠。 recrocpos 仅在.exe程序包含重新定位(不)时才使用,而 noverlay 在加载(和执行).exe文件时完全忽略了DOS。

  • 单个重要的剩余技巧是将代码完全嵌入DOS .EXE标题中。看起来代码在连续的.exe标头字段的10个字节中非常适合 minalloc maxalloc ss ss , sp sp /code>, checksum ,并且使用的实际代码字节在加载程序时解释这些标头字段时不会遇到问题。有关更多详细信息,请参见源代码中的评论。更多信息:我们不想要大型 minalloc ,这会增加程序的内存要求。 maxalloc 无关紧要(但要使它与 minalloc 以良好的方式使其大小)。我们需要足够大的 ss sp ,以便堆栈不会重叠代码和消息(例如,初始值应指向上方至少32个字节。代码>结束),以及 minalloc 必须足够大,以便堆栈也适合。 checksum 没关系,旧版本和新的DOS版本(用PC DOS 2.00作为最旧版本测试)都忽略了它。


  • 不可能将消息完整地符合DOS .EXE标题,因为消息本身太长了。也不可能重叠,因为那时它必须重叠 ip cs 标头字段,我们需要在那里非常具体的值。因此,如果将代码完全嵌入消息,而不是完全在.EXE标题中,我们将无法节省更多字节。我决定做后者以简单起见,也可以使消息灵活地进行。

  • 要使.exe文件缩短,请将消息短(降至4个字节,包括 $ )。少于4个字节可能不起作用,因为某些DOS版本坚持一个.EXE程序文件至少长28个字节,因为这是DOS .EXE标头的最小尺寸。

end:

请参阅 https:// github 。

  • mov ds,ax 以初始化 ds 。 (我们需要一个正确的 ds 才能用 ah == 9和 int 0x21 。)这很长,它也使用 @data 的4字节重定位插槽。避免它的一种方法是在.exe标题为0中制作 ss ,然后按SS ,然后是 pop ds 也有效,并且也有效,并且它不使用任何搬迁。更好的是:不要初始化 ds ,请利用DOS将其初始化为PSP段(为0x100字节长,并且就在内存中的程序图像前)的事实,所以只需在打印时将0x100添加到 dx

  • 在.exe标头0xFFF0中设置 cs ,这将将 cs 初始化为PSP段。如果 cs 的值是PSP段,则可以使用 int 0x20 使用退出代码0,而不是更长的 mov ax ax,0x4c00 后跟 int 0x21 。这节省了3个字节。

  • 不幸的是, XCHG bp,ax 设置为 ah 9的技巧在MS-DOS 4.00之前不起作用,因此我的解决方案不使用它。通常的 mov ah,9 是1个字节更长。我的解决方案使用 mov ax,0x903 ,它甚至更长1个字节,看似浪费(因为不使用 al 中的3个字节),但是该空间中有空间该额外字节的重叠DOS .EXE标头,而3的小值则减少了程序的内存使用情况,因为 MOV AX,0x903 指令与 minalloc 重叠.exe标头。

  • relocpos 和 noverlay .exe标头字段在.exe标头的末端被DOS忽略,因此我的解决方案与消息与消息重叠。 recrocpos 仅在.exe程序包含重新定位(不)时才使用,而 noverlay 在加载(和执行).exe文件时完全忽略了DOS。

  • 单个重要的剩余技巧是将代码完全嵌入DOS .EXE标题中。看起来代码在连续的.exe标头字段的10个字节中非常适合 minalloc maxalloc ss ss , sp sp /code>, checksum ,并且使用的实际代码字节在加载程序时解释这些标头字段时不会遇到问题。有关更多详细信息,请参见源代码中的评论。更多信息:我们不想要大型 minalloc ,这会增加程序的内存要求。 maxalloc 无关紧要(但要使它与 minalloc 以良好的方式使其大小)。我们需要足够大的 ss sp ,以便堆栈不会重叠代码和消息(例如,初始值应指向上方至少32个字节。代码>结束),以及 minalloc 必须足够大,以便堆栈也适合。 checksum 没关系,旧版本和新的DOS版本(用PC DOS 2.00作为最旧版本测试)都忽略了它。


  • 不可能将消息完整地符合DOS .EXE标题,因为消息本身太长了。也不可能重叠,因为那时它必须重叠 ip cs 标头字段,我们需要在那里非常具体的值。因此,如果将代码完全嵌入消息,而不是完全在.EXE标题中,我们将无法节省更多字节。我决定做后者以简单起见,也可以使消息灵活地进行。

  • 要使.exe文件缩短,请将消息短(降至4个字节,包括 $ )。少于4个字节可能不起作用,因为某些DOS版本坚持一个.EXE程序文件至少长28个字节,因为这是DOS .EXE标头的最小尺寸。

FYI Here is my attempt at writing a short hello-world DOS .exe program.

I'm not trying to overlap the code and the message (like @Peter Cordes in their DOS .com solution), but (as we will see it later), it wouldn't help reducing the size of the program.

Surely a DOS hello-world .exe program will be longer than an equivalent DOS .com program, because the DOS .exe header is 28 bytes (and the DOS .com header is 0 bytes).

I was able to squeeze it to 40 bytes, including the 28 bytes of DOS .exe header and the 15 bytes of message, totaling 43 bytes (!), by making both the code and the message overlap the DOS .exe header. Here is my solution:

; nasm -O0 -f bin -o prog.exe prog.nasm
exe:  ; DOS .exe header: http://justsolve.archiveteam.org/wiki/MS-DOS_EXE
.signature      db 'MZ'
.lastsize       dw end-exe  ; Number of bytes in the last 0x200-byte block in the .exe file. For us, total file size.
.nblocks        dw 1  ; Number of 0x200-byte blocks in .exe file (rounded up).
.nreloc         dw 0  ; No relocations.
.hdrsize        dw 0  ; Load .exe file to memory from the beginning.
..@code:
%if 1  ; Produces identical .exe output even if we change it to 0.
.minalloc:      mov ax, 0x903  ; AH := 9, AL := junk. The number 3 matters for minalloc, see below.
.ss_minus_1:    mov dx, message+(0x100-exe)  ; (0x100-exe) to make it work with any `org'.
.sp:            int 0x21  ; Print the message to stdout. https://stanislavs.org/helppc/int_21-9.html
.checksum:      int 0x20  ; Exit. Requires CS == PSP. https://stanislavs.org/helppc/int_20.html
%else
.minalloc       dw 0x03b8  ; To have enough room for the stack, we need minalloc >= ss+((sp+0xf)>>4)-0x20 == 0x315. kvikdos verifies it.
.maxalloc       dw 0xba09  ; Actual value doesn't matter.
.ss             dw 0x0118  ; Actual value doesn't matter as long as it matches minalloc. dw message
.sp             dw 0x21cd  ; Actual value doesn't matter. int 0x21
.checksum       dw 0x20cd  ; Actual value doesn't matter. int 0x20
%endif
.ip             dw ..@code+(0x100-exe)  ; Entry point offset. (0x100-exe) to make it work with any `org'.
.cs             dw 0xfff0  ; CS := PSP upon entry.
%if 0
.relocpos       dw ?  ; Doesn't matter, overlaps with 2 bytes of message: 'He'.
.noverlay       dw ?  ; Doesn't matter. overlaps with 2 bytes of message: 'll'.
; End of 0x1c-byte .exe header.
%endif
message         db 'Hello, World!', 13, 10, '

See more comments at https://github.com/pts/mininasm/blob/master/demo/hello/helloe.nasm

Here are the tricks involved:

  • Most .exe programs have mov ax, @data followed by mov ds, ax to initialize ds. (We need a correct ds to print a message with ah == 9 and int 0x21.) This is rather long, and it also uses a 4-byte relocation slot for @data. One way to avoid it is to make ss in the .exe header be 0, and then push ss followed by pop ds also works, and it doesn't use any relocation. Even better: don't initialize ds, make use of the fact that DOS initializes it to the PSP segment (which is 0x100 bytes long, and it's right in front of the program image in memory), so just add 0x100 to dx instead when printing.

  • Set the cs in the .exe header 0xfff0, and this will initialize cs to the PSP segment. If the value of cs is the PSP segment, then int 0x20 can be used to exit to DOS with exit code 0, rather than the longer mov ax, 0x4c00 followed by int 0x21. This saves 3 bytes.

  • Unfortunately the xchg bp, ax trick to set ah to 9 doesn't work before MS-DOS 4.00, so my solution doesn't use it. The usual mov ah, 9 is 1 byte longer. My solution uses mov ax, 0x903 instead, which is even longer by 1 bytes, seemingly wasteful (because the 3 in al is not used), but there is room in the overlapped DOS .exe headers for that extra byte, and the small value of 3 reduces the memory usage of the program, because the mov ax, 0x903 instruction overlaps with minalloc in the .exe header.

  • The relocpos and noverlay .exe header fields at the end of the .exe header are ignored by DOS, so my solution overlaps them with the message. relocpos is only used if the .exe program contains relocations (mine doesn't), and noverlay is completely ignored by DOS when loading (and executing) the .exe file.

  • The single important remaining trick is completely embedding the code into the DOS .exe header. It looks like the code fits nicely in the 10 bytes of the consecutive .exe header fields minalloc, maxalloc, ss, sp, checksum, and the actual code bytes used don't make problems when DOS is interpreting those header fields when loading the program. See the comments in the source code for more details. Some more info: we don't want a large minalloc, that would increase the memory requirements of the program. maxalloc doesn't matter (but make it at least as large as minalloc for good manners). We need a large enough ss and sp so that the stack doesn't overlap the code and the message (e.g. the initial value should point to at least 32 bytes above the end), and also minalloc must be large enough so that the stack also fits. The checksum doesn't matter, old and new DOS versions (tested with PC DOS 2.00 as the oldest) all ignore it.

  • It's not possible to fit the message in its entirety to the DOS .exe header, because the message itself is too long. It's also not possible to overlap it more, because then it would have to overlap the ip and cs header fields, and we need very specific values there. Thus we can't save more bytes if embed the code entirely in the message rather than entirely in the .exe headers. I've decided to do the latter for simplicity, and also for making the message flexible.

  • To make the .exe file shorter, make the message shorter (down to 4 bytes, including the $). Less than 4 bytes may not work, because some DOS versions insist that an .exe program file is at least 28 bytes long, because that's the minimum size of the DOS .exe header.

end:

See more comments at https://github.com/pts/mininasm/blob/master/demo/hello/helloe.nasm

Here are the tricks involved:

  • Most .exe programs have mov ax, @data followed by mov ds, ax to initialize ds. (We need a correct ds to print a message with ah == 9 and int 0x21.) This is rather long, and it also uses a 4-byte relocation slot for @data. One way to avoid it is to make ss in the .exe header be 0, and then push ss followed by pop ds also works, and it doesn't use any relocation. Even better: don't initialize ds, make use of the fact that DOS initializes it to the PSP segment (which is 0x100 bytes long, and it's right in front of the program image in memory), so just add 0x100 to dx instead when printing.

  • Set the cs in the .exe header 0xfff0, and this will initialize cs to the PSP segment. If the value of cs is the PSP segment, then int 0x20 can be used to exit to DOS with exit code 0, rather than the longer mov ax, 0x4c00 followed by int 0x21. This saves 3 bytes.

  • Unfortunately the xchg bp, ax trick to set ah to 9 doesn't work before MS-DOS 4.00, so my solution doesn't use it. The usual mov ah, 9 is 1 byte longer. My solution uses mov ax, 0x903 instead, which is even longer by 1 bytes, seemingly wasteful (because the 3 in al is not used), but there is room in the overlapped DOS .exe headers for that extra byte, and the small value of 3 reduces the memory usage of the program, because the mov ax, 0x903 instruction overlaps with minalloc in the .exe header.

  • The relocpos and noverlay .exe header fields at the end of the .exe header are ignored by DOS, so my solution overlaps them with the message. relocpos is only used if the .exe program contains relocations (mine doesn't), and noverlay is completely ignored by DOS when loading (and executing) the .exe file.

  • The single important remaining trick is completely embedding the code into the DOS .exe header. It looks like the code fits nicely in the 10 bytes of the consecutive .exe header fields minalloc, maxalloc, ss, sp, checksum, and the actual code bytes used don't make problems when DOS is interpreting those header fields when loading the program. See the comments in the source code for more details. Some more info: we don't want a large minalloc, that would increase the memory requirements of the program. maxalloc doesn't matter (but make it at least as large as minalloc for good manners). We need a large enough ss and sp so that the stack doesn't overlap the code and the message (e.g. the initial value should point to at least 32 bytes above the end), and also minalloc must be large enough so that the stack also fits. The checksum doesn't matter, old and new DOS versions (tested with PC DOS 2.00 as the oldest) all ignore it.

  • It's not possible to fit the message in its entirety to the DOS .exe header, because the message itself is too long. It's also not possible to overlap it more, because then it would have to overlap the ip and cs header fields, and we need very specific values there. Thus we can't save more bytes if embed the code entirely in the message rather than entirely in the .exe headers. I've decided to do the latter for simplicity, and also for making the message flexible.

  • To make the .exe file shorter, make the message shorter (down to 4 bytes, including the $). Less than 4 bytes may not work, because some DOS versions insist that an .exe program file is at least 28 bytes long, because that's the minimum size of the DOS .exe header.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文