With a couple of guys we have a challenge who can write the smallest executable being able to print "Hello World".
Since the .com files would be the smallest possible, this is the current target.
Using a little trick (command line argument) I'm up to 7 bytes:
mov ah,09h
mov dx,82h
int 21h
which can be run:
test.com Hello World$and it would print Hello World to the screen.
The only way I could come up with to make it another byte shorter is:
mov ah,09h
mov dl,82h
int 21h
This should work the same, but gives an error instead:
Quote
Administrator: cmd.exe - test3.com hello$
The NTVDM CPU has encountered an illegal instruction.
CS:11ed IP:0024 OP:ff ff ff ff ff Choose 'Close' to terminate the application.
I know I'm assuming an empty DH here, but when I run both versions through debug.exe the registers are identical (except for the IP which is off by one byte of course).
Shouldn't this just work or am I missing something here?
Any other ideas to make it even shorter?
Thanks!
.model tiny
.286
.code
org 100h
go: mov al,dh
call phex8
ret
phex8: ror al,4
call phex4
ror al,4
phex4: push ax
and al,15
cmp al,10
sbb al,105
das
mov dl,al
mov ah,2
int 21h
pop ax
ret
end go
This code gives me "05" as the result, so I guess DH isn't 0 after all...
You should really have a "ret" at the end of your code too.
strange, it gives 11 for me when I run your code, but when I run it through debug.exe:
AX=0000 BX=0000 CX=001F DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000
DS=17AB ES=17AB SS=17AB CS=17AB IP=0102 NV UP EI PL NZ NA PO NC
17AB:0102 E80100 CALL 0106
Both AX and DX are 0 after the first line of code....
So debug.exe doesn't work like it should then?
I know about the ret that should be there, but it doesn't help in size :D
Thanks for your reply!
The only registers initialised by DOS for a .com program are AL,AH,DS,ES,SS and SP, all others are 'undefined' - they could be anything, usually what DOS left in there.
Debug initialises BX:CX to the program's size, maybe it zeroes out other registers? For me, debugging any program shows DX=0.
Debug zeros AX, DX, BP, SI, and DI by design.
Ahhh, so that explains why it looks ok.
Well, then 7 bytes really is the smallest we can go, I think.
Thanks for your answers!
Hi,
Yes I just got bitten by the difference between DEBUG and
normal loading of a program. Look at the GENERAL.TXT file
in the Hugi Compo rules for a good description of the start up
register contents.
http://www.hugi.scene.org/compo/
The DI register was zeroed by DEBUG, which "fixed" an error
in my code.
Cheers,
Steve N.
Quote from: Prince Wotoshi on November 01, 2008, 08:09:19 PM
Using a little trick (command line argument) I'm up to 7 bytes:
mov ah,09h
mov dx,82h
int 21h
which can be run: test.com Hello World$
and it would print Hello World to the screen.
Without the
ret, I get a lot of garbage until it prints Hello. Are the rules of your game unspecific enough to tolerate the garbage?
Are you sure you have the $ at the end of the argument?
It works perfectly for me on vista. This the file (program) if you look at it from a hex editor:
B409 BA8200 CD21
And no it's not allowed to see garbage ;), but for me it doesnt......
Hey Prince Wotoshi. I see that you have a captains of crush gripper in your avatar. It was funny to see that there are grip trainers in this forum. I have closed the CoC 3.5 myself from a choked position and I have repped the CoC 3 from a non-choked position for about 6 reps.
Yes, I did a lot of grip training in the past :)
repping the #3 is a nice achievement, as well as closing the #3.5 from a choke. Good job!
I did both as well, but was not able to become COC certified. My small hands really gave me the disadvantage on the credit card set.
I got Mash monster certified with my #3 though, and the pic you see in my avatar is the #3.
I'm also red nail certified, but achieving that was a lot easier :)
But like I said, I did a lot in the past. Now I sometimes still do it, but I cannot close the #3 consistently anymore. Only on good days ;)
I have nails here myself. I havent trained much with them because I tend to run out of nails pretty quickly, and it takes a while to order new ones. I'm not in america. I bend blue nails very easily, but the red nail is not in reach yet.
I train with alot of equipment related to grip and forearm development. Here is a list of equipment/exercises I use frequently:
1: Captains of Crush grippers (I have dual sets of all of them)
2: Heavy Grips grippers (I have all of them)
3: Ironmind Wrist Roller (This one is really effective, it gives you a forearm pump like nothing else i've tried)
4: Ironmind pinch grip block (This one gets on the pinch grip)
5: Ironmind Rolling Thunder (I like this one)
6: Hammer Bar (I ordered this from an armwrestling store, its an effective tool, you mount weight plates onto it)
7: Hercules Bar (This is also a good forearm developer)
8: I use normal weight plates in my hand and curl them with my wrist, I can almost handle 15 kg plates now)
My bench press is really bad at the moment, but my deadlift is 280 kg and my squat is 210 kg. Overhead press is 100 kg x 3 reps so far.
Bicep curl is 90 kg x 3 reps at most.
My strongest area is definitely deadlift. I am trying to improve my bench, I can barely handle 120 kg in the bench. I have very long arms, it could be because of that i'm not sure.
Anyways, good day!
BTW: I understand the emotional situation one can get into after years of training. You get tired, cant afford enough protein, motivation is lost etc. It takes effort to get back into a good pattern again. I struggle with this myself.
you must keep in mind that interrupts are executable code.
this i think may be smaller. works only for text mode.
mov ax,0b800h
mov es,eax
lea esi,HelloString
mov edi,0
mov cx,sizeof HelloString
loop:
lodsb
mov ah,07h ; not sure if attr should be ah or al long time no DOS
stosw
dec cx
jcxz end_loop
jmp loop
end_loop:
int 20h
Not sure how this stiff works anymore . It gives invalid fixup .
.286
.model tiny
.data
HelloString db 'Hello World'
.code
org 100h
_start:
mov ax,0b800h
mov es,ax
lea si,HelloString
mov di,0
mov cx,sizeof HelloString
cld
string_loop:
lodsb
mov ah,7
stosw
dec cx
jcxz end_loop
jmp string_loop
end_loop:
int 20h
end _start
37 bytes, 15 of code?
.286
.model tiny
option casemap:none
.data
out_string db "H", 07h, "e",07h, "l", 07h,"l", 07h,"o", 07h," ", 07h,"W", 07h,"o", 07h,"r", 07h,"l", 07h,"d", 07h
.code
org 0100h
start:
mov dx,0b800h
mov es,dx
mov cl, SIZEOF out_string
mov si, OFFSET out_string
move:
lodsw
stosw
loop move
ret
end start
i think you need the 8th byte...
mov ah,9
mov dx,82h
int 21h
ret
as for relying on DH=0, not sure that is a valid assumption under NTVDM
yeah,... well lets not forget that int 21h is a far call. So there's code beneath the instruction... Is it smaller? Don't know....
bye
that is true however, .COM programs are executed similar to a NEAR CALL
the reason a RETN instruction exits is that an INT 20h instruction is at CS:0000 and a 0000 pushed on the stack at program entry
(CS = PSP)
ok ... i'm not sure we're understanding each other. If i do this...
call PrintHelloWorldAndExit
...is everyone going to disregard the code parts in this procedure call?
No? Yay, ive won!!!
LMAO :)
Did you talk about 16 programs only, or for Win32, too?
i think its DOS only antariy
Quote from: xandaz on November 20, 2010, 12:51:02 AM
i think its DOS only antariy
Well, if it been Win32, then I can suggest a candidate...
It's .com, actually... and it's 8 bytes short:
.model tiny
.code
org 100h
start:
mov ah, 09h ; write string to STDOUT
mov dx, 82h ; get command line
int 21h ; show it... ;-)
ret
end start
If that looks too complex, try this:
.model tiny
.code
dq 0C321CD0082BA09B4h
end
Batch file for testing:
Quote@ECHO OFF
HelloWorldDOS.com Hellooo... world of Masm!$
echo.
echo.
echo.
echo.
pause
Quote from: Antariy on November 20, 2010, 12:53:52 AM
Well, if it been Win32, then I can suggest a candidate...
Which one?
Quote from: jj2007 on November 20, 2010, 12:55:31 AM
Quote from: Antariy on November 20, 2010, 12:53:52 AM
Well, if it been Win32, then I can suggest a candidate...
Which one?
You are know :lol
But it not only print HelloWorld :wink
Quote from: jj2007 on November 20, 2010, 12:55:31 AM
It's .com, actually... and it's 8 bytes short:
I can suggest to put code into command line specification, and at start of the program put the 2 byte jump to the command line :wink
So, you just needed to avoid binary null in the code (this is easy), and enter the code as command line for the 2 bytes program, which just jump to command line.
But I must warn that under Windows this is a bit tricky due to encodings difference. So, this is reliablest from DOS.
Command line is something like (in hex, convert it to dec and enter it with Alt codes):
B4 09 31 D2 B2 8B CD 21 C3 48 65 6C 6C 6F 2C 57 6F 72 6C 64 24
The program is:
jmp 82
jmp 82h but...:
error A2076: jump destination must specify a label
There is a test with 2 byte program which print HelloWorld.
To simplify things with different encodings, is written an .BAT file.
On my system it works.
Alex
Thanks, Alex - works like a charm on Win XP SP2...
.model tiny
.code
dw 080EBh
end
Update in .BAT file - pause>nul
It actually prints "Hello,World" for me, not space but comma, is that legal? :lol
(I tried it with space and that worked also :lol)
PS. Does that mean I technically win :lol
Quote from: oex on November 20, 2010, 01:47:10 AM
It actually prints "Hello,World" for me, not space but comma, is that legal? :lol
(I tried it with space and that worked also :lol)
This is correct - I used not space.
For pure historical DOS, there is one more update :lol
Alex
Any idea why jmp word ptr ss:[82h] does not work?
Quote from: jj2007 on November 20, 2010, 01:55:52 AM
Any idea why jmp word ptr ss:[82h] does not work?
Because this is level of inderection - you jump not to address 82, but to address, which is specified in WORD placed at address 82.
I guess my English not help...
Quote from: oex on November 20, 2010, 01:47:10 AM
It actually prints "Hello,World" for me, not space but comma, is that legal? :lol
By the way, you can enter very very very long (up to ~110 chars) string for printing - and this will have no influence for program size :bg
P.S. you can edit .BAT file because it contain only printable chars.
Alex,
Your program + .bat file works on Vista (32-bit) too.
Quote from: GregL on November 20, 2010, 02:16:00 AM
Alex,
Your program + .bat file works on Vista (32-bit) too.
Thank you, Greg!
This "EB 80" 2-byte program was also discussed in the FASM forum:
http://board.flatassembler.net/topic.php?t=10847
here's the clean Masm version, without tricks like "JMP $-7Eh":
CGROUP group PSP, _TEXT
PSP segment at 0
db 82h dup (?)
cmdl:
db 7eh dup (?)
PSP ends
_TEXT segment 'CODE'
start:
jmp short cmdl
_TEXT ends
end start
to be linked with "link16 /tiny ..."
there is nothing wrong with this method, either...
.MODEL TINY
_TEXT SEGMENT WORD PUBLIC 'CODE'
ORG 82h
Branch:
ORG 100h
_main PROC NEAR
jmp Branch
_main ENDP
_TEXT ENDS
END _main
of course, you can use a Start: label instead of a _main proc, if you prefer
thing is - if you need a batch file to get the results, i say you have defeated the purpose of the contest :P
Quote from: dedndave on November 20, 2010, 11:32:55 AM
thing is - if you need a batch file to get the results, i say you have defeated the purpose of the contest :P
You don't need a batch file, actually. But you should know how to use
Alt nnn at the DOS prompt :bg
i know how to do it :P
but, who can remember the sequences :lol
it reminds me of booting a tape drive on a PDP11 with the front panel switches
a sequence which i, at one time, had memorized - now happily forgotten
at any rate, the point of the post: you don't need to open a segment at 0 for the PSP
the code segment naturally encompasses the PSP in a .COM program
Quote from: dedndave on November 20, 2010, 12:06:44 PM
at any rate, the point of the post: you don't need to open a segment at 0 for the PSP
the code segment naturally encompasses the PSP in a .COM program
You're right. I had the idea that with the AT segment there is no risk that a linker adds 256 null- bytes to "fill" the gap, but this isn't necessary. Also, some linkers won't accept an AT segment in a group.
Quote from: dedndave on November 20, 2010, 11:32:55 AM
thing is - if you need a batch file to get the results, i say you have defeated the purpose of the contest :P
Well, since I saw that other programs uses passed string as Message, that why I cannot use passed string for code?
The program itself is just vulnerable application, which allow execution of arbitrary code, code in shell-style. :P
So, my version is just from model line of: "http://www.masm32.com/board/index.php?topic=10252.msg125593#msg125593" :wink
Alex
Quote from: japheth on November 20, 2010, 07:53:22 AM
This "EB 80" 2-byte program was also discussed in the FASM forum:
I'm have nothing to say contrary. For 30 years of DOS existence, I'm sure - thousands of peoples reinvent the same many times.
Alex
Quote from: Antariy on November 20, 2010, 09:31:00 PM
I'm have nothing to say contrary. For 30 years of DOS existence, I'm sure - thousands of peoples reinvent the same many times.
My post was merely informational.
Quote from: japheth on November 21, 2010, 09:07:16 AM
My post was merely informational.
No problem, I'm understand that :U
Alex
QuoteYou're right. I had the idea that with the AT segment there is no risk that a linker adds 256 null- bytes to "fill" the gap, but this isn't necessary. Also, some linkers won't accept an AT segment in a group.
yes - that may happen if you stuck anything more than a label there
over the years, using different versions of different assemblers...
you can sometimes get away with DW ? - sometimes not
ORG xx LABEL DWORD or ORG xx BranchLabel: always seem to work
the only time i have used SEGMENT AT is when i wanted to access the interrupt vector table (even then it isn't needed)
or when writing ROMable code
it matters if you want to generate proper segment values in far addresses
as i said, it isn't needed when accessing the IVT, because i generally do not access that memory in 0000:0000 context
rather, i use something like XOR AX,AX - MOV DS,AX - then access the vector offsets