I’m trying to write a Python script to test the output of some various code I’ve written in assembly against an expected output. However I am having difficulty redirecting the output into a file.
I have written the following:
extern printf
LINUX equ 80H ; interupt number for entering Linux kernel
EXIT equ 1 ; Linux system call 1 i.e. exit ()
section .data
intfmt: db "%ld", 10, 0
segment .text
global main
main:
push rax
push rsi
push rdi
mov rsi, 10
mov rdi, intfmt
xor rax, rax
call printf
pop rdi
pop rsi
pop rax
call os_return ; return to operating system
os_return:
mov rax, EXIT ; Linux system call 1 i.e. exit ()
mov rbx, 0 ; Error code 0 i.e. no errors
mov rcx, 5
int LINUX ; Interrupt Linux kernel
I then procede to do the following in the console:
nasm -f elf64 basic.asm
gcc -m64 -o basic basic.o
./basic
Which outputs 10 to the screen.
However if I enter
./basic > basic.txt
cat basic.txt
basic.txt appears as an empty file.
My overall goal is to write a shell script that loops over each assembly file to compiling and run the file and then redirect the output of this script into a file. However I cannot do this until I can get it to work with a single file.
I was wondering it it was something to do with my call to printf? Although I was under the illusion that printf writes to STDOUT.
Thanks in advance!
Your redirection is correct; the problem must be in the assembly you are generating.
The tool to debug such problems is
strace. Running your program understrace, shows:You can clearly see your desired output, but also some “stray” write. Where is that write coming from?
GDB to the rescue:
Good, this is the expected call to write.
This is just the return from syscall. Did write succeed? (We know it did, since we see its output above, but let’s confirm.)
Good. Write wrote the expected 3 characters.
This is the write we didn’t expect. Where from?
So your syscall executed
write(2)instead of expectedexit(2). Why did this happen?Because you’ve defined
EXITincorrectly:From above, you can tell that
EXITshould be 1 in 32-bit mode, but 60 in 64-bit mode.What about NR_write? Is it 1 in 64-bit mode?
Indeed it is. So we have solved the “where did stray write come from?” puzzle. Fixing
EXITto be 60, and rerunning understrace, we now see:That still isn’t right. We should be calling
_exit(0), not_exit(1). A look at thex86_64ABI, reveals that your register use is incorrect: syscall number should be in%rax, but the arguments in%rdi,%rsi,%rdx, etc.Fixing that (and deleting bogus
mov rcx, 5), we finally get desired output fromstrace:So now we are ready to see if above fixes also fixed the redirection problem.
Re-running under strace, with output redirected:
Clearly our call to
writeis missing. Where did it go?Well,
stdoutoutput is line buffered by default, and gets fully buffered when redirected to a file. Perhaps we are missing anfflushcall?Indeed, adding a call to
fflush(NULL)just before exiting solves the problem:I hope you’ve learned something today (I did 😉