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

Posted: August 30, 2017. At: 9:05 AM. This was 6 months ago. Post ID: 11276
Page permalink.
WordPress uses cookies, or tiny pieces of information stored on your computer, to verify who you are. There are cookies for logged in users and for commenters. These cookies expire two weeks after they are set.

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