|   | 
			  首先,编写一个简单的C程序:#include <stdio.h>
 
 void fun(int *num, int *num2);
 
 int main()
 {
 int a = 10, b = 32;
 fun(&a, &b);
 printf("a=%d, b=%d\n", a, b);
 return 0;
 }
 其中主函数调用了fun函数。
 fun函数我们打算用汇编语言来写,其功能是把*num的值加15, *num2的值加5。
 
 | 
                
          |   | 
			  GLOBAL fun
 fun:
 MOV ECX, [ESP+4] ; 把第一个参数的值送入ECX寄存器,其中存储的是变量a的地址
 ADD DWORD[ECX], 15 ; []表示取内存内容,DWORD就是类型int的大小,把ECX指向的内存区域的值加15
 
 MOV ECX, [ESP+8] ; 取第二个参数的值
 ADD DWORD[ECX], 5
 
 RET ; 返回
 | 
                
          |   | 
			  Makefile文件:# 连接
 test: test.o hello.o
 gcc -m32 test.o hello.o -o test
 
 # 编译test.c,生成32位的目标文件
 test.o: test.c
 gcc -m32 -c test.c
 
 # 编译hello.asm,生成目标文件
 hello.o: hello.asm
 nasm -f elf hello.asm
 
 | 
                
          |   | 
			  编译,运行程序:octopus@pc3:~/Documents/Codes/C/link2$ make
 gcc -m32 -c test.c
 nasm -f elf hello.asm
 gcc -m32 test.o hello.o -o test
 octopus@pc3:~/Documents/Codes/C/link2$ ./test
 a=25, b=37
 octopus@pc3:~/Documents/Codes/C/link2$
 
 
 | 
                
          |   | 
			  为了能在64位系统下编译32位的程序,应该为gcc安装:sudo apt-get install libc6-dev-i386
 
 | 
                
          |   | 
			  如果想要fun函数返回值,可以将其放入EAX寄存器里面:MOV EAX, 12345678 ; 返回值
 RET ; 返回
 
 C程序部分:
 #include <stdio.h>
 int fun(int *num, int *num2);
 int main()
 {
 int a = 10, b = 32;
 int c = fun(&a, &b);
 printf("a=%d, b=%d\n", a, b);
 printf("c=%d\n", c);
 return 0;
 }
 运行结果:
 $ ./test
 a=25, b=37
 c=12345678
 
 | 
                
          |   | 
			  返回64位值的方法:GLOBAL fun
 fun:
 MOV EDX, 0xabcdef01 ; 返回值的高32位
 MOV EAX, 0x12345678 ; 返回值的低32位
 RET
 
 #include <stdio.h>
 long long fun();
 int main()
 {
 long long v = fun();
 printf("返回值 = %lld\n", v);
 printf("高32位: %#08lx\n", (long)(v >> 32));
 printf("低32位: %#08lx\n", (long)(v & 0xffffffff));
 return 0;
 }
 
 运行结果:
 返回值 = -6066930335118764424
 高32位: 0xabcdef01
 低32位: 0x12345678
 
 | 
                
          |   | 
			  返回字符串指针的方法:GLOBAL fun
 fun:
 MOV EAX, msg ; 把数据段的地址作为返回值返回
 RET
 
 ; 数据段
 msg:
 DB "Hello, World!"
 DB 0
 
 
 #include <stdio.h>
 char *fun();
 int main()
 {
 char *str = fun();
 puts(str);
 return 0;
 }
 
 程序输出:
 Hello, World!
 
 | 
                
          |   | 
              
                10樓                巨大八爪鱼
                2016-2-26 13:53
                                                  
			  其实,在C语言中可以直接通过引用外部变量的方法引用数据段msg:【汇编部分】
 GLOBAL msg
 msg:
 DB "Hello, World!"
 DB 0
 【C语言部分】
 #include <stdio.h>
 extern char msg;
 int main()
 {
 // 变量msg只是第一个字符
 printf("第1个字符: %c\n", msg);
 
 // 要想输出其他字符,必须先得到msg的地址,然后对这个地址进行加法运算
 printf("第2个字符: %c\n", *(&msg + 1));
 printf("第3个字符: %c\n", *(&msg + 2));
 
 // 可以用下面的方法输出整个字符串
 char *pMsg = &msg;
 puts(pMsg);
 
 return 0;
 }
 
 【输出】
 $ ./test
 第1个字符: H
 第2个字符: e
 第3个字符: l
 Hello, World!
 
 | 
                
          |   | 
              
                11樓                巨大八爪鱼
                2016-2-26 14:21
                                                  
			  如果把msg变量声明为数组的话,也能直接输出字符串:#include <stdio.h>
 #include <string.h>
 extern char msg[];
 int main()
 {
 puts(msg);
 printf("length: %d\n", strlen(msg));
 return 0;
 }
 运行结果:
 Hello, World!
 length: 13
 
 但是,不能声明成字符串指针:
 extern char *msg;
 否则会出现段错误。
 
 |