文档章节

汇编总结:左移,右移指令

guonaihong
 guonaihong
发布于 2015/09/26 23:47
字数 1376
阅读 5866
收藏 2

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

1.左移指令和右称指令的种类及作用:

左移指令作用:左移指令将操作数的bit位向左移动n位,空出来的位用0填充。

  左移指令包含sal和shl,这两条指令的作用是相同的,空出来的位用0填充。

  其中左移sal的指令用法:

.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的指令用法:

.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和shr

其中右移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.语言中的同类操作符:

    左移操作符是>>  用法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;
}


© 著作权归作者所有

guonaihong

guonaihong

粉丝 6
博文 83
码字总数 27591
作品 1
徐汇
程序员
私信 提问
程序是如何执行的(一)a=a+1

一、概述 1、计算机中有两个主要的核心部件:CPU和内存,其中CPU负责运算而内存负责存储程序和相关的变量,每一条程序语句和变量都在内存中有对应的内存地址。 2、寄存器是CPU的存储单元,每...

城固如春
2017/11/07
12
0
关于汇编语言寄存器和指令操作的整理

最近汇编学到后面的内容, 越来越觉得前面的基础没有掌握好, 弄得最后编写汇编程序的时候, 寄存器瞎用, 没有一点的规矩, 中断操作也不知道是对哪个寄存器里的数进行操作, 每次做一个小程序, 都...

如风达
2016/09/04
68
0
Java移位运算符总结

本文参考:java移位运算符详解 Java移位运算符有三种 << 左移运算符,value< >> 右移运算符,value>>num >>> 无符号右移运算符, value>>>num << 左移运算符。(value< 相当与2*2,即将2(v......

Mercy_丶
2016/06/27
57
0
大小端和移位运算

移位运算分为逻辑左移、逻辑右移、算术左移、算术右移 顾名思义:算术是有正负的。因此算术移位,关心符号位;而逻辑不管符号位。 1 算术左移(<<) 计算规则:按二进制形式把所有的数字向左移...

J_Stone
2016/04/17
199
0
交换某个整数的奇数位和偶数位,使用指令越少越好

/** * 功能:交换某个整数的奇数位和偶数位,使用指令越少越好(即,位0与位1交换,位2与位3交换,以此列推)。 */ 这题要交换的是整数二进制的奇数和偶数位。 按照一般的解题肯定会对每一位...

一贱书生
2016/11/19
61
0

没有更多内容

加载失败,请刷新页面

加载更多

web前端入门到实战:图解原生dialog标签(非常详细)

在html5中,新增了很多语义化的标签。如footer、header之类的,今天的主角是dialog标签 顾名思义,就是用来定义对话框的。目前只有Chrome和Safari支持该标签,所以用的不多,不过确实挺好用的...

梦想编程
22分钟前
3
0
一些php常用函数积累

本文链接<?php// id: ecffe70d3af54df9bad97b61918ace7d global $ct_path, $ct_log_path;$log_path = "test_php.txt";// 是否先log到buffer,再通过CT_flush()一次性写入文件$......

一字见心
22分钟前
3
0
IntelliJ idea中 注释代码折叠

visual studio中有#region 可以折叠代码,IntelliJ idea 中也有类似功能 //region 描述代码//endregion

format
23分钟前
4
0
oracle表中更改主键

一、数据表有主键但无主键约束名 先删除之前的主键,后添加主键 ,执行SQL: a. alter table 表名 drop primary key; b. alter table 表名 add primary key(想要更改的字段名称); 二、数据表...

_Somuns
24分钟前
3
0
jQuery AJAX提交表单

我有一个名称为orderproductForm的表单,输入的数量不确定。 我想做某种jQuery.get或ajax或类似的事情,它将通过Ajax调用页面,并发送所有形式为orderproductForm的输入。 我想一种方法是做类...

技术盛宴
30分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部