The relevant code is actually in asm_io.asm (which is assembled to asm_io.o and linked with your code)...
print_int:
enter 0,0
pusha
pushf
push eax
push dword int_format
call _printf
pop ecx
pop ecx
popf
popa
leave
ret
As you can see, it even preserves flags (print_nl likewise). You should be able to remove the "push ebx", "pop ebx" (both or neither, please!) and still have it work. What Bryant did that actually fixed it was:
xor eax,eax
cycle:
push ebx
mov al,[ostring+ebx*1]
instead of:
mov eax,[ostring+ebx*1]
With eax there, you get 4 bytes of your string in eax, and print_int prints all 4 of 'em as a single number. By zeroing eax first, and then loading just al from your string, print_int prints all of eax as a single number - but it's the number we want.
Or is it? Your example appears to show the bytes of the string represented in hex. That's not what print_int does (it prints a decimal representation). It would be trivial (for an experienced programmer) to add a "print_hex" function - a duplicate of "print_int", but with "push dword hex_format"... added above as hex_format db "%X", 0... add print_hex to the list of globals here, and to the list of externs in asm_io.inc... reassemble asm_io.asm... and you should be able to use print_hex just like print_int. I don't imagine you're supposed to do that as homework, though.
If it's really supposed to be hex, you may be expected to convert to a hex representation and use print_char to display it. If that's the case, you have more work to do.
Best,
Frank