Printf without newline in assembly - c

I've recently read this article on using printf and scanf in assembly:
Meaning of intfmt: db "%d", 10, 0 in assembly
In particular it says
"In printf, the newline prints a newline and then (if the output is in line buffered mode, which it probably is), flushes the internal output buffer so you can actually see the result. So when you remove the 10, there's no flush and you don't see the output."
However I do not know what to do if I do not want a newline after my output in my assembly file.
Here's a simple test file I've written to try printing without a newline:
extern printf
LINUX equ 80H ; interupt number for entering Linux kernel
EXIT equ 60 ; Linux system call 1 i.e. exit ()
section .data
int_output_format: db "%ld", 0
segment .text
global main
main:
mov r8, 10
push rdi
push rsi
push r10
push r9
mov rsi, r8
mov rdi, int_output_format
xor rax, rax
call printf
pop r9
pop r10
pop rsi
pop rdi
call os_return ; return to operating system
os_return:
mov rax, EXIT ; Linux system call 1 i.e. exit ()
mov rdi, 0 ; Error code 0 i.e. no errors
syscall ; Interrupt Linux kernel 64-bit
but as the article I've read suggests stdout isn't being flushed. I was thinking perhaps I need to somehow flush after I output the number? But I'm really not sure.
I am using the NASM assembly language.
Thanks in advance!

fflush() flushes buffered output in line or full-buffered stdio streams:
extern fflush
...
xor edi, edi ; RDI = 0
call fflush ; fflush(NULL) flushes all streams
...
Alternatively, mov rdi, [stdout] / call fflush also works to flush only that stream. (Use default rel for efficient RIP-relative addressing, and you'll need extern stdout as well.)

Call fflush(stdout); to display what's currently sitting in the buffers.

For Windows 32-bit mode (FASM):
push [_iob]
call [fflush] ; call into DLL. Callee-pops calling convention
GNU/Linux 32-bit mode (NASM)
extern fflush
extern stdout
...
push dword [stdout]
call fflush ; linker takes care of PLT stub for dynamic linking (in a non-PIE executable)
add esp, 4 ; caller-pops calling convention
etc...

The other possibility would be to remove the default line buffering of the stdoutstream. Here the C call to do that. Translation to assembly let as exercice, as I don't think it makes even sense to do file/stream I/O in ASM, the cost/benefit is tremendously wrong.
setvbuf(stdout, NULL, _IONBF, 0);
This way every printf (and fputs, putc, puts etc...) would have an implicit fflush

My answer is for those searching a fast bypass to the problem, not an actual fix.
I was attempting to output the number 1234 one digit at a time and encountered the same issue as those here. After having no success with the mentioned solutions, and not wanting to spend more than a few minutes on this, I have found an easy way to display the number.
In your output string formats, simply have an output string that is an empty line (with the newline ofcourse).
Digit_out: db "%u", 0
Number_end: db "", 10, 0
Output as you would; in my case I had 4 pushes of digit_out (with 4 pushes of the digits themselves) and 4 calls to printf.
Once this is done, push Number_end and do a final call to printf. The entire number will then show :)

Related

Segmentation fault error when using fgets in assembly?

I use the fgets() function in assembly and it should work, but I have a problem with my buffer. Is there a way to define a char pointer? I ask because the function needs a char pointer as the first argument.
Here you can see my code:
; nasm fgets.asm -f elf64 -o fgets.o
; gcc -no-pie fgets.o
; ./a.out
; Define fgets as an external function
extern fgets
SECTION .DATA
buffer: db "0000000000", 0
SECTION .TEXT
global main
main:
push rbp ; Push stack
; Set up parameters and call the C function
mov rdi, buffer
mov rsi,10
mov rdx, 1
mov rax,0
call fgets
pop rbp ; Pop stack
mov rax,0 ; Exit code 0
ret ; Return
I want to read something from the stdin which is a maximum of 10 characters long.
A FILE * is not a file descriptor. Instead of passing 1 like you do, pass [stdin] (this works because stdin is a global pointer in glibc, and the keyword stdin in NASM is a pointer to that):
mov rdx, [stdin]
If you use GAS, this will work:
mov stdin, %rdx
However, you should probably be using RIP-relative addressing; this allows your executable to be relocated and is required for PIE (position-independent executable)s, which are the default now. In NASM, simply put this at the top of the file:
default rel
In GAS, it's a bit more complicated. You have to add (%rip) to all the external symbols you use, like this:
mov stdin(%rip), %rdx
This loads the memory located at stdin (which is the 8-byte FILE * pointer you're looking for) into rdx.
fgets takes a FILE * pointer arg, not an integer file descriptor, as the 3rd arg.
Also, 1 is the stdout file descriptor, not stdin. But anyway, when fgets dereferences 1 as a pointer it segfaults. You could have seen this using a debugger to find the instruction that faulted.
In C you'd call fgets(buf, len, stdin). The global variable stdin is a pointer of type FILE *stdin. This pointer value (to an opaque FILE struct) is itself stored in memory at the symbol address stdin. (Glibc's startup code initializes this pointer to point at a FILE struct it allocates).
Therefore you want to load a qword pointer from static storage as the 3rd arg for fgets. You could have seen this yourself by looking at compiler output for the C function.
default rel ; Use RIP-relative addressing by default
extern stdin
extern fgets
...
main:
push rax ; dummy push to realign the stack by 16
...
lea rdi, [buffer] ; RIP-relative LEA, or mov edi, buffer in a non-PIE
mov esi, buffer.len
mov rdx, [stdin]
call fgets
...
pop rcx ; dummy pop to readjust RSP
ret
section .bss
buffer: resb 11 ; reserve 11 bytes, zero-filled
.len equ $ - buffer
Note that it's not just lea rdx, [stdin] or mov edx, stdin to put the address of the stdin variable itself in a register. fgets takes the pointer arg by value, not as a pointer to a pointer, and it's not FILE stdin, it's FILE *stdin.
I got the assembler to calculate the length of buffer for me. I filled it with zero bytes instead of ASCII '0' characters.
fgets() reads at most len-1 bytes, and writes a terminating \0 after those, so you need to pass 11 (the size of the full buffer) to read up to 10 bytes.
fgets isn't variadic so you don't need to zero AL before calling it.

NASM Assembly while loop counter

I'm writing a while loop in assembly to compile in the Linux terminal with nasm and gcc. The program compares x and y until y >= x and reports number of loops at the end. Here's the code:
segment .data
out1 db "It took ", 10, 0
out2 db "iterations to complete loop. That seems like a lot.", 10, 0
x db 10
y db 2
count db 0
segment .bss
segment .text
global main
extern printf
main:
mov eax, x
mov ebx, y
mov ecx, count
jmp lp ;jump to loop lp
lp:
cmp ebx, eax ;compare x and y
jge end ;jump to end if y >= x
inc eax ;add 1 to x
inc ebx ;add 2 to y
inc ebx
inc ecx ;add 1 to count
jp lp ;repeat loop
end:
push out1 ;print message part 1
call printf
push count ;print count
call printf
push out2 ;print message part 2
call printf
;mov edx, out1 ;
;call print_string ;
;
;mov edx, ecx ;these were other attempts to print
;call print_int ;using an included file
;
;mov edx, out2 ;
;call print_string ;
This is compiled and run in the terminal with:
nasm -f elf test.asm
gcc -o test test.o
./test
Terminal output comes out as:
It took
iterations to complete loop. That seems like a lot.
Segmentation fault (core dumped)
I can't see anything wrong with the logic. I think it's syntactical but we've only just started learning assembly and I've tried all sorts of different syntax like brackets around variables and using ret at the end of a segment, but nothing seems to work. I've also searched for segmentation faults but I haven't found anything really helpful. Any help would be appreciated because I'm an absolute beginner.
The reason it crashes is probably that your main function doesn't have a ret instruction. Also be sure to set eax to 0 to signal success:
xor eax, eax ; or `mov eax, 0` if you're more comfortable with that
ret
Additionally, global variables designate pointers, not values. mov eax, x sets eax to the address of x. You need to write back to it if you want anything to happen (or not use global variables).
Finally, you're calling printf with a single non-string argument:
push count ;print count
call printf
The first argument needs to be a format string, like "%i". Here, count is a pointer to a null byte, so you get nothing instead. Off my head, you should try this:
out3 db "%i ", 0
; snip
push ecx
push out3
call printf
I think your problem might just be that you are referencing the addresses of your constants and not their intrinsic value. One must think of a label in nasm as a pointer rather than a value. To access it you just need to use [label]:
segment .data
x dw 42
segment .text
global main
extern printf
main:
mov eax, x
push eax
call printf ; will print address of x (like doing cout<<&x in C++)
mov eax, [x]
push eax
call printf ; will print 42
sub esp, 8
xor eax, eax
ret
PS:I don't think anyone has mentioned it but volatile registers are modified very often when calling external code (C or C++ or other) since at compilation those functions you use are "translated" to assembly and then linked with your asm file. The PC is not a human so it is not distinguishing between what was written in high-level or low-level, the processor is just reading opcodes and operands stored in registers and memory, hence why an external function when using low-level language (call printf) is going to modify (or not! always depends on compiler and architecture) registers that you are also using.
To solve this there are various solutions:
You check what registers are not being modified by using gcc your_c_file.c -S and then in the file your_c_file.swill be the pre-prepared assembly code your compiler has produced from your C file. (It tends to be quite hard to figure out what is what and if you are going to use this method check out Name Mangling, to see how func names will be changed.)
Push all the registers you want to save to stack, and then after the call pop them back to their registers keeping in mind LIFO method.
Use the instructions PUSHA and POPAwhich push or pop all registers respectively.
This is the NASM manual chapter 3 which explains the basis of the language to use: http://www.csie.ntu.edu.tw/~comp03/nasm/nasmdoc3.html
Hope you managed to solve it.

How can passing a deviant number of function parameters in C still end up working as intended?

Let's take this codegolf example, which reverses the stdin character buffer, and prints it on stdout:
main(_){write(read(0,&_,1)&&main());}
Here write() prints the intended output even though it seems to make do with only 1 parameter passed to it. For comparison, here's the actual write() prototype which clearly specifies 3 parameters:
ssize_t write(int fildes, const void *buf, size_t nbyte);
Moreover, in the example above, the only parameter passed to write() is (as far as I can tell) not even the 1st one, but the 2nd, which corresponds to the buffer pointer. So how are the file descriptor and size values set correctly here? UPDATE: the only argument explicitly passed is argument 1. See my answer for more information.
Can anyone give a precise explanation for this hack?
It's taking advantage of ANSI C89's implicit declaration of functions. (Search implicit declaration here http://flash-gordon.me.uk/ansi.c.txt)
This code golfer must have a system with a syscall called write that defaults to stdout.
This program doesn't work on my system.
Update:
The program works for me if I compile it as a 32-bit application, which gave me a hint as to what's going on.
read is writing to the location of the first argument to main, which is usually argc. If write is the three argument write, then the value at the address of argc to the current call to main must be passed as the second argument to write, and the value of 1 must be passed as the third argument of write, which is the value of argc, because no arguments are passed to the program.
It has something to do with abusing the call stack as the arguments to write.
Here's the x86 asm, if someone wants to step through and explain this one. I'm currently working on it, but haven't figured it out completely yet.
main:
push ebp
mov ebp, esp
and esp, -16
sub esp, 16
mov DWORD PTR [esp+12], eax
mov DWORD PTR [esp+8], 1
lea eax, [esp+12]
mov DWORD PTR [esp+4], eax
mov DWORD PTR [esp], 0
call read
test eax, eax
je .L2
call main
test eax, eax
je .L2
mov eax, 1
jmp .L3
.L2:
mov eax, 0
.L3:
mov DWORD PTR [esp], eax
call write
leave
ret
I think I've figured this out now. As OregonTrail crucially discovered, the code example in question only works on 32-bit systems. This lead to me suspect the code relies on the commonly used 32-bit calling conventioned called CDECL. To quote this wikibook:
In the CDECL calling convention the following holds:
Arguments are passed on the stack in Right-to-Left order, and return values are passed in eax.
The calling function cleans the stack. This allows CDECL functions to have variable-length argument lists (aka variadic functions). For this reason the number of arguments is not appended to the name of the function by the compiler, and the assembler and the linker are therefore unable to determine if an incorrect number of arguments is used.
In chronological order:
1 is pushed to the stack as the 3rd parameter (length) to read().
the pointer &_ to a char buffer is pushed to the stack as the 2nd parameter to read().
0 is pushed to the stack as the 1st parameter (the file descriptor of stdin) to read().
read() is called, returns, and now write() is about to be called.
The assembly was generated based on the premise given in the source code that write() takes only 1 paramater, so only one item is "cleaned"/popped off the stack.
1 is pushed to the stack as the 1st parameter (the file descriptor of stdout) to write(), because 1 is the result of the write(read(0,&_,1)&&main() expression.
write() needs 3 parameters so reads the top 3 items on the stack.
So why does write() write correctly? Because the 2nd and 3d item on the stack have not been touched since they were put there for read() to read, and the 2nd and 3rd parameters of read() and write() in this case need to hold the exact same values anyway: a pointer to the char buffer and a length of 1.

itoa implementation crashing?

I am trying to implement atoi in assembly (the netwide assembler). I have verified that my approach is valid by inspecting the register values with a debugger. The problem is that the application will crash when it is about to exit. I am afraid my program is corrupting the stack somehow. I am linking against the GCC stdlib to allow the use of the printf function. I noticed it mutated the registers which caused unexpected behaviour (extensive iterations over values I did not recognize), however I solved this by storing the value of EAX inside EBX (not modified by printf) and then restoring the value after the function call. This is why I have been able to confirm that the program now behaves as it is supposed to by singlestepping through the algorithm AND confirm that the program crashes as it is about to terminate.
Here is the code:
global _main
extern _printf
section .data
_str: db "%d", 0
section .text
_main:
mov eax, 1234
mov ebx, 10
call _itoa
_terminate:
ret
_itoa:
test eax, eax
jz _terminate
xor edx, edx
div ebx
add edx, 30h
push eax
push edx
push _str
call _printf
add esp, 8
pop eax
jmp _itoa
And here is the stackdump:
Exception: STATUS_ACCESS_VIOLATION at eip=00402005
eax=00000000 ebx=00000000 ecx=20000038 edx=61185C40 esi=612A3A7C edi=0022CD84
ebp=0022ACF8 esp=0022AC20 program=C:\Cygwin\home\Benjamin\nasm\itoa.exe, pid 3556, thread main
cs=001B ds=0023 es=0023 fs=003B gs=0000 ss=0023
Stack trace:
Frame Function Args
0022ACF8 00402005 (00000000, 0022CD84, 61007120, 00000000)
End of stack trace
EDIT: Please note that the stackdump really is not that relevant anymore as the program no longer crashes, it just displays an incorrect value.
I'm not familiar with your platform, but I would expect you need to restore the stack by popping off the pushed values after calling printf().
Since printf() doesn't know how many arguments will be passed, it can't restore the stack. Your code pushes arguments that are never popped off. So when your procedure returns, it gets the return address from the data that was pushed on the stack, which are not going to point to valid code. And that would be your access violation.

Explain the strange assembly of empty C `main` function by Visual C++ compiler

I just noticed some strange assembly language code of empty main method.
//filename: main.c
void main()
{
}
disassembly:
push ebp
mov ebp,esp
sub esp,0C0h; why on the earth is it reserving 192 bytes?
push ebx
push esi
push edi ; good compiler. Its saving ebx, esi & edi values.
lea edi,[ebp-0C0h] ; line 1
mov ecx,30h ; line 2
mov eax,0CCCCCCCCh ; line 3
rep stos dword ptr es:[edi] ; line 4
xor eax,eax ; returning value 0. Code following this line is explanatory.
pop edi ; restoring the original states of edi,esi & ebx
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
why on the earth is it reserving 192 bytes for function where there aren't any variables
whats up with the four lines: line 1, line 2, line 3, line 4? what is it trying to do & WHY?
Greg already explained how the compiler generates code to diagnose uninitialized local variables, enabled by the /RTCu compile option. The 0xcccccccc value was chosen to be distinctive and easily recognized in the debugger. And to ensure the program bombs when an uninitialized pointer is dereferenced. And to ensure it terminates the program when it is executed as code. 0xcc is pretty ideal to do all of these jobs well, it is the instruction opcode for INT3.
The mysterious 192 bytes that are allocated in the stack frame are there to support the Edit + Continue feature, /ZI compile option. It allows you to edit the code while a breakpoint is active. And add local variables to a function those 192 bytes are available to provide the space for those added locals. Exceeding that space will make the IDE force you to rebuild your program.
Btw: this can cause a problem if you use recursion in your code. The debug build will bomb with this site's name a lot quicker. Not normally much of an issue, you debug with practical dataset sizes.
The four code lines you've indicated are the debug build clearing out the local variable space with the "clear" special value (0xCCCCCCCC).
I'm not sure why there are 192 bytes of seemingly dead space, but that might be VC++ building some guard space into your local variable area to try to detect stack smashing.
You will probably get a very different output if you switch from Debug to Release build.

Resources