彙編總結:左移,右移指令

1.左移指令和右稱指令的種類及做用:數組

左移指令做用:左移指令將操做數的bit位向左移動n位,空出來的位用0填充。函數

  左移指令包含sal和shl,這兩條指令的做用是相同的,空出來的位用0填充。測試

  其中左移sal的指令用法:ui

.section .text
.global _start
_start:
    movb $0b11111111, %al  #8字節
    salb $3, %al 

    movw $0b11111111, %ax  #16字節
    salw $3, %ax 

    movl $0b11111111, %eax #32字節
    sall $3, %eax
    
    movq $0b11111111, %rax #64字節
    salq $3, %rax

 其中左移shl的指令用法:spa

.section .text
.global _start
_start:
    movb $0b11111111, %al #1個字節
    shlb $3, %al 

    movw $0b11111111, %ax #2個字節
    shlw $3, %ax 

    movl $0b11111111, %eax #4個字節
    shll $3, %eax

    movq $0b11111111, %rax #8個字節
    shlq $3, %rax

右移指令做用:右移指令將操做數的bit位向右移動n位,sar執行算術移位(填上符號位),而shr執行邏輯移位(填上0).移位操做的目的操做數能夠是一個寄存器或是一個存儲器位置。
指針

右移指令sar和shrcode

其中右移sar的指令用法,sar右移會用符號位填充,若是符號位是1,就填充1,若是是0就填充0。原型

.section .text
.global _start
_start:
    movb $0b01111111, %al #符號位是0 
    sarb $3, %al 

    movb $0b11111111, %al #符號位是1 
    sarb $3, %al 

    movw $0x7FFF, %ax 
    sarw $3, %ax 

    movw $0xFFFF, %ax 
    sarw $3, %ax 

    movl $0x7FFFFFFF, %eax
    sarl $3, %eax

    movl $0xFFFFFFFF, %eax
    sarl $3, %eax

    movq $0x7FFFFFFFFFFFFFFF, %rax
    sarq $3, %rax

    movq $0xFFFFFFFFFFFFFFFF, %rax
    sarq $3, %rax

其中右移sar的指令用法,shr始終填充0編譯器

.section .text
.global _start
_start:
    movb $0b01111111, %al #符號位是0
    shrb $3, %al

    movb $0b11111111, %al #符號位是1
    shrb $3, %al

    movw $0x7FFF, %ax
    shrw $3, %ax

    movw $0xFFFF, %ax
    shrw $3, %ax


    movl $0x7FFFFFFF, %eax
    shrl $3, %eax

    movl $0xFFFFFFFF, %eax
    shrl $3, %eax

    movq $0x7FFFFFFFFFFFFFFF, %rax
    shrq $3, %rax

    movq $0xFFFFFFFFFFFFFFFF, %rax
    shrq $3, %rax

2.語言中的同類操做符:it

    左移操做符是>>  用法value >> 1

    右移操做符是<<  用法value << 1

    注意:

        在c標準裏說明無符號值執行的全部移位操做都是邏輯移位,但對於有符號值,究竟是採用邏輯移位仍是算術移位取決於編譯器。

3.練習:

練習題摘自《c和指針》第5章操做符和表達式

3.1.請編寫函數

unsigned int reverse_bits(unsigned int value);

這個函數的返回值是把value的二進制位模式從左到右變換一下後的值。例如,在32位機器上,25這個值包含了下列各個位:

00000000000000000000000000011001

10011000000000000000000000000000

彙編code:

.section .text

.global reverse_bits
.type reverse_bits, @function
reverse_bits:
    
    xorl %eax, %eax
    movl $32, %ecx
reverse_bits_start:
    cmpl $0, %ecx
    je reverse_bits_end
    shll $1, %eax
    movl %edi, %esi
    andl $1, %esi
    orl  %esi, %eax
    shrl $1, %edi
    decl %ecx

    jmp reverse_bits_start
reverse_bits_end:
    ret

c測試代碼

#include <stdio.h>
#include <assert.h>

extern int reverse_bits(unsigned int ui);

int main() {
    unsigned u;  
    u = reverse_bits(0x7fffffff);
    assert(u == 0xfffffffe);
    printf("u(%x)\n", u); 

    u = reverse_bits(0x00ffffff);
    assert(u == 0xffffff00);
    printf("u(%x)\n", u); 

    u = reverse_bits(0xffff00ff);
    assert(u == 0xff00ffff);
    printf("u(%x)\n", u); 

    u = reverse_bits(0xffffff00);
    assert(u == 0x00ffffff);
    printf("u(%x)\n", u); 

    u = reverse_bits(0xff00ffff);
    assert(u == 0xffff00ff);
    printf("u(%x)\n", u); 
    return 0;
}

3.2.編寫一組函數,實現位數組。函數的原型應該以下:

void set_bit(char bit_array[], unsigned bit_number);
void clear_bit(char bit_array[], unsigned bit_number);
void assign_bit(char bit_array[], unsigned bit_number, int value);
int test_bit(char bit_array[], unsigned bit_number);

 每一個函數的第1個參數是個字符數組,用於實際存儲全部的位。第2個參數用於標識須要訪問的位。函數的調用者必須確保這個值不要太大,以致於超出數組的邊界。

    第1個函數把指定的位設置爲1。

    第2個函數則把指定的位清零。

    若是value的值爲0,第3函數把指定的位清0,不然設置爲1.

    至於最後一個函數,若是參數中指定的位不是0,函數就返回真,不然就返回假。

彙編code:

.section .text

.global set_bit
.type set_bit, @function
set_bit:
    movl %esi, %edx
    shrl $3, %edx
    movb (%rdi, %rdx, 1), %r8b
    
    movb $1, %r9b
    movb %sil, %cl
    andb $7, %cl
    shlb %cl, %r9b

    orb %r8b, %r9b
    movb %r9b, (%rdi, %rdx, 1)
    ret

.global clear_bit
.type clear_bit, @function
clear_bit:
    movl %esi, %edx
    shrl $3, %edx
    movb (%rdi, %rdx, 1), %r8b
    
    movb $1, %r9b
    movb %sil, %cl
    andb $7, %cl
    shlb %cl, %r9b

    notb %r9b
    andb %r8b, %r9b
    movb %r9b, (%rdi, %rdx, 1)
    ret

.global test_bit
.type test_bit, @function
test_bit:
    movl %esi, %edx
    shrl $3, %edx
    movb (%rdi, %rdx, 1), %r8b
    
    movb $1, %r9b
    movb %sil, %cl
    andb $7, %cl
    shlb %cl, %r9b
    andb %r8b, %r9b
    movl $0, %eax #返回假
    cmpb $0, %r9b
    je test_bit_false
    movl $1, %eax #返回真
test_bit_false:
    ret

.global assign_bit
.type assign_bit, @function
assign_bit:
    cmpl $0, %edx
    je call_clear_bit
    call set_bit
    jmp assign_bit_end
call_clear_bit:
    call clear_bit
assign_bit_end:
    ret

c測試代碼:

#include <stdio.h>
#include <assert.h>

extern void set_bit(char arr[], unsigned int bit_number);
extern void clear_bit(char arr[], unsigned int bit_number);
extern int  test_bit(char arr[], unsigned int bit_number);
extern void assign_bit(char arr[], unsigned int bit_number, int value);

void test_one_bit() {
    printf("test one bit start...\n");
    unsigned char c = 0;
    set_bit(&c, 1);
    assert(test_bit(&c, 1) == 1);

    clear_bit(&c, 1);
    assert(test_bit(&c, 1) == 0);

    assign_bit(&c, 1, 1);
    assert(test_bit(&c, 1) == 1);
    assert(c == 2);
    assign_bit(&c, 1, 0);
    assert(test_bit(&c, 1) == 0);
    assert(c == 0);
}

void test_byte() {
    printf("test one byte start...\n");
    unsigned char c = 0;
    int i;
    for (i = 0; i < sizeof(c) * 8; i++) {
        set_bit(&c, i);
    }
    assert(c == 0xff);
    for (i = 0; i < sizeof(c) * 8; i++) {
        assert(test_bit(&c, i) == 1);
    }
    for (i = 0; i < sizeof(c) * 8; i++) {
        clear_bit(&c, i);
    }
    assert(c == 0);

    for (i = 0; i < sizeof(c) * 8; i++) {
        assign_bit(&c, i, 1);
    }
    assert(c == 0xff);
    for (i = 0; i < sizeof(c) * 8; i++) {
        assign_bit(&c, i, 0);
    }
    assert(c == 0);
}

void test_two_byte() {
    printf("test two byte start...\n");
    unsigned short s = 0;
    int i;
    for (i = 0; i < sizeof(s) * 8; i++) {
        set_bit((char *)&s, i);
    }
    assert(s == 0xffff);
    for (i = 0; i < sizeof(s) * 8; i++) {
        assert(test_bit((char *)&s, i) == 1);
    }
    for (i = 0; i < sizeof(s) * 8; i++) {
        clear_bit((char *)&s, i);
    }
    assert(s == 0);

    for (i = 0; i < sizeof(s) * 8; i++) {
        assign_bit((char *)&s, i, 1);
    }
    assert(s == 0xffff);
    for (i = 0; i < sizeof(s) * 8; i++) {
        assign_bit((char *)&s, i, 0);
    }
    assert(s == 0);
}

int main() {
    test_one_bit();
    test_byte();
    test_two_byte();
    //test_xxoo();
    return 0;
}
相關文章
相關標籤/搜索