C程序内联asm中编写的算术函数导致分段错误
获得了以下用于执行乘法、除法和求余数的函数:C程序内联asm中编写的算术函数导致分段错误,c,gcc,assembly,x86,inline-assembly,C,Gcc,Assembly,X86,Inline Assembly,获得了以下用于执行乘法、除法和求余数的函数: #define IS_EQUAL(var_, const_) ((INT32)(var_) == (INT32)(const_)) // all these functions must use hexadecimals as constants according to syllabus static inline INT32 math_qmultiply (INT32 num1, INT32 num2) { INT32 r
#define IS_EQUAL(var_, const_) ((INT32)(var_) == (INT32)(const_))
// all these functions must use hexadecimals as constants according to syllabus
static inline INT32
math_qmultiply (INT32 num1, INT32 num2)
{
INT32 retval = 0x0,
count = 0x0;
while (num2)
{
if (IS_EQUAL ((num2 & 0x1), 0x1))
{
retval += num1 << count;
}
count++;
num2 = num2 >> 1;
}
return retval;
}
static inline INT32
math_qdivide (INT32 num1, INT32 num2)
{
if (!num1)
{
return 0x0;
}
if (!num2)
{
return INT_MAX;
}
INT32 neg_result = FALSE;
if (num1 < 0x0)
{
num1 = -num1;
if (num2 < 0x0)
{
num2 = -num2;
}
else
{
neg_result = TRUE;
}
}
else if (num2 < 0x0)
{
num2 = -num2;
neg_result = TRUE;
}
INT32 quotient = 0x0;
while (num1 >= num2)
{
num1 -= num2;
quotient++;
}
if (neg_result)
{
quotient = -quotient;
}
return quotient;
}
static inline INT32
math_qmod (INT32 n1, INT32 n2)
{
INT32 q = math_qdivide (n1, n2);
INT32 p = math_qmultiply (q, n2);
return n1 - p;
}
此功能产生正确的输出,工作正常
当我更改前面函数的代码以使其如下所示时,问题就开始了:
INLINE_ATTRIB INT32
math_qmultiply (INT32 n1, INT32 n2)
{
INT32 res = 0x0;
asm volatile(
"mov eax, %1;"
"mov ebx, %2;"
"mul ebx;"
"mov %0, eax;"
: "=r" (res)
: "g" (n1),
"g" (n2)
);
return res;
}
INLINE_ATTRIB INT32
math_qdivide (INT32 n1, INT32 n2)
{
INT32 res = 0;
asm volatile(
"mov eax, %1;"
"mov ebx, %2;"
"xor edx, edx;"
"div ebx;"
"mov %0, eax;"
: "=r" (res)
: "g" (n1),
"g" (n2)
);
return res;
}
INLINE_ATTRIB INT32
math_qmod (INT32 n1, INT32 n2)
{
INT32 res = 0;
asm volatile
("mov eax, %1;"
"mov ebx, %2;"
"xor edx, edx;"
"div ebx;"
"mov %0, edx;"
: "=r" (res)
: "g" (n1), "g" (n2)
);
return res;
}
现在我总是分段出错,尽管当我分别检查这些函数时,它们会正确地进行除法、乘法和求余数。您能告诉我分段错误的原因吗?您的内联程序集缓冲寄存器没有告诉GCC它们已被修改。这可能会导致问题,特别是当您在不告诉GCC的情况下重击EBX时,因为它是生成的32位代码中的位置独立代码寄存器 如果修改寄存器,请使用输出约束、输入/输出约束;或一个clobber来告诉编译器寄存器已更改。您还可以通过告诉编译器将数据放入特定的寄存器来简化内联程序集。代码可能看起来像:
INLINE_ATTRIB INT32
math_qmultiply (INT32 n1, INT32 n2)
{
INT32 res = 0x0;
asm (
"mul %2;"
: "=a" (res)
: "0" (n1),
"r" (n2)
: "edx"
);
return res;
}
INLINE_ATTRIB INT32
math_qdivide (INT32 n1, INT32 n2)
{
INT32 res = 0;
INT32 temp_edx = 0;
asm (
"div %3;"
: "=a" (res),
"+d" (temp_edx)
: "0" (n1),
"r" (n2)
);
return res;
}
INLINE_ATTRIB INT32
math_qmod (INT32 n1, INT32 n2)
{
INT32 res = 0;
asm
(
"div %2;"
: "+d" (res),
"+a" (n1)
: "r" (n2)
);
return res;
}
您不应该在编译器背后更改寄存器。将它们列为clobbered或使用适当的约束(推荐)。此外,也不需要使用内联asm。可能是ebx的破坏导致了这种情况。@Jester任务是使用asm@ronni_lao当然可以,但正如Jester所说,您需要告诉gcc您修改了哪些寄存器。@ronni_lao:您可以使用
asm(“imul%1,%0”:“+r”(n1):“g”(n2))
来避免重击EDX,和以允许内存或立即源操作数。只有在div
中,您才能使用隐式额外寄存器。(另外,如果INT32已签名,则应使用cdq;idiv
)。
INLINE_ATTRIB INT32
math_qmultiply (INT32 n1, INT32 n2)
{
INT32 res = 0x0;
asm (
"mul %2;"
: "=a" (res)
: "0" (n1),
"r" (n2)
: "edx"
);
return res;
}
INLINE_ATTRIB INT32
math_qdivide (INT32 n1, INT32 n2)
{
INT32 res = 0;
INT32 temp_edx = 0;
asm (
"div %3;"
: "=a" (res),
"+d" (temp_edx)
: "0" (n1),
"r" (n2)
);
return res;
}
INLINE_ATTRIB INT32
math_qmod (INT32 n1, INT32 n2)
{
INT32 res = 0;
asm
(
"div %2;"
: "+d" (res),
"+a" (n1)
: "r" (n2)
);
return res;
}