目前共有18篇帖子。
【方法】在Linux C程序中嵌入彙編語言
1樓 巨大八爪鱼 2016-2-26 12:49
首先,編寫一個簡單的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。
3樓 巨大八爪鱼 2016-2-26 12:51
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 ; 返回
4樓 巨大八爪鱼 2016-2-26 12:51
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
5樓 巨大八爪鱼 2016-2-26 12:51
編譯,運行程序:
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$

6樓 巨大八爪鱼 2016-2-26 12:58
為了能在64位系統下編譯32位的程序,應該為gcc安裝:
sudo apt-get install libc6-dev-i386
7樓 巨大八爪鱼 2016-2-26 13:24
如果想要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
8樓 巨大八爪鱼 2016-2-26 13:31
返回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
9樓 巨大八爪鱼 2016-2-26 13:37
返回字符串指針的方法:
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;
否則會出現段錯誤。

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
 
 
©2010-2024 Arslanbar [手機版] [桌面版]
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。