I was doing some test in assembly calling c functions and I get what I think es a strange behavior when using ansi escape codes and calling a c function that uses printf.
This is the assembly part:
section .data
red db 27,"[31;1m",0
redlen equ $ - red
cyan db 27,"[36;1m",0
cyanlen equ $ - cyan
colorReset db 27,"[0m",0
colorResetLen equ $ - colorReset
section .text
extern printLetter
extern letter
global main
main:
mov BYTE [letter], 'H'
call ansiSetRed
call printLetter
mov BYTE [letter], 'e'
call ansiSetCyan
call printLetter
mov BYTE [letter], 'l'
call ansiReset
call printLetter
mov BYTE [letter], 'l'
call ansiSetRed
call printLetter
mov BYTE [letter], 'o'
call ansiSetCyan
call printLetter
mov BYTE [letter], '!'
call ansiReset
call printLetter
mov BYTE [letter], 10
call printLetter
ret
ansiSetRed:
mov rax, 1
mov rdi, 1
mov rsi, red
mov rdx, redlen
syscall
ret
ansiSetCyan:
mov rax, 1
mov rdi, 1
mov rsi, cyan
mov rdx, cyanlen
syscall
ret
ansiReset:
mov rax, 1
mov rdi, 1
mov rsi, colorReset
mov rdx, colorResetLen
syscall
ret
Looks long but all that i does is define some strings with ansi codes at the beginning, one to set foreground color to red, one for cyan and one to reset the colors.
Then I have functions that print this ansi strings using syscall write.
The main function is just supposed to print "Hello!" alternating the color of each letter, by first calling an assembly function that prints the corresponding ansi string, and then calling an extern c function that prints a character that is stored in a global variable.
Here the c part:
#include <stdio.h>
char letter;
void printLetter(void) {
printf("%c", letter);
}
When I run it, the Message "Hello!" is displayed all white like if the assembly part was not printing the ansi codes
but if I change the c part to just print a new line after each character:
#include <stdio.h>
char letter;
void printLetter(void) {
printf("%c\n", letter);
}
Then the letters show one of each color as I expected at the beginning.
What can be the cause of this behavior?
That's because stdio (the C standard I/O package) uses line buffering for stdout if stdout goes to a terminal. That means that data you write is not immediately sent to the terminal but rather buffered until a whole line is available. What you observe in your first program (hello on a line) is that no character of Hello
is actually written until you call printLetter
with a line feed, causing the buffer for stdout to be flushed to the terminal.
I see the following approaches to solve your problem (any single of them does the trick, but use only one approach):
ansiSetRed
etc. to call fwrite
instead of directly executing a write
system call. This should make buffering work as expected.setbuf(stdout, NULL)
to turn off buffering before writing any data.stderr
instead of stdout
as stderr
is unbufferedfflush(stdout)
after each printf
to manually flush stdout
.printLetter
to use the system call write
instead of printf
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With