使用inline __asm()在C中实现最小的32位恢复

lf3rwulv  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(72)

尝试使用内联__asm()在C中创建最小的32位代码。
到目前为止,我已经成功地将__asm()代码大小变为23字节。
我很好奇是否有方法通过使用

  • 编译程序物理学
  • 专用汇编指令
  • vanilla C代码
    示例

godbolt

#include <stdio.h>

unsigned int CodeSize;

void print_binary(unsigned int number) { if (number >> 1) print_binary(number >> 1); putc((number & 1) ? '1' : '0', stdout); }

void reverseBits(unsigned int OriginalValue)
{
    unsigned int ReversedValue = 0;

    start_asm:
    __asm__ (
        "movl  %1, %%eax\n"       // load the value
        "xorl  %%ebx, %%ebx\n"    // clear EBX (optimized)
        "bsrl  %%eax, %%ecx\n"    // find highest order bit set to 1 in EAX
        "incl  %%ecx\n"           // increment to get the correct number of iterations
    "reverse:\n\t"                // local label
        "shrl  $1, %%eax\n"       // shift the LSB of EAX to the carry flag CF
        "rcll  $1, %%ebx\n"       // the MSB of EBX goes into CF and CF's previous value goes into the LSB of EBX
        "loop  reverse\n"         // loop back to the local label
        "movl  %%ebx, %0"         // move the result to the output
        : "=r" (ReversedValue)    // output
        : "r" (OriginalValue)     // input
        : "eax", "ebx", "ecx"     // clobbered registers
    );
    end_asm:

    CodeSize = (char *)&&end_asm - (char *)&&start_asm;

    printf("\nOriginal: 0x%X ", OriginalValue); print_binary(OriginalValue);
    printf("\nReversed: 0x%X ", ReversedValue); print_binary(ReversedValue);
    printf("\n");
}

int main()
{
    reverseBits(0xfeedface);  
    reverseBits(0xfeed);  
    reverseBits(0xfe);               

    printf("\nCodeSize: %u bytes\n", CodeSize); 
    return 0;
}

输出

Original: 0xFEEDFACE 11111110111011011111101011001110
Reversed: 0x735FB77F 1110011010111111011011101111111

Original: 0xFEEDFA 111111101110110111111010
Reversed: 0x5FB77F 10111111011011101111111

Original: 0xFEED 1111111011101101
Reversed: 0xB77F 1011011101111111

Original: 0xFE 11111110
Reversed: 0x7F 1111111

CodeSize: 23 bytes

更新

根据下面的有用注解,代码大小现在为13 bytes

uint32_t reverseBits(uint32_t OriginalValue) {
    uint32_t ReversedValue = 0;

    __asm__ (
        "start_asm:\n"             // start label
        "xorl  %%ebx, %%ebx\n"     // clear EBX
        "bsrl  %1, %%ecx\n"        // find highest order bit set to 1 in EAX (which is %1)
    "reverse:\n"                   // local label for looping
        "shrl  $1, %1\n"           // shift the LSB of EAX (which is %1) to the carry flag CF
        "rcll  $1, %%ebx\n"        // the MSB of EBX goes into CF and CF's previous value goes into the LSB of EBX
        "decl  %%ecx\n"            // manually decrement ECX
        "jns   reverse\n"          // jump to reverse if sign flag is set (i.e., if ecx is negative)
        "end_asm:\n"               // end label
        : "=b" (ReversedValue)     // output directly to EBX
        : "a" (OriginalValue)      // input directly to EAX
        : "ecx"                    // clobbered register
    );

    return ReversedValue;
}
gajydyqb

gajydyqb1#

10 bytes:

__asm__ (
    "start_asm:\n"
    "xorl  %%ebx, %%ebx\n"    //Clear destination and CF
 "repeat:\n\t"
    "rcll  $1, %%ebx\n"       // Shift CF into destination LSB
    "shrl  $1, %%eax\n"       // Shift LSB from source into CF
    "jnz  repeat\n"           // If source is not zero - repeat
                              // else (source is zero, CF is always 1)
    "rcll  $1, %%ebx\n"       // Shift the last 1 into destination
    "end_asm:\n"
    : "=b" (ReversedValue)    // output
    : "a" (OriginalValue)     // input
    :                         // no clobbered registers
);
8yoxcaq7

8yoxcaq72#

6 bytes

uint32_t reverseBits(uint32_t OriginalValue) {
    uint32_t ReversedValue = 0;

    __asm__ (
    "repeat:\n\t"
        "shrl  $1, %%eax\n"        // Shift LSB from source into CF
        "rcll  $1, %%ebx\n"        // Shift CF into destination LSB
        "jnz   repeat\n"           // If source EAX is not zero - repeat
        : "=b" (ReversedValue)     // output: EBX
        : "a"  (OriginalValue),    // input: OriginalValue is loaded into EAX.
          "b"  (ReversedValue)     // input: ReversedValue (0) is loaded into EBX. 
        :                          // no clobbered registers
    );    

    return ReversedValue;
}

相关问题