printf.c: No such file or directory [duplicate] - linux

I try to use printf from my assembler code, this is a minimal example which should just print hello to stdout:
.section .rodata
hello:
.ascii "hello\n\0"
.section .text
.globl _start
_start:
movq $hello, %rdi # first parameter
xorl %eax, %eax # 0 - number of used vector registers
call printf
#exit
movq $60, %rax
movq $0, %rdi
syscall
I build it with
gcc -nostdlib try_printf.s -o try_printf -lc
and when I run it, it seems to work: the string hello is printed out and the exit status is 0:
XXX$ ./try_printf
hello
XXX$ echo $?
0
XXX$
But when I try to capture the text, it is obvious, that something is not working properly:
XXX$ output=$(./try_printf)
XXX$ echo $output
XXX$
The variable output should have the value hello, but is empty.
What is wrong with my usage of printf?

Use call exit instead of a raw _exit syscall after using stdio functions like printf. This flushes stdio buffers (write system call) before making an exit_group system call).
(Or if your program defines a main instead of _start, returning from main is equivalent to calling exit. You can't ret from _start.) Calling fflush(NULL) should also work.
As Michael explained, it is OK to link the C-library dynamically. This is also how it is introduced in the "Programming bottom up" book (see chapter 8).
However it is important to call exit from the C-library in order to end the program and not to bypass it, which was what I wrongly did by calling exit-syscall. As hinted by Michael, exit does a lot of clean up like flushing streams.
That is what happened: As explained here, the C-library buffers the the standard streams as follows:
No buffering for standard error.
If standard out/in is a terminal, it is line-buffered.
If standard out/in is a not a terminal, it is fully-buffered and thus flush is needed before a raw exit system call.
Which case applies is decided when printf is called for the first time for a stream.
So if printf_try is called directly in the terminal, the output of the program can be seen because hello has \n at the end (which triggers the flush in the line-buffered mode) and it is a terminal, also the 2. case.
Calling printf_try via $(./printf_try) means that the stdout is no longer a terminal (actually I don't know whether is is a temp file or a memory file) and thus the 3. case is in effect - there is need for an explicit flush i.e. call to C-exit.

The C standard library often contains initialization code for the standard I/O streams — initialization code that you're bypassing by defining your own entry point. Try defining main instead of _start:
.globl main
main:
# _start code here.
and then build with gcc try_printf.s -o try_printf (i.e., without -nostdlib).

Related

segfault for simple close program in assembly

I just started to learn assembly by following "Programming From The Ground Up" and already hit my first issue with the first ever program. I got a segfault for the following code which is supposed to be an exit program:
.section .data
.section .text
.global _start
_start:
movl $1, %eax
movl $0, %edi
int $0x80
I've looked into it and one thing suggested was to not use int $0x80 anymore since its a legacy way to invoke system call so I tried to use syscall instead but it didn't fix it.
the commands I used are as follow:
as test.s -o test.o
ld test.o -o test
./test
I am using the Windows Subsystem for Linux.
I tried to look at it in a debugger and what I found was that after my code, there would be an endless stream of add %al, (%rax) with each memory address from 0x40100c and onwards having this line.
I have absolutely no idea what is happening and would appreciate any help.

Using printf in assembly leads to empty output when piping, but works on the terminal

I try to use printf from my assembler code, this is a minimal example which should just print hello to stdout:
.section .rodata
hello:
.ascii "hello\n\0"
.section .text
.globl _start
_start:
movq $hello, %rdi # first parameter
xorl %eax, %eax # 0 - number of used vector registers
call printf
#exit
movq $60, %rax
movq $0, %rdi
syscall
I build it with
gcc -nostdlib try_printf.s -o try_printf -lc
and when I run it, it seems to work: the string hello is printed out and the exit status is 0:
XXX$ ./try_printf
hello
XXX$ echo $?
0
XXX$
But when I try to capture the text, it is obvious, that something is not working properly:
XXX$ output=$(./try_printf)
XXX$ echo $output
XXX$
The variable output should have the value hello, but is empty.
What is wrong with my usage of printf?
Use call exit instead of a raw _exit syscall after using stdio functions like printf. This flushes stdio buffers (write system call) before making an exit_group system call).
(Or if your program defines a main instead of _start, returning from main is equivalent to calling exit. You can't ret from _start.) Calling fflush(NULL) should also work.
As Michael explained, it is OK to link the C-library dynamically. This is also how it is introduced in the "Programming bottom up" book (see chapter 8).
However it is important to call exit from the C-library in order to end the program and not to bypass it, which was what I wrongly did by calling exit-syscall. As hinted by Michael, exit does a lot of clean up like flushing streams.
That is what happened: As explained here, the C-library buffers the the standard streams as follows:
No buffering for standard error.
If standard out/in is a terminal, it is line-buffered.
If standard out/in is a not a terminal, it is fully-buffered and thus flush is needed before a raw exit system call.
Which case applies is decided when printf is called for the first time for a stream.
So if printf_try is called directly in the terminal, the output of the program can be seen because hello has \n at the end (which triggers the flush in the line-buffered mode) and it is a terminal, also the 2. case.
Calling printf_try via $(./printf_try) means that the stdout is no longer a terminal (actually I don't know whether is is a temp file or a memory file) and thus the 3. case is in effect - there is need for an explicit flush i.e. call to C-exit.
The C standard library often contains initialization code for the standard I/O streams — initialization code that you're bypassing by defining your own entry point. Try defining main instead of _start:
.globl main
main:
# _start code here.
and then build with gcc try_printf.s -o try_printf (i.e., without -nostdlib).

A simple assembly code cause a segment fault?

.section .data
.section .text
.globl _start
_start:
movl $1, %eax # this is the linux kernel command
# number (system call) for exiting
# a program
movl $4, %ebx # this is the status number we will
# return to the operating system.
# Change this around and it will
# return different things to
# echo $?
int $0x80 # this wakes up the kernel to run
# the exit command
But if I remove the last line of code int 0x80 , then it'll cause a segment fault.
I don't know why? Can anyone tell me.
Thanks for your time.
Thanks everyone. Now I get the answer.
Without the line of code int $0x80 , the system doesn't know that whether this application has ended or when this application ended. So it will cause crash.
If you remove the int 0x80 you will have a segmentation fault because it will begin executing whatever random bytes were in RAM immediately following your program. You really can't predict what will be there and other things can certainly happen, but a segfault is likely because the random data will very likely work out to be a memory access outside of your process memory.

x86 Assembly - printf doesn't print without "\n"

So I'm confused. I'm going through the book "Programming from the Ground Up" and am working with using libraries.
printf is working just fine so long as I include a "\n" in the string, but without it it will print absolutely nothing.
Any idea why this happens?
Code:
.section .data
my_str:
.ascii "Jimmy Joe is %d years old!\n\0"
my_num:
.long 76
.section .text
.globl _start
_start:
pushl my_num
pushl $my_str
call printf
movl $1, %eax
movl $0, %ebx
int $0x80
Also, when I use -m elf_i386 for 32-bit mode and -dynamic-linker /lib/ld-linux.so.2 -lc to link, I get the warning
ld: skipping incompatible /usr/lib64/libc.so when searching for -lc
If that makes any difference, or if anybody has any suggestions as to how to have it load the 32-bit library directly.
Thanks!
The problem is that printf by default just prints stuff into the stdout buffer. Things won't actually be printed until the buffer is flushed. The depends on the buffering mode of stdout, but, by default, it is line-buffered, which means it gets flushed every time you print a newline character.
To flush explicitly in C, you call fflush; you can do that in asm code with
pushl stdout
call fflush
addl $4, %esp
Alternately, you can call the stdlib exit function (which flushes all I/O buffers before actually exiting), instead of using the _exit system call, which does not.
It seems you try to link your 32-bit program against the (system default) 64Bit c library.
Check if you have libs32 packages installed.
To find out which libraries a program or other dynamically loads froum the LD_LIBRARY_PATH use ldd <name_of_your_binary>
As to why the newline is required I can only speculate that it flushes the output buffer.
See also Why does printf not flush after the call unless a newline is in the format string?

Linux 64 command line parameters in Assembly

This description is valid for Linux 32 bit:
When a Linux program begins, all pointers to command-line arguments are stored on the stack. The number of arguments is stored at 0(%ebp), the name of the program is stored at 4(%ebp), and the arguments are stored from 8(%ebp).
I need the same information for 64 bit.
Edit:
I have working code sample which shows how to use argc, argv[0] and argv[1]: http://cubbi.com/fibonacci/asm.html
.globl _start
_start:
popq %rcx # this is argc, must be 2 for one argument
cmpq $2,%rcx
jne usage_exit
addq $8,%rsp # skip argv[0]
popq %rsi # get argv[1]
call ...
...
}
It looks like parameters are on the stack. Since this code is not clear, I ask this question. My guess that I can keep rsp in rbp, and then access these parameters using 0(%rbp), 8(%rbp), 16(%rbp) etc. It this correct?
Despite the accepted answer being more than sufficient, I would like to give an explicit answer, as there are some other answers which might confuse.
Most important (for more information see examples below): in x86-64 the command line arguments are passed via stack:
(%rsp) -> number of arguments
8(%rsp) -> address of the name of the executable
16(%rsp) -> address of the first command line argument (if exists)
... so on ...
It is different from the function parameter passing in x86-64, which uses %rdi, %rsi and so on.
One more thing: one should not deduce the behavior from reverse engineering of the C main-function. C runtime provides the entry point _start, wraps the command line arguments and calls main as a common function. To see it, let's consider the following example.
No C runtime/GCC with -nostdlib
Let's check this simple x86-64 assembler program, which do nothing but returns 42:
.section .text
.globl _start
_start:
movq $60, %rax #60 -> exit
movq $42, %rdi #return 42
syscall #run kernel
We build it with:
as --64 exit64.s -o exit64.o
ld -m elf_x86_64 exit64.o -o exit64
or with
gcc -nostdlib exit64.s -o exit64
run in gdb with
./exit64 first second third
and stop at the breakpoint at _start. Let's check the registers:
(gdb) info registers
...
rsi 0x0 0
rdi 0x0 0
...
Nothing there. What about the stack?
(gdb) x/5g $sp
0x7fffffffde40: 4 140737488347650
0x7fffffffde50: 140737488347711 140737488347717
0x7fffffffde60: 140737488347724
So the first element on the stack is 4 - the expected argc. The next 4 values look a lot like pointers. Let's look at the second pointer:
(gdb) print (char[5])*(140737488347711)
$1 = "first"
As expected it is the first command line argument.
So there is experimental evidence, that the command line arguments are passed via stack in x86-64. However only by reading the ABI (as the accepted answer suggested) we can be sure, that this is really the case.
With C runtime
We have to change the program slightly, renaming _start into main, because the entry point _start is provided by the C runtime.
.section .text
.globl main
main:
movq $60, %rax #60 -> exit
movq $42, %rdi #return 42
syscall #run kernel
We build it with (C runtime is used per default):
gcc exit64gcc.s -o exit64gcc
run in gdb with
./exit64gcc first second third
and stop at the breakpoint at main. What is at the stack?
(gdb) x/5g $sp
0x7fffffffdd58: 0x00007ffff7a36f45 0x0000000000000000
0x7fffffffdd68: 0x00007fffffffde38 0x0000000400000000
0x7fffffffdd78: 0x00000000004004ed
It does not look familiar. And registers?
(gdb) info registers
...
rsi 0x7fffffffde38 140737488346680
rdi 0x4 4
...
We can see that rdi contains the argc value. But if we now inspect the pointer in rsi strange things happen:
(gdb) print (char[5])*($rsi)
$1 = "\211\307???"
But wait, the second argument of the main function in C is not char *, but char ** also:
(gdb) print (unsigned long long [4])*($rsi)
$8 = {140737488347644, 140737488347708, 140737488347714, 140737488347721}
(gdb) print (char[5])*(140737488347708)
$9 = "first"
And now we found our arguments, which are passed via registers as it would be for a normal function in x86-64.
Conclusion:
As we can see, the is a difference concerning passing of command line arguments between code using C runtime and code which doesn't.
It looks like section 3.4 Process Initialization, and specifically figure 3.9, in the already mentioned System V AMD64 ABI describes precisely what you want to know.
I do believe what you need to do is check out the x86-64 ABI. Specifically, I think you need to look at section 3.2.3 Parameter Passing.

Resources