我试图在不使用反汇编表的情况下对Intel 8080进行反汇编。我读取内存字节并将它们分成比特的部分:(7,6),(5,4,3),(2,1,0)。我想知道这些部分的数值是什么,这是一个例子:
给出这个字节:
0b00110000
第7位和第6位评估为:
0b00 -> 0
第5到3位:
0b110 -> 6
位2到0:
0b000 -> 0
现在,我对C非常缺乏经验,我很难想出一个优雅而简单的解决方案来解决这个问题。到目前为止,我的想法如下:
这会完成这项工作还是有更好的方法?
如果你考虑需要做什么,你只需要关注一元>>
移位算子和&
算子。它还有助于提出一个位掩码,以便根据可能需要的任何中间计算仅隔离那些所需的位。 (位掩码只是一个包含数字的变量,其1
位和0
位可用于按位运算,以便为您提供所需的结果)。
在这里,在所有的位分离中,在转换到最终结果后,您将只关注2或3个低位。在你正在查看(7,6)
的情况下,没有其他位可以屏蔽,只留下你正在查看需要掩码的低3位的情况。
从位掩码(或神奇数字)的角度来看,您需要一个掩码来保留最后的3位并丢弃所有剩余的高位。因此,对于8位值,您需要00000111
,或者只需要数字7
。
首先,如果要检查8位数中的最高2位,则只需将数字向qamxswpoi移动到右侧,例如给出一个字节6
在你的情况下持有总值b
,你需要。
0x00110000
这里不需要屏蔽任何东西,因为没有更高的位。
对于你的例子中的b >> 6;
位,你需要通过(5,4,3)
向右移动,然后你需要用你的3
(&
或mask
)7
中间结果来摆脱保留b00000111
的两位,例如
(6,7)
在最后一部分,你的uint8_t mask = 7;
...
(b >> 3) & mask;
位,不需要移位,你只需要消除位(2,1,0)
上的所有位,例如,用你的面具摆脱2
,
(7,6,5,4,3)
完全放置,使用精确的宽度类型,您可以执行类似于以下操作。程序将您的字节值作为其第一个参数(使用b & mask
,例如,如果没有给出参数,则默认为48
)并输出移位和掩码的结果:
0x0011000
示例使用/输出
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main (int argc, char *argv[]) {
uint64_t tmp = argc > 1 ? strtoul (argv[1], NULL, 0) : 48;
uint8_t b = 0,
mask = 7;
if (tmp > UINT8_MAX) {
fprintf (stderr, "input exceeds UINT8_MAX.\n");
return 1;
}
b = (uint8_t)tmp;
printf ("(7,6) 0x%02" PRIx8 "\n", b >> 6);
printf ("(5,4,3) 0x%02" PRIx8 "\n", (b >> 3) & mask);
printf ("(2,1,0) 0x%02" PRIx8 "\n", b & mask);
return 0;
}
仔细看看,如果您有其他问题,请告诉我。
为了解析二进制值的特定位,我们使用位移和位掩码。可以使用以下概念以这种方式获得任何比特段:
$ /bin/bytes_233
(7,6) 0x00
(5,4,3) 0x06
(2,1,0) 0x00
其中(data >> n) & mask
是原始数据,data
是此数据开始的位位置,n
是“所有1”的位掩码,对应于段的长度。
“所有人”的mask
可以从知道片段大小获得:mask
。如果段的大小例如是3位,则1 << 3给出1000b。 1000b - 1 = 111b,这是3位的“全1”掩码。
因此,如果我们知道位的大小和位位置(偏移量),我们就可以得到数据。例:
(1u << size) - 1
带有“X宏”的高级版本,以避免代码重复:
#include <stdio.h>
#include <inttypes.h>
#define SEG1_BITS 2
#define SEG1_OFFSET 6
#define SEG2_BITS 3
#define SEG2_OFFSET 3
#define SEG3_BITS 2
#define SEG3_OFFSET 0
#define SEG1(d) ( ((uint32_t)d >> SEG1_OFFSET) & ((1u<<SEG1_BITS)-1) )
#define SEG2(d) ( ((uint32_t)d >> SEG2_OFFSET) & ((1u<<SEG2_BITS)-1) )
#define SEG3(d) ( ((uint32_t)d >> SEG3_OFFSET) & ((1u<<SEG3_BITS)-1) )
int main (void)
{
uint8_t data = 0x30;
printf("%"PRIu32"\n", SEG1(data));
printf("%"PRIu32"\n", SEG2(data));
printf("%"PRIu32"\n", SEG3(data));
return 0;
}
由于问题证明是广泛的,我不得不概括它并编写这个方法:
#include <stdio.h>
#include <inttypes.h>
#define SEG_LIST \
/*bits, offset */ \
X(2, 6) \
X(3, 3) \
X(2, 0)
#define SEG(data, bits, n) ( ((uint32_t)data >> n) & ((1u<<bits)-1) )
int main (void)
{
uint8_t data = 0x30;
#define X(bits, n) printf("%"PRIu32"\n", SEG(data, bits, n));
SEG_LIST
#undef X
return 0;
}
它将从字节的连续段中提取值。