|
首先,編寫一個簡單的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; 否則會出現段錯誤。
|