将汇编 'shl'、'OR'、'AND'、'SHR' 操作转换为 C 的参考?
A reference for converting assembly 'shl', 'OR', 'AND', 'SHR' operations into C?
我要将以下 AT&T x86 程序集转换为 C:
movl 8(%ebp), %edx
movl [=14=], %eax
movl [=14=], %ecx
jmp .L2
.L1
shll , %eax
movl %edx, %ebx
andl , %ebx
orl %ebx, %eax
shrl , %edx
addl , %ecx
.L2
cmpl , %ecx
jl .L1
leave
但必须遵守以下框架代码:
int f(unsigned int x) {
int val = 0, i = 0;
while(________) {
val = ________________;
x = ________________;
i++;
}
return val;
}
我可以看出片段
.L2
cmpl , %ecx
jl .L1
可以解释为while(i<32)
。我也知道x
存储在%edx
,val
存储在%eax
,i
存储在%ecx
。但是,我很难将 while
/.L1
循环中的程序集转换为适合提供的框架代码的精简高级语言。例如,shll
、shrl
、orl
和 andl
是否可以简单地使用它们的直接 C 等效项(<<
、>>
、|
,&
), 还是有更多的细微差别?
是否有汇编到 C 语言转换的标准化指南/"cheat sheet"?
我知道汇编到高级转换并不总是一目了然,但汇编代码中肯定有一些模式可以一致地解释为某些 C 操作。
while (i < 32) { val = (val << 1) | (x & 1); x = x >> 1; i++; }
除了 val 和 return 值应该是无符号的,它们不在您的模板中。函数 return 将 x 中的位反转。
你的问题的实际答案更复杂而且几乎是:不,没有这样的指南,它不可能存在,因为编译会丢失信息,你不能从汇编程序中重新创建丢失的信息。但是您通常可以做出有根据的猜测。
For example, can shll, shrl, orl, and andl simply be written using
their direct C equivalents (<<,>>,|,&), or is there some more nuance
to it?
他们可以。让我们一步步检查循环体:
shll , %eax // shift left eax by 1, same as "eax<<1" or even "eax*=2"
movl %edx, %ebx
andl , %ebx // ebx &= 1
orl %ebx, %eax // eax |= ebx
shrl , %edx // shift right edx by 1, same as "edx>>1" = "edx/=2"
让我们
%eax *=2
%ebx = %edx
%ebx = %ebx & 1
%eax |= %ebx
%edx /= 2
ABI 告诉我们(8(%ebp), %edx
)%edx 是 x,%eax(return 值)是 val:
val *=2
%ebx = x // a
%ebx = %ebx & 1 // b
val |= %ebx // c
x /= 2
组合 a,b,c: #2 将 a 插入 b:
val *=2
%ebx = (x & 1) // b
val |= %ebx // c
x /= 2
组合 a,b,c: #2 将 b 插入 c:
val *=2
val |= (x & 1)
x /= 2
最后一步:将两者 'val =' 合二为一
val = 2*val | (x & 1)
x /= 2
我要将以下 AT&T x86 程序集转换为 C:
movl 8(%ebp), %edx
movl [=14=], %eax
movl [=14=], %ecx
jmp .L2
.L1
shll , %eax
movl %edx, %ebx
andl , %ebx
orl %ebx, %eax
shrl , %edx
addl , %ecx
.L2
cmpl , %ecx
jl .L1
leave
但必须遵守以下框架代码:
int f(unsigned int x) {
int val = 0, i = 0;
while(________) {
val = ________________;
x = ________________;
i++;
}
return val;
}
我可以看出片段
.L2
cmpl , %ecx
jl .L1
可以解释为while(i<32)
。我也知道x
存储在%edx
,val
存储在%eax
,i
存储在%ecx
。但是,我很难将 while
/.L1
循环中的程序集转换为适合提供的框架代码的精简高级语言。例如,shll
、shrl
、orl
和 andl
是否可以简单地使用它们的直接 C 等效项(<<
、>>
、|
,&
), 还是有更多的细微差别?
是否有汇编到 C 语言转换的标准化指南/"cheat sheet"?
我知道汇编到高级转换并不总是一目了然,但汇编代码中肯定有一些模式可以一致地解释为某些 C 操作。
while (i < 32) { val = (val << 1) | (x & 1); x = x >> 1; i++; }
除了 val 和 return 值应该是无符号的,它们不在您的模板中。函数 return 将 x 中的位反转。
你的问题的实际答案更复杂而且几乎是:不,没有这样的指南,它不可能存在,因为编译会丢失信息,你不能从汇编程序中重新创建丢失的信息。但是您通常可以做出有根据的猜测。
For example, can shll, shrl, orl, and andl simply be written using their direct C equivalents (<<,>>,|,&), or is there some more nuance to it?
他们可以。让我们一步步检查循环体:
shll , %eax // shift left eax by 1, same as "eax<<1" or even "eax*=2"
movl %edx, %ebx
andl , %ebx // ebx &= 1
orl %ebx, %eax // eax |= ebx
shrl , %edx // shift right edx by 1, same as "edx>>1" = "edx/=2"
让我们
%eax *=2
%ebx = %edx
%ebx = %ebx & 1
%eax |= %ebx
%edx /= 2
ABI 告诉我们(8(%ebp), %edx
)%edx 是 x,%eax(return 值)是 val:
val *=2
%ebx = x // a
%ebx = %ebx & 1 // b
val |= %ebx // c
x /= 2
组合 a,b,c: #2 将 a 插入 b:
val *=2
%ebx = (x & 1) // b
val |= %ebx // c
x /= 2
组合 a,b,c: #2 将 b 插入 c:
val *=2
val |= (x & 1)
x /= 2
最后一步:将两者 'val =' 合二为一
val = 2*val | (x & 1)
x /= 2