Tuesday, March 2, 2010

Hello World - 再更小code size

在gcc compiler的參數中,除了nostartfiles可以移除一些code(註:一般來說這是不正常的用法)之外,還有一個參數 nostdlib:
主要的目的是告知編譯器,編譯時不需要用上default的函式庫。所以...
(當然在這hello world中,雖然只有利用write(), exit()兩個system call,但是這兩個system call呼叫int 0x80的程式碼還是借用libc的實作來完成,所以預計底下的code以nostdlib的方式連結會發出找不到此兩個function的錯誤。)

$ cat helloworld.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define HELLO_WORLD "Hello World\n"

int main(void)
{
write(STDOUT_FILENO, HELLO_WORLD, sizeof(HELLO_WORLD));

exit(0);

return 0;
}

$ gcc -nostdlib -nostartfiles helloworld.c -o helloworld
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000008048074
/tmp/cckQkLTF.o: In function `main':
helloworld.c:(.text+0x34): undefined reference to `write'
helloworld.c:(.text+0x40): undefined reference to `exit'
collect2: ld returned 1 exit status
$
$

所以乾脆...利用組合語言的技巧自己寫個write(),exit()的system call...
(又有一個問題,因為利用nostartfiles的參數編譯,如此並不會建立process正確的stack,以下的code執行時會發生嚴重錯誤。)
1. 因為之前compiler一直抱怨找不到_start,所以將main改成_start
2. 這邊暫時先忽略exit() function的警告訊息。

$ cat hello1.c
#include <unistd.h>

unsigned char *str = "Hello World\n";

ssize_t write (int __fd, __const void *__buf, size_t __n)
{
asm("movl %2, %%edx;\
movl %0, %%ecx;\
movl %1, %%ebx;\
movl $4, %%eax;\
int $0x80;"
: :"m"(__buf), "r"(__fd), "r"(__n));

}

void exit(int ret)
{
asm("movl %0, %%ebx;\
movl $1, %%eax;\
int $0x80;"
: : "r"(ret));
}

int _start(void)
{
write(STDOUT_FILENO, str, sizeof(str));

exit(0);

return 0;
}

$ gcc -nostartfiles -nostdlib -static hello1.c -o hello1
hello1.c: In function `exit':
hello1.c:22: warning: function declared `noreturn' has a `return' statement
hello1.c:23: warning: `noreturn' function does return
$
$ ./hello1
程式記憶體區段錯誤
$
$


所以...將程式中的stack拿掉....

$ cat hello2.c
unsigned char *str = "Hello World\n";

int _start(void)
{
/* write(STDOUT_FILENO, str, sizeof(str)); */
asm("movl $14, %%edx;\
movl %0, %%ecx;\
movl $1, %%ebx;\
movl $4, %%eax;\
int $0x80;"
: :"m"(str));

/* exit(0); */
asm("movl $0, %ebx;\
movl $1, %eax;\
int $0x80;");

return 0;
}

$ gcc -nostartfiles -nostdlib -static hello2.c -o hello2
$
$ ./hello2
Hello World
$


成功了...可以編譯並執行 :)
來看一下code size...

$ gcc -nostartfiles -nostdlib -static hello2.c -o hello2
$ strip hello2
$ ./hello2
Hello World
$
$ ls -l hello2
-rwxr-xr-x 1 lungswu lungswu 536 2010-02-26 18:15 hello2
$

code size突破低於1024 bytes, 只有536 bytes, 幾乎是0.5K bytes。

No comments:

Post a Comment