位域结构体存储的32位指令转换为小端十六进制输出问题
问题描述
我需要将32位指令转换为机器码二进制,示例指令add #3, #5, #9的参数如下:
- opcode为0
rs取第一个操作数值3,rt取第二个操作数值5,rd取第三个操作数值9- funct值为1
- 未使用的6位统一填0
#x代表内存中的寄存器
因此上述R型指令的二进制表示为:
opCodersrtrdfunctunused000001 00011 00101 01001 00001 000000,即32位/4字节指令
我当前使用以下联合体定义存储各类型指令:
typedef union __attribute__((__packed__)) { struct { unsigned opcode : 6; unsigned rs : 5; unsigned rt : 5; unsigned rd : 5; unsigned funct : 5; unsigned unused : 6; } r; struct { unsigned first : 8; unsigned second : 8; unsigned third : 8; unsigned fourth : 8; } bytes; } r_instruction; typedef union __attribute__((__packed__)) { struct { unsigned rs : 5; unsigned rt : 5; unsigned opcode : 6; unsigned immed : 16; } i; struct { unsigned first : 8; unsigned second : 8; unsigned third : 8; unsigned fourth : 8; } bytes; } i_instruction; typedef union __attribute__((__packed__)) { struct { unsigned addr : 25; unsigned opcode : 6; unsigned isReg : 1; } j; struct { unsigned first : 8; unsigned second : 8; unsigned third : 8; unsigned fourth : 8; } bytes; } j_instruction;
我的需求是将每条指令的二进制输出到文件,每行对应一条指令的4字节,每个字节以十六进制表示,字节序为小端。
待处理的输入汇编代码如下:
;comment MAIN: add #3, #5, #9 LOOP: ori #9, -5, #2 la val1 jmp Next Next: move #20, #4 bgt #0, #2, END la K sw #0, 4, #10 bne #31, #9 , LOOP call val1 jmp #4 END: stop STR: .asciz "aBcd" LIST: .db 6, -9 .dh 27056 .dw 5 .entry K K: .dw 31,-12 .extern val1
我按照如下方式输出时得到的结果不符合预期:
r_instruction inst; inst.r.opcode = 0; inst.r.rs = 3; inst.r.rt = 5; inst.r.rd = 9; inst.r.funct = 1; inst.r.unused = 0; printf("%x %x %x %x", inst.bytes.first, inst.bytes.second, inst.bytes.third, inst.bytes.fourth); // 输出结果为 c0 28 29 0
请问我应该如何修改,才能将存储的指令转换为要求的输出格式?
解决方案
你遇到的问题核心是C语言位域的分配顺序和你预期的指令字段排列顺序不符,小端架构下,编译器会从结构体低地址的最低位开始分配位域,你当前写的位域顺序是从高位到低位排列,和实际分配规则完全相反。
第一步:修正所有指令的位域定义顺序
你需要把位域按照「从最低位到最高位」的顺序倒着写,和你之前的定义顺序反过来:
- R型指令原预期的字段排列(高位到低位)是
opcode -> rs -> rt -> rd -> funct -> unused,对应位域定义要反过来(低位到高位):
struct { unsigned unused : 6; // 最低6位 unsigned funct : 5; unsigned rd : 5; unsigned rt : 5; unsigned rs : 5; unsigned opcode : 6; // 最高6位 } r;
- I型指令、J型指令同理,把你定义的结构体字段顺序完全倒转即可。
第二步:修正输出格式
你当前的printf没有补前导零,会导致小于0x10的字节只输出1位,不符合要求,修改输出语句为:
printf("%02x %02x %02x %02x\n", inst.bytes.first, inst.bytes.second, inst.bytes.third, inst.bytes.fourth);
%02x表示输出两位十六进制,不足的位置前面补0。
修正后再运行代码,输出结果就会符合小端字节序的要求。
内容的提问来源于stack exchange,提问作者best man
相关产品推荐
相关产品推荐

