HelloWorld... 不用C语言库,不用main函数

1.从程序员的自我修养上摘录的。

2.这不是卖弄技巧,这是深入了解链接和编译。


开始


     使用c语言输出hello world,不用C语言库,不用main函数。怎么做?

1. 我们需要printf这样的功能。

2. 一段程序需要一个程序入口,C语言默认是main。

     有这样的武器:

1. GCC支持内嵌汇编。

2. 使用汇编直接产生中断,可以使用系统调用。

3. ld连接器可以指定程序入口。


     好了,我们要做的就是,在程序中使用GCC内嵌汇编,产生中断,进行write的系统调用, 在链接程序时,指定自己的程序入口。代码如下:

/*
 * @FileName: TinyHelloWorld.c
 * @Author: wzj
 * @Brief: 
 *  
 *  
 *  
 *  
 *  
 * @History: 
 * 
 * 
 * 
 * @Date: 2012年06月19日星期二22:46:23
 * 
 */ 
char* str = "Hello world\n";

void
print()
{	//使用write的系统调用, write的调用号为4,原型为int write(int filedesc, char* buffer, int size)
	//这里的系统调用,先将参数写入寄存器,之后传入write调用
	asm(
	"movl $13, %%edx \n\t"		//str的长度
	"movl %0, %%ecx \n\t"           //缓冲区,这里的%0,指的是“r”后面的字符串地址,也就是传入到这段汇编的参数。
	"movl $0, %%ebx \n\t"		//打印到标准输出, 也就是0
	"movl $4, %%eax	\n\t"		//将系统调用号传入eax。 
	"int $0x80		\n\t"	//执行中断, 调用write函数
	::"r" (str):"edx","ecx", "ebx"	//传入的参数列表, 被重命名的寄存器列表。
	);
}

void
exit()
{
	asm(
		"movl $42,%ebx \n\t "			
		"movl $1, %eax \n\t"
		"int $0x80		\n\t"
	);
}
//这里是程序的入口
void
nomain()
{
	print();	
	exit();
}

进行编译:

gcc -c -fno-builtin  TinyHelloWorld.c

ld -static -e nomain -o TinyHelloWorld TinyHelloWorld.o


注:-fno-buildtin  说明禁止使用gcc的内置函数, -static指明使用静态链接进行链接。 -e nomain 指定函数入口为 nomain。


或者,我们可以使用一份链接脚本:


ENTRY(nomain)	 	:指定程序入口

SECTIONS
{
	. = 0x08048000 + SIZEOF_HEADERS;          ;指明程序开始的地址。
	tinytext : { *(.text) *(.data) *(.rodata) }        ;将后面三段,合成当前一段。
	/DISCARD/	: { *(.comment) }
}

进行编译:

gcc -c -fno-builtin  TinyHelloWorld.c

ld -static -T TinyHelloWorld.ld  -o TinyHelloWorld TinyHelloWorld.o


注:使用这份脚本编译之后,与前面的不同之处是,.text  .data  .rodata 被合并成了.tinytext。    使用objdump -h 可以看到两者最终生成文件的不同之处。


你可能感兴趣的:(编译原理)