我有以下简短的应用程序(原文取自:https://www.aldeid.com/wiki/X86-assembly/Instructions/str。我刚刚对其进行了修改(尝试...),使其也可以在linux上编译。
#include <stdio.h>
unsigned char mema[4] = {0, 0, 0, 0};
void test4 (void)
{
asm (
"str mema\n"
);
printf ("\n[+] Test 4: STR\n");
printf ("STR base: 0x%02x%02x%02x%02x\n", mema[0], mema[1], mema[2], mema[3]);
if ((mema[0] == 0x00) && (mema[1] == 0x40))
printf ("Result : VMware detected\n\n");
else
printf ("Result : Native OS\n\n");
}
int main () {
test4();
}
以及当我尝试编译它时:
$ gcc -ggdb -O0 -fPIC -x c ./pill.c -o pill
它给了我奇怪的错误:
/usr/bin/ld: /tmp/ccDhGo05.o: relocation R_X86_64_32S against symbol `mema' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
然而,同样的事情在在线编译器上也起作用:https://gcc.godbolt.org/z/RYWjy8
...,除非当我抱怨变量mema
在函数test4
的两个地方时都将其作为局部变量
undefined symbol `mema'
还有另一个怪异:用clang编译时,相同的东西也可以工作。
知道为什么会这样吗? (不考虑STR
和其他事物所需的特权级别,我仅对链接错误以及为什么它在一个系统/编译器而不是另一个系统/编译器上起作用感到兴趣。
[当您编写asm("str mema\n");
时,编译器实际上将str mema
写入汇编文件。
在用-fPIC
编译的程序中,汇编代码不允许包含程序中任何内容的任何地址(这是与位置无关的means)。因此,不允许您使用包含全局变量mema
的地址的指令。
局部变量不是汇编器一开始就知道的东西。
如果要用汇编指令读取或写入变量,则需要告诉编译器您要读取或写入的内容,然后让编译器找出要写入的确切代码:
asm("str %0" : "=m" (mema));
["=m"
说该值是一个输出(=
),它必须是一个存储位置(m
),但是编译器会弄清楚实际位置应该是什么。
[The GCC manual has more information(叮当声的工作方式相同)。