How to make the stack of a C program executable? - c

Is there a way to make the stack of a C program executable through compilation?
I did
$ gcc -o convert -g convert
and then run
$ readelf -l convert
to check if the stack is executable but the output was:
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4

The correct way to make the stack executable doesn't require that stack canaries be disabled, unlike what the accepted answer suggests.
Here's the correct way:
gcc -z execstack ...
What this does is, the -z option of gcc is passed to the linker [source]:
keyword
-z is passed directly on to the linker along with the keyword keyword. See the section in the documentation of your linker for permitted
values and their meanings.
From man ld [source]:
execstack
Marks the object as requiring executable stack.

-fno-stack-protector should do the trick for you.

Related

GDB is not stopping at breakpoint when debugging a PIE kernel

I have a position independent kernel that gets compiled and linked like this:
gcc -Og -g -Werror -nostdlib -o kernel.o -c kernel/main.c
gcc -nostdlib -ffreestanding -e kmain -o kernel.elf kernel.o
The problem I have is that when I launch the bootloader in qemu like this:
qemu-system-x86_64 -s -S -bios /usr/share/ovmf/OVMF.fd -drive file=/os.img,format=raw
and then do this in gdb:
target remote :1234
symbol-file kernel.elf
break kmain
continue
layout next
it will not stop at the breakpoint, it just keeps continuing.
This is how I call kmain from the bootloader:
int (*kmain)(void*) = (int(*)(void*)) (buf + elf->entry);
stat = uefi_call_wrapper(BS->ExitBootServices, 2, IH, mapkey);
kmain(&bootinfo);
where buf is the beginning of the kernel.elf file and this is the kmain()
int kmain(Bootinfo *Bootinfo) {
int x = 1;
int y = x;
return 0;
}
Someone told me this:
"If your kernel is position-independent or relocatable and your bootloader can handle the runtime requirements of position-independent or relocatable code, you need to tell GDB that you've loaded your kernel at a different base address."
How can I tell gdb that my kernel is loaded at a different base address?
Is the base address in this case buf?
if I disassemble kmain in gdb this is what it shows:
gdb kmain
in gdb the command symbol-file can be given a -o offset argument:
symbol-file [ filename [ -o offset ]]
If an optional offset is specified, it is added to the start address of each section in the symbol file. This is useful if the program is relocated at runtime, such as the Linux kernel with kASLR enabled.
source: https://sourceware.org/gdb/onlinedocs/gdb/Files.html

Compiling statically libc C code and ASM code

I have ASM code:
extern my_func
extern printf
extern exit
global _start
section .data
...
section .text
_start:
...
call printf
...
call my_func
...
call exit
and C code:
int my_func(int a, int b)
{
return a+b;
}
I'm using fedora on 64-bit machine. I want the executable be 32-bit.
For dynamic linking I do:
nasm -f elf32 asm.asm ; this gives me asm.o
gcc -m32 -Wall -c c_code.c ; this gives me c_code.o
ld c_code.o asm.o -melf_i386 -L /usr/lib/ -lc -I /lib/ld-linux.so.2 ; this gives me a.out which runs fine and weights 5601 bytes.
What I want to do is link libc statically. I do the following:
gcc -o a2.out -m32 -static -m32 asm.o c_code.o
And I get error:
asm.o: In function `_start':
asm.asm:(.text+0x0): multiple definition of `_start'
/usr/lib/gcc/x86_64-redhat-linux/4.8.3/../../../../lib64/crt1.o:(.text+0x0):
first defined here
collect2: error: ld returned 1 exit status
Then I change _start to main in ASM code and the whole thing links fine! ldd shows "not a dynamic executable". But the file created weights 721067 bytes! I think that it compiles statically a lot of unnecessary code.
So, my 1st question is:
1) How can I link statically only libc for the required printf and exit functions?
When I try
gcc -m32 -o a3.out -lc asm.o c_code.o ; ASM file has main instead of _start
I get a file that weights 7406 bytes. ldd shows the same dynamic libraries as for the a.out which weights 5601 bytes.
2) Why is that difference? Looks like some additional code that "connects" _start with main in my code...
3) What is the difference between linking with gcc and ld?
Thanks a lot for your attention!
1) How can I link statically only libc for the required printf
and exit functions?
Try compiling with -nostartfiles -static -nostdlib -lc which will avoid adding crt1.o and crtend.o. But keep in mind that this will disable all Glibc initialization code so some Glibc functions will fail to work.
2) Why is that difference? Looks like some additional code
that "connects" _start with main in my code...
GCC adds start files (crt*.o) which perform initialization. See the many online articles for details (e.g. this one).
3) What is the difference between linking with gcc and ld?
Already answered above but in general you can run gcc -v and inspect ld's (or collect2's) arguments.

`bash: ./a.out: No such file or directory` on running executable produced by `ld`

Here is a Hello World code in C:
// a.c
#include <stdio.h>
int main() {
printf("Hello world\n");
return 0;
}
I compile it as gcc a.c, which produces a.out as expected and ./a.out prints Hello world... as expected.
Now if I do the compile and link separately:
gcc -c a.c; ld -lc a.o, it run the a.out produced as ./a.out I get the message:
bash: ./a.out: No such file or directory
I Googled that error and it seems that happens when the executable produced is a 32-bit ELF and the machine architecture is 64-bit.
I'm running a 64-bit machine and running file a.out gives:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Why does this happen?
EDIT:
Output of uname -m
$ uname -m
x86_64
Output of ldd a.out
$ ldd a.out
linux-vdso.so.1 => (0x00007ffeeedfb000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa13a7b8000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa13abab000)
gcc a.c produces a.out which runs correctly.
ld -lc a.o
There are several things wrong with this command line:
In general, user-level code should never use ld directly, and always use appropriate compiler front end (gcc here) to perform the link.
As you have discovered, the link command line that gcc constructs is quite complicated, and the command line that you've accepted in Joan Esteban's answer is wrong.
If you want to see the actual link command, examine output from gcc -v a.o.
Also note that link command changes significantly when you change gcc command only slightly (e.g. some OSes require different crt1.o depending on whether you are linking multi-threaded executable or not), and the command line is always OS-specific (which is one more reason to never use ld directly).
Libraries should follow object files on command line. So ld -lc a.o is never correct, and should always be (a variant of) ld a.o -lc. Explanation.
Link dynamic executables with gcc foo.o (to use the right paths for CRT and libc, and the dynamic linker / ELF interpreter ld-linux-x86-64.so.2).
Or gcc -nostartfiles foo.o for libc but not CRT _start, if you have a hand-written _start
(For static executables without libc or CRT, you can use ld directly or gcc -nostdlib -static.)
gcc -v foo.o will show you the actual paths GCC used on your system.
The other answers only address how to avoid this1, not the actual question of what happened.
The gcc -c a.c; ld -lc a.o commands you gave produce a pretty obvious warning:
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400260
So even if this file could be executed, it will probably crash right away. See #EmployedRussian's answer for an explanation of what you should have done.
The question of why it can't even be executed is still interesting:
$ strace ./a.out
execve("./a.out", ["./a.out"], [/* 72 vars */]) = -1 ENOENT (No such file or directory)
execve(2) returns ENOENT because it can't find the interpreter (which I figured out from file and so on, see below). You'd get the same error from trying to run a file that started with
#!/usr/non-existant-path/bin/bash
As you discovered, the usual reason for this error message is when running an ELF binary on a system without the right dynamic linker and dynamic libraries installed (e.g. a 64bit system without 32bit support installed). In your case, it's because you used a bad link command and made a dynamic executable with a bad interpreter path.
I'm on Ubuntu 15.10, where GNU file version 5.22 reports:
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64.so.1, not stripped
There is no /lib/ld64.so.1 on my system. ldd output is confusing, because ldd uses its default ELF interpreter, not the one specified by the binary.
$ ldd a.out
linux-vdso.so.1 => (0x00007ffc18d2b000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0e0a79f000)
/lib/ld64.so.1 => /lib64/ld-linux-x86-64.so.2 (0x0000559dbc9d2000)
So it assumes that the runtime interpreter in the binary resolved to the one ldd used itself, I guess.
Your ldd output is probably from an old version too, since it just shows /lib64/ld-linux-x86-64.so.2 for that line. Not taking a bad guess is probably better behaviour, for a weird case like this, but doesn't help you see that your binary has a weird interpreter path.
readelf -l a.out
will decode the ELF headers for you, including the interpreter path. (Thanks to #EmployedRussian's comment for pointing this out.)
Use that:
ld -o a.out -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -lc c.o /usr/lib/crtn.o

How to call c functions that call c standard library in nasm?

First I want to clarify that I know this question might have been answered hundreds of times. However after hours of Google search I simply couldn't find anything that's exactly what I want. Also even though I've been writing c programs for quite a while, I'm kind of new to nasm and ld. So I would really appreciate it if I can get a simple answer without having to read a whole nasm/ld tutorial or the complete manual.
What I want to do is:
say I have a function written in c that calls some function in the c standard library:
/* foo.c */
#include <stdio.h>
void foo(int i)
{
printf("%d\n", i);
}
I want to call this function in nasm so I tried this:
; main.asm
global _start
extern foo
section .text
_start:
push 1234567
call foo
add esp, 4
mov eax, 1
xor ebx, ebx
int 80h
Then I tried to compile them and run:
[user ~/Documents/asm/callc]#make all
nasm main.asm -felf
gcc -c foo.c -o foo.o -m32
ld -o main main.o foo.o -melf_i386 -lc
[user ~/Documents/asm/callc]#ls
foo.c foo.o main main.asm main.o Makefile
[user ~/Documents/asm/callc]#./main
bash: ./main: No such file or directory
[user ~/Documents/asm/callc]#bash main
main: main: cannot execute binary file
I didn't get any errors but apparently I couldn't run the executable output file.
If the c function doesn't call any library functions then the code above can be compiled and it will run without any problems. I also figured out a way to call library functions directly in nasm and use gcc to produce the final executable file. But none of them is exactly what I want.
EDIT:
1. I'm running 64-bit Ubuntu but I'm trying to write 32-bit programs so I used flags like -m32 and -melf_i386.
2. Output of file *:
[user ~/Documents/asm/sof]#file *
foo.c: C source, ASCII text
foo.c~: empty
foo.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
main: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
main.asm: C source, ASCII text
main.asm~: empty
main.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
Makefile: makefile script, ASCII text
Makefile~: makefile script, ASCII text
3. I really have no idea of how to tell ld to include the c standard library. I found something like -lglibc or -lc in some other posts. -lgibc doesn't work and -lc seems to be able to get rid of all errors and I probably thought it worked at first but maybe that's the problem since it probably doesn't link the correct library.
UPDATE
Adding -I/lib32/ld-linux.so.2 to the ld command solved my problem.
Below are commands to compile/assemble/link and run the program:
nasm main.asm -felf
gcc -c foo.c -o foo.o -m32
ld -o main main.o foo.o -melf_i386 -lc -I/lib32/ld-linux.so.2
./main
The C library provides code using the _start interface that starts the C runtime, calls main(), and shuts the runtime down. Hence if you intend to use the C library in your program you must not use the _start interface but provide a main() function.
This is the correct way to do it:
; main.asm
global main
extern foo
section .text
main:
push 1234567
call foo
add esp, 4
xor eax, eax
ret
Build with:
nasm -f elf32 -o main.o main.asm
gcc -m32 -o foo.o -c foo.c
gcc -m32 -o main main.o foo.o
Two remarks:
main() returns, instead of doing an exit system call, to allow the C runtime shutdown code to run.
gcc is used for linking. Internally gcc invokes ld with the appropriate parameters to link with the C library. These are platform specific and subject to change. Hence, don't use ld for this.

ld : _start not found defaulting to

Hi I made a simple hello world C program and I am compiling it like this :
gcc -c hello.c
ld hello.o -lc -o out
I get a warning from ld : ld : _start not found defaulting to ....
I do an objdump -D hello.o and I cannot find the _start routine in the output.
What am I missing here ?
You're missing the crt* stuff which you will see if you link with gcc -v: crt1.o, crtend.o, crtn.o. Look at how gcc invokes collect2 (it's visible with gcc -v) and use the same options for ld.
main function is not the executable entry point: some initialization for standard library is done before main (because it's either impossible or illogical to do otherwise). Real entry point, which is _start by default, is in crt1.o which is always linked into your executable.
It's because you don't have a main function, also you can try
gcc -v hello.c -o hello
See if it compiles successfully.
On my system (Angstrom Linux, gcc 4.3.3), it happened due me installing libgcc-s-dev instead of libgcc-dev. No binary on the system contained _start string, I checked that. Installing libgcc-dev helped.

Resources