装配中的位装不按预期工作

时间:2021-10-29 02:17:01

I am currently trying to learn assembly (Intel x86) and I've made a program that simulates bit stuffing on 32bit words -> every 5 consecutive identical bits (5 0's or 5 1's), an opposite bit is inserted. In order to keep the word to its original 32bit size, the less significant bits are truncated if stuffing bits are added.

我目前正在尝试学习汇编(Intel x86),我已经制作了一个模拟32位字位填充的程序 - >每5个连续相同的位(5 0或5 1),插入相反的位。为了使单词保持其原始的32位大小,如果添加填充位,则截断不太重要的位。

Here are a few examples:

这里有一些例子:

0000 1111 0000 1111 0000 1111 0000 1111 -> 0000 1111 0000 1111 0000 1111 0000 1111
0000 1111 0000 1111 0000 1111 0000 0000 -> 0000 1111 0000 1111 0000 1111 0000 0100
0000 1111 0000 1111 0000 0000 0000 0000 -> 0000 1111 0000 1111 0000 0100 0001 0000

So this is my C++ program that tests if everything works correctly, but the last two don't work, and I can't figure out why. I ran it several times by following every step the program doesn with the IDE Debugger, and it seems to do exactly what I want it to do, but the results don't follow...

所以这是我的C ++程序,测试一切是否正常,但最后两个不起作用,我无法弄清楚原因。我按照程序使用IDE调试器执行的每一步都运行了几次,它似乎完全按照我想要的方式执行,但结果不遵循...

#include <iostream>

using namespace std;

extern "C" {unsigned int bitstuffing(unsigned int a);}

int main () {


    unsigned int in    = 0xFFFFFFFF;
    unsigned int verif = 0xFBEFBEFB;
    unsigned int out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;

    in    = 0x00000000;
    verif = 0x04104104; 
    out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;

    in    = 0xF0F0F0F; // 0000 1111 0000 1111 0000 1111 0000 1111
    verif = 0xF0F0F0F; // 0000 1111 0000 1111 0000 1111 0000 1111
    out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;

    in    = 0xF0F0F00; // 0000 1111 0000 1111 0000 1111 0000 0000
    verif = 0xF0F0F04; // 0000 1111 0000 1111 0000 1111 0000 0100
    out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;    

    in    = 0xF0F0000; // 0000 1111 0000 1111 0000 0000 0000 0000
    verif = 0xF0F0410; // 0000 1111 0000 1111 0000 0100 0001 0000
    out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;

    in    = 0xAAAA0000; // 1010 1010 1010 1010 0000 0000 0000 0000
    verif = 0xAAAA0820; // 1010 1010 1010 1010 0000 1000 0010 0000
    out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl;

    in    = 0x7878000; // 0000 0111 1000 0111 1000 0000 0000 0000
    verif = 0x7C1F041; // 0000 0111 1100 0001 1111 0000 0100 0001
                 // out = 0000 0111 1100 0111 1101 0000 0100 0001
    out   = bitstuffing(in);
    if (out==verif) cout<<endl<<"OK: "<<hex<<out<<dec<<endl;
    else cout<<endl<<"ERROR: "<<hex<<out<<dec<<endl; 


    return 0;
}

And this is the ASM program, which is the most important

这是ASM计划,这是最重要的

CPU 386

%include "io.inc"

section .text
    global CMAIN

;0FFFFFFFFh - 0xFBEFBEFB ok
;000000000h - 0x04104104 ok
;0F0F0F0Fh  - 0xF0F0F0F  ok
;0F0F0F00h  - 0xF0F0F04  ok
;0F0F0000h  - 0xF0F0410  ok
;0AAAA0000h - 0xAAAA0820 DOESNT WORK
;07878000h  - 0x7878000  DOESNT WORK


CMAIN:
    mov ebp, esp; for correct debugging
    PUSH EBP
    MOV EBP, ESP
    MOV EAX, 07878000h;[EBP+8]    ; places message (parameter) in EAX
    MOV ECX, 32
    MOV BL, 0           ; counts number of "0" bits
    MOV BH, 0           ; counts number of "1" bits

    loop1:
        ROL EAX, 1
        JC carry
        JNC no_carry

carry:
    XOR BL, BL         ; resets "0" counter to 0
    INC BH             ; increments "1" counter
    CMP BH, 5          ; if we get 5 consecutive bits of the same sign -> bitstuffing
    JE stuffing_0
    DEC ECX            ; Decrementing ECX for loop
    JNZ loop1
    JZ end

no_carry:
    XOR BH, BH         ; resets "1" counter to 0
    INC BL             ; increments "0" counter
    CMP BL, 5          ; if we get 5 consecutive bits of the same sign -> bitstuffing
    JE stuffing_1
    DEC ECX            ; Decrementing ECX for loop
    JNZ loop1
    JZ end

stuffing_0:
    XOR EDX, EDX
    XOR EBX, EBX
    MOV EDX, 2        ; Putting 2 in EDX for MUL operation
    MUL EDX           ; Multiplying EAX by 2 is like adding a 0 at the end
    XOR EDX, EDX      ; Resetting EDX register
    DEC ECX           ; Decrementing ECX twice for loop (in order to truncate bits)
    DEC ECX           
    CMP ECX, 0           
    JG loop1
    JLE end

stuffing_1:
    XOR EDX, EDX
    XOR EBX, EBX
    MOV EDX, 2        ; Putting 2 in EDX for MUL operation
    MUL EDX           ; Multiplying EAX by 2 is like adding a 0 at the end
    ADD EAX, 1        ; Adding 1 to EAX when the last bit is the zero we added is the same is adding 1 instead of zero
    XOR EDX, EDX      ; Resetting EDX register
    DEC ECX           ; Decrementing ECX twice for loop (in order to truncate bits)
    DEC ECX
    CMP ECX, 0           
    JG loop1
    JLE end

end:
    LEAVE
    RET

So when I run this program, it works very well with the following values (they are all put in EAX)

因此,当我运行此程序时,它可以很好地使用以下值(它们都放在EAX中)

;0FFFFFFFFh - 0xFBEFBEFB ok
;000000000h - 0x04104104 ok
;0F0F0F0Fh  - 0xF0F0F0F  ok
;0F0F0F00h  - 0xF0F0F04  ok
;0F0F0000h  - 0xF0F0410  ok

But doesn't work with the following

但不适用于以下情况

;0AAAA0000h - 0xAAAA0820 DOESNT WORK
;07878000h  - 0x7878000  DOESNT WORK

If anyone can spot the problem it would be of great help!

如果有人能发现问题,那将是非常有帮助的!

1 个解决方案

#1


To stuff the new bit you multiply by 2 which is just a convoluted way to do a shift left. This will discard the most significant bit, so you are not discarding from the least significant position of the original value, rather, you are basically overwriting the following bit with your stuffed bit.

要填充新位,你乘以2,这只是一个复杂的左移。这将丢弃最重要的位,因此您不会丢弃原始值的最低位置,而是基本上用填充位覆盖后面的位。

In short, your code does not do what you say it does :)

简而言之,您的代码不会像您说的那样做:)

A possible solution (gas syntax):

一种可能的解决方案(气体语法):

.intel_syntax noprefix
.global main
main:
    sub esp, 12
    mov [esp + 8], ebx
    xor ebx, ebx

test_loop:
    mov eax, [in + 4 * ebx]
    mov dword ptr [esp], eax
    call bitstuffing
    mov [esp + 8], eax
    cmp eax, [verify + 4 * ebx]
    mov dword ptr [esp], offset ok
    je got_fmt
    mov dword ptr [esp], offset error
got_fmt:
    mov eax, [in + 4 * ebx]
    mov [esp + 4], eax
    call printf
    inc ebx
    cmp ebx, 7
    jb test_loop

    mov ebx, [esp + 8]
    add esp, 12
    xor eax, eax
    ret

bitstuffing:
    push ebp
    mov ebp, esp
    push ebx

    mov cl, 32         # 32 bits to go
    xor eax, eax       # the output
    mov edx, [ebp + 8] # the input
    xor bl, bl         # the run count
next_bit:
    dec cl             # more bits?
    js done            # no
    shl edx, 1         # consume from the input into CF
    rcl eax, 1         # copy to output from CF
    test bl, bl        # first bit always matches
    jz match
    test al, 3         # do we have 00 or 11 in the low 2 bits?
    jnp reset          # no, start counting again
match:
    inc bl
    cmp bl, 5          # did 5 bits match?
    jb next_bit        # no, keep going
    dec cl             # space for stuffed bit?
    js done            # no
    mov ebx, eax       # make a copy
    and ebx, 1         # isolate LSB
    xor ebx, 1         # flip it
    shl eax, 1         # make space for it
    or eax, ebx        # stuff it
reset:
    mov bl, 1          # already have length 1
    jmp next_bit

done:
    pop ebx
    mov esp, ebp
    pop ebp
    ret

.data
ok: .string "OK: 0x%08x => 0x%08x\n"
error: .string "ERROR: 0x%08x => 0x%08x\n"
in: .int 0xFFFFFFFF, 0x00000000, 0x0F0F0F0F, 0x0F0F0F00, 0x0F0F0000, 0xAAAA0000, 0x07878000
verify: .int 0xFBEFBEFB, 0x04104104, 0x0F0F0F0F, 0x0F0F0F04, 0x0F0F0410, 0xAAAA0820, 0x07C1F041

See it in operation at ideone.com.

在ideone.com上查看它。

#1


To stuff the new bit you multiply by 2 which is just a convoluted way to do a shift left. This will discard the most significant bit, so you are not discarding from the least significant position of the original value, rather, you are basically overwriting the following bit with your stuffed bit.

要填充新位,你乘以2,这只是一个复杂的左移。这将丢弃最重要的位,因此您不会丢弃原始值的最低位置,而是基本上用填充位覆盖后面的位。

In short, your code does not do what you say it does :)

简而言之,您的代码不会像您说的那样做:)

A possible solution (gas syntax):

一种可能的解决方案(气体语法):

.intel_syntax noprefix
.global main
main:
    sub esp, 12
    mov [esp + 8], ebx
    xor ebx, ebx

test_loop:
    mov eax, [in + 4 * ebx]
    mov dword ptr [esp], eax
    call bitstuffing
    mov [esp + 8], eax
    cmp eax, [verify + 4 * ebx]
    mov dword ptr [esp], offset ok
    je got_fmt
    mov dword ptr [esp], offset error
got_fmt:
    mov eax, [in + 4 * ebx]
    mov [esp + 4], eax
    call printf
    inc ebx
    cmp ebx, 7
    jb test_loop

    mov ebx, [esp + 8]
    add esp, 12
    xor eax, eax
    ret

bitstuffing:
    push ebp
    mov ebp, esp
    push ebx

    mov cl, 32         # 32 bits to go
    xor eax, eax       # the output
    mov edx, [ebp + 8] # the input
    xor bl, bl         # the run count
next_bit:
    dec cl             # more bits?
    js done            # no
    shl edx, 1         # consume from the input into CF
    rcl eax, 1         # copy to output from CF
    test bl, bl        # first bit always matches
    jz match
    test al, 3         # do we have 00 or 11 in the low 2 bits?
    jnp reset          # no, start counting again
match:
    inc bl
    cmp bl, 5          # did 5 bits match?
    jb next_bit        # no, keep going
    dec cl             # space for stuffed bit?
    js done            # no
    mov ebx, eax       # make a copy
    and ebx, 1         # isolate LSB
    xor ebx, 1         # flip it
    shl eax, 1         # make space for it
    or eax, ebx        # stuff it
reset:
    mov bl, 1          # already have length 1
    jmp next_bit

done:
    pop ebx
    mov esp, ebp
    pop ebp
    ret

.data
ok: .string "OK: 0x%08x => 0x%08x\n"
error: .string "ERROR: 0x%08x => 0x%08x\n"
in: .int 0xFFFFFFFF, 0x00000000, 0x0F0F0F0F, 0x0F0F0F00, 0x0F0F0000, 0xAAAA0000, 0x07878000
verify: .int 0xFBEFBEFB, 0x04104104, 0x0F0F0F0F, 0x0F0F0F04, 0x0F0F0410, 0xAAAA0820, 0x07C1F041

See it in operation at ideone.com.

在ideone.com上查看它。