我想请教一下您的帮助!我有一个包含很多 C 源代码的项目。其中大部分是用 gcc 编译的,但也有一些是用 Intel 编译器编译的。后面的代码有很多微软MASM
格式的内联汇编代码。我想用 gcc 编译整个项目并尽可能少地修改代码。所以我写了一个 perl 脚本,它将 intel 格式的 inline asm 转换为 GAS 格式。(顺便说一句:我在 64 位 Linux 机器上编译为 32 位)。
我的问题是我必须为 gcc 指定在内联中将asm("...")
哪些 C 变量传递给:: [var1] "m" var1, [var2] "m" var2, ...
在末尾添加行的代码。
这是一种避免这种明确规范的方法吗?
我的尝试:
虚拟测试 C 代码只是用源 char 数组的元素替换目标 char 数组的 4 个字符(我知道这不是最好的方法。这只是一个愚蠢的例子)。
在原始函数中没有明确的规范,但它可以用英特尔编译器编译(我很惭愧,但我没有对此进行测试,但它应该可以与英特尔编译器一起使用,因为我是根据真实代码制作的)。LOOP
label 被多次使用,即使在同一个 C 源文件中也是如此。
#include <stdio.h>
void cp(char *pSrc, char *pDst) {
__asm
{
mov esi, pSrc
mov edi, pDst
mov edx, 4
LOOP:
mov al, [esi]
mov [edi], al
inc esi
inc edi
dec edx
jnz LOOP
};
}
int main() {
char src[] = "abcd";
char dst[] = "ABCD";
cp(src, dst);
printf("SRC: '%s', DST: '%s'\n", src, dst);
return 0;
}
结果是:SRC: 'abcd', DST: 'abcd'
转换后的工作cp
代码是(用 gcc 编译的)。
GAS (AT&T) 格式(编译gcc -ggdb3 -std=gnu99 -m32 -o asm asm.c
:)
void cp(char *pSrc, char *pDst) {
asm(
"mov %[pSrc], %%esi\n\t"
"mov %[pDst], %%edi\n\t"
"mov $4, %%edx\n\t"
"LOOP%=:\n\t"
"mov (%%esi), %%al\n\t"
"mov %%al, (%%edi)\n\t"
"inc %%esi\n\t"
"inc %%edi\n\t"
"dec %%edx\n\t"
"jnz LOOP%=\n\t"
: [pDst] "=m" (pDst)
: [pSrc] "m" (pSrc)
: "esi", "edi", "edx", "al"
);
}
Intel 格式(编译gcc -ggdb3 -std=gnu99 -m32 -masm=intel -o asm asm.c
:)
void cp(char *pSrc, char *pDst) {
asm(".intel_syntax noprefix\n\t");
asm(
"mov esi, %[pSrc]\n\t"
"mov edi, %[pDst]\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
: [pDst] "=m" (pDst)
: [pSrc] "m" (pSrc)
: "esi", "edi", "edx", "al"
);
asm(".intel_syntax prefix");
}
两种代码都可以工作,但需要进行一些代码修改(插入“%”字符、收集变量、修改跳转标签和jump
函数)。
我也试过这个版本:
void cp(char *pSrc, char *pDst) {
asm(".intel_syntax noprefix\n\t");
asm(
"mov esi, pSrc\n\t"
"mov edi, pDst\n\t"
"mov edx, 4\n\t"
"LOOP:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP\n\t"
);
asm(".intel_syntax prefix");
}
但是会掉
gcc -ggdb3 -std=gnu99 -masm=intel -m32 -o ./asm.exe ./asm.c
/tmp/cc2F9i0u.o: In function `cp':
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pSrc'
/home/TAG_VR_20130311/vr/vr/slicecodec/src/./asm.c:41: undefined reference to `pDst'
collect2: ld returned 1 exit status
有没有办法避免输入参数的定义,避免局部标签的修改?
添加
我尝试使用全局变量。因为这个g
约束必须被使用而不是m
.
char pGlob[] = "qwer";
void cp(char *pDst) {
asm(".intel_syntax noprefix\n\t"
"mov esi, %[pGlob]\n\t"
"mov edi, %[pDst]\n\t"
"mov edx, 4\n\t"
"LOOP%=:\n\t"
"mov al, [esi]\n\t"
"mov [edi], al\n\t"
"inc esi\n\t"
"inc edi\n\t"
"dec edx\n\t"
"jnz LOOP%=\n\t"
".intel_syntax prefix" : [pDst] "=m" (pDst) : [pGlob] "g" (pGlob)
: "esi", "edi", "edx", "al");
}
添加#2
我试过了
"lea esi, pGlob\n\t" // OK
"lea esi, %[_pGlob]\n\t" // BAD
//"lea esi, pGlob_not_defined\n\t" // BAD
//gcc failed with: undefined reference to `pGlob_not_defined'
编译为
lea esi, pGlob
lea esi, OFFSET FLAT:pGlob // BAD
//compilation fails with: Error: suffix or operands invalid for `lea'
似乎只需要定义函数局部变量。全局变量可能会被添加到预告片中,但不是必须的。两者都在工作:
"mov esi, pGlob\n\t" // OK
"mov esi, %[_pGlob]\n\t" // OK
编译为
mov esi, OFFSET FLAT:pGlob
mov esi, OFFSET FLAT:pGlob
我定义了一个函数局部变量。它必须在约束部分定义:
void cp(char *pDst) {
char pLoc[] = "yxcv";
asm(".intel_syntax noprefix\n\t"
...
//"mov esi, pLoc\n\t" // BAD
"mov esi, %[_pLoc]\n\t" // OK, 'm' BAD
...
".intel_syntax prefix" : [_pDst] "=m" (pDst) : [_pLoc] "g" (pLoc)
: "esi", "edi", "edx", "al");
不幸的是,应该确定什么是全局变量和什么是局部变量。这并不容易,因为 asm 代码可以在C
宏中定义,甚至周围的功能也不确定。我认为只有预编译器对此有足够的信息。也许代码必须用gcc -E ...
.
我意识到,不在约束部分定义输出,优化器可以消除一些代码。
蒂亚!