How to write a Hello World program in C that does not use main().

Posted: August 30, 2017. At: 9:05 AM. This was 3 months ago. Post ID: 11276
Page permalink: http://securitronlinux.com/debian-testing/how-to-write-a-hello-world-program-in-c-that-does-not-use-main/

Now, we must convince Congress to stop the FCC. Can you display an alert?

This simple program is a Hello World example that does not use the main() function. This is certainly possible in a C program.

#define syscall(a, D, S, d) __asm__ __volatile__("syscall" : : "a"(a), "D"(D), "S"(S), "d"(d))
 
void _start(void)
{
        syscall(1, 1, "Hello, World\n", 14);
        syscall(60, 0, 0, 0);
}

This is how to compile this program. Then the Hello World text will print to the terminal. The -nostartfiles parameter to gcc tells it that we are not using the main() function that is called by the operating system to run the program code.

[email protected]:~/Documents$ gcc syscall.c -nostartfiles -o sycall

And it works perfectly.

jason@jason-desktop:~/Documents$ ./sycall
Hello, World

Notice in this strace output, it is still using the write() system call to print the text.

jason@jason-desktop:~/Documents$ strace ./sycall 
execve("./sycall", ["./sycall"], [/* 51 vars */]) = 0
brk(NULL)                               = 0x564b96c3f000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f398360c000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=102631, ...}) = 0
mmap(NULL, 102631, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f39835f2000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\5\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1856752, ...}) = 0
mmap(NULL, 3959200, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f3983023000
mprotect(0x7f39831e1000, 2093056, PROT_NONE) = 0
mmap(0x7f39833e0000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bd000) = 0x7f39833e0000
mmap(0x7f39833e6000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f39833e6000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f39835f0000
arch_prctl(ARCH_SET_FS, 0x7f39835f0700) = 0
mprotect(0x7f39833e0000, 16384, PROT_READ) = 0
mprotect(0x564b9633f000, 4096, PROT_READ) = 0
mprotect(0x7f398360f000, 4096, PROT_READ) = 0
munmap(0x7f39835f2000, 102631)          = 0
write(1, "Hello, World\n\0", 14Hello, World
)        = 14
exit(0)                                 = ?
+++ exited with 0 +++

But this programming trick really works and is worth trying out in your own programs.

Here is how to get the return value of a program on a UNIX or Linux machine.

jason@jason-desktop:~/Documents$ ./sycall && echo $?
Hello, World
0

Here is another example without inline ASM.

#include <stdio.h>
#include <stdlib.h>
 
void _start() {
	printf("Hello World\n");
	exit(0);
 
}

Compile this example the same way and it will work perfectly.

No comments have been made. Use this form to start the conversation :)

Leave a Reply