【问题标题】:Assembly translation汇编翻译
【发布时间】:2015-11-13 21:24:35
【问题描述】:

我正在尝试将以下 C 代码转换为程序集:

void write (int bitpos, unsigned short sample)
{
    int pos = bitpos / 16;
    int posA = bitpos - pos * 16;
    unsigned short write1 = sample >> posA;
}

我在换档操作中不断出错。我看过书中的一些例子,但我不明白有什么问题。我认为这可能是因为我想要转移的数量是一个变量。我想知道实现这一目标的正确方法是什么?

这是我尝试过的:

//int pos = bitpos / 16;
mov eax, 0
mov eax, [bitpos] // eax= bitpos
cdq
mov ecx, 16         
idiv ecx        //ecx = pos

//int posA = bitpos - pos * 16;
mov ebx, ecx    //ebx = pos
imul ebx, 16    // ebx = pos*16
sub eax, ebx    // eax = posA

//unsigned short write1 = sample >> posA;
mov bx, [sample]
shr bx, eax // This is the part that is not working.

错误说:错误的操作数类型。错误代码:C2415

【问题讨论】:

  • 尝试使用sar 而不是shr。这会保留符号。
  • 一个好的汇编器参考应该说明唯一指示变量移位的寄存器是in CL
  • 您可以将bitpos / 16 替换为bitpos >> 4,将pos * 16 替换为pos << 4

标签: assembly x86 32-bit intel-syntax


【解决方案1】:

您的write() 函数没有返回值,也没有副作用(没有写入任何全局变量,没有系统调用,只设置了一些在函数返回时被丢弃的局部变量)。您可以并且应该将其优化为一个空函数just like gcc does

global write
write:
    ret

让我们假设您的函数返回 write1 变量,所以您必须计算它。

gcc -Og(针对调试进行优化)制作了可读性很好的 asm,它不会一直从内存中存储/重新加载。 gcc -m32 -Og -fverbose-asm -masm=intel emits:

# see the godbolt link for colour-coded mapping of source lines to asm lines
write(int, unsigned short):
    mov edx, DWORD PTR [esp+4]  # bitpos, bitpos
    lea eax, [edx+15]   # tmp98,
    test    edx, edx    # bitpos
    cmovns  eax, edx    # tmp98,, bitpos, bitpos
    sar eax, 4  # tmp99,
    neg eax # tmp101
    sal eax, 4  # tmp102,
    mov ecx, eax    # tmp102, tmp102
    add ecx, edx    # posA, bitpos
    movzx   eax, WORD PTR [esp+8]   # D.2591, sample
    sar eax, cl # D.2591, posA
    ret

注意它是如何从堆栈中加载函数参数的,因为它们是函数参数,而不是全局参数。 (您的代码引用了[bitpos],这是一个全局的,而不是返回地址之后堆栈上的第一个位置[esp+4]。)64 位ABI 在寄存器中传递参数,因此您可以获得更简洁的代码。

有条件移动代码是因为负数整数除法的 C 语义给出了算术右移的不同结果(它们的舍入方式不同)。由于idiv 与轮班相比非常昂贵,因此仍然值得使用额外的指令来设置轮班。如果bitpos 未签名,则可以使用shr

启用全面优化后,gcc 找到了一种更有效的处理方式,并将一些算术折叠在一起。 (即除以 16,然后乘以 16,四舍五入到最接近的 16 倍数,使用单个 and 实现以屏蔽这些位。)

故事的寓意:您总是可以查看编译器输出以获取有关如何做某事的灵感,并且经常会看到您最初没有想到的技巧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    • 2012-10-17
    • 2016-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-05
    相关资源
    最近更新 更多