注意:以下适用于 amd64 上的 linux,但同样的原理也适用于 i386。
如果调用外部工具(在本例中为 gcc 和 nasm)没有问题,您可以这样做:
main.c:
#include <stdio.h>
#include <unistd.h>
void make_obj (const char *filename,
const char *data,
size_t length,
const char *entry_point)
{
const char *filename_s = "tmp.s";
const char *filename_bin = "tmp.bin";
FILE *f;
char buf[1000];
// create bin file
f = fopen (filename_bin, "wb");
fwrite (data, 1, length, f);
fclose (f);
// create assembly wrapper
f = fopen (filename_s, "w");
fprintf (f,
"\t\tsection .text\n"
"\t\tglobal %s\n"
"%s:\n"
"\t\tincbin \"%s\"\n",
entry_point, entry_point, filename_bin);
fclose (f);
// call nasm to convert it to object file
snprintf (buf, 1000, "nasm -f elf64 -o %s %s", filename, filename_s);
system (buf);
unlink (filename_bin);
unlink (filename_s);
}
void test_add (const char *filename_o, const char *entry_point)
{
const char *filename_c = "test.c";
const char *filename_exe = "test";
FILE *f;
char buf[1000];
f = fopen (filename_c, "w");
fprintf (f,
"#include <stdio.h>\n"
"\n"
"extern int %s (int a, int b);\n"
"\n"
"int main () {\n"
"\tconst int a = 2;\n"
"\tconst int b = 3;\n"
"\n"
"\tint c = %s (a, b);\n"
"\n"
"\tprintf (\"%%d + %%d = %%d\\n\", a, b, c);\n"
"\n"
"\treturn 0;\n"
"}\n",
entry_point, entry_point);
fclose (f);
snprintf (buf, 1000, "gcc -o %s %s %s",
filename_exe, filename_c, filename_o);
system (buf);
snprintf (buf, 1000, "./%s", filename_exe);
system (buf);
unlink (filename_c);
unlink (filename_exe);
}
int main ()
{
const char code[] = {
0x48, 0x89, 0xF8, // mov rax,rdi
0x48, 0x01, 0xF0, // add rax,rsi
0xC3 // ret
};
const char *filename_o = "tmp.o";
const char *entry_point = "add";
make_obj (filename_o, code, sizeof(code), entry_point);
test_add (filename_o, entry_point);
unlink (filename_o);
return 0;
}
测试它:
cc -o main main.c
./main
如果一切顺利,main 应该生成一个包含整数加法函数的机器代码的目标文件,一个调用机器代码例程的 C 文件,编译 C 文件并运行它。
结果应该是:
2 + 3 = 5
注释掉 unlink() 调用以保留中间文件。