Going down the size optimization rabbit hole a little bit (not criticism, I just enjoy this sort of puzzle).
Two bytes shorter:
call print_str
ret
=>
jmp print_str
Three bytes shorter; this one may be a little too clever, since it depends on the low bit of CR0 being 0 initially: mov EAX, CR0
or EAX, 1
=>
mov EAX, CR0
inc AX
Also noticed a minor optimisation:
Could've been replaced with a 'lodsb', saving 2 bytes. Ditto for MOV BH/MOV BL with MOV BX. :-)