|
首先,编写一个简单的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; 否则会出现段错误。
|