Ler um arquivo binário e mostrar os bits (Linguagem C)

Boa noite, alguém poderia me ajudar nesta?
Terei um arquivo contendo em linguagem de montagem do MIPS ex:

add $1, $2, $3
bne $2, $3, 0x5

Enfim, o arquivo é contem estas instruções é binário e cada uma delas é uma palavra de 32 bits.
Eu devo abrir este arquivo e manipular os bits, porém não consegui ainda fazer essa leitura dos bits dessa forma.

Se alguém puder ajudar agradeço.

Basicamente, o que vocë precisa procurar é:

Abrir o arquivo - fopen
Ler 4 bytes - fread
Pegar os 4 bytes e transformar em bits - usar os operadores <<, >>, &, | e ~

Só uma coisinha para te desanimar. Onde você arranjou esse arquivo? Se for um binário como um executável de um Linux portado para MIPS, ele tem muito mais coisas que simplesmente as instruções do processador. Você precisa arranjar a documentação desse formato de arquivo; muitas vezes, um binário desses é link-editado em tempo de execução e coisas importantes (como branches) não aparecem com seus valores corretos e sim como zeros ou então índices para uma tabela de funções que são link-editados no tempo de carregamento do binário.

Se trata de um arquivo gerado pelo simulador Mipisit, contendo as instruções, que nesse caso é do MIPS.

Então deve ser mais fácil fazer o “disassembly”. Tem certeza que não há nenhuma ferramenta pronta que faça isso por você, ou isso é um trabalho de escola (fazer o “disassembly” das instruções)?

É um trabalho da faculdade, tenho que ler esse arquivo, pegar os 32 bits da instrução e manipular, porém estou desnorteado quanto a primeira parte, que é ler esses bits.
Trabalho pouco com c, por isso não sei exatamente uma forma de faze-lo.

Tem certeza que seu trabalho de escola é esse mesmo? Estou lendo a especificação das instruções MIPS e vai dar um trabalhinho lascado.

http://www.weblearn.hs-bremen.de/risse/RST/docs/MIPS/mips-isa.pdf

Veja a página 40 dessa especificação.

É isso mesmo, a identificação das instruções estão mapeadas nos bits delas, no caso:

add $1, $2, $3

esperasse que tenha 32 bits e a partir dos seis mais significativos(e nesse caso os seis menos significativos também), decodificar a instrução e apresentar ela na linguagem de montagem.

até agora só o que fiz foi tentar ler o arquivo em modo binário.


FILE *fp;
char caracter;

fp = fopen("path", "rb");

while(!feof())
caracter = getc(fp);

porém é um byte que vem.

  1. Evite usar feof() - C não é Pascal, e feof() não é uma boa forma de detectar se o arquivo acabou. O correto é tentar ler e verificar se apareceram menos bytes que o desejado
  2. Ler a documentação não faz mal a ninguém - eu não cantei a bola do fread? Não use getc, não serve para o que você precisa .

Um grande problema, a meu ver, é que não sei no seu arquivo se os bytes estão escritos na ordem natural ou na ordem inversa.

Por exemplo, digamos que um opcode seja uma palavra de 32 bits representada por:

int opcode = 0x12345678;

Nesse seu arquivo, não sei se ele está gravado na ordem natural (ou seja, byte 0 = 0x12, byte 1 = 0x34, byte 2 = 0x56, byte 3 = 0x78 )
ou na ordem inversa (byte 0 = 0x78, byte 1 = 0x56, byte 2 = 0x34, byte 3 = 0x12). É que o processador MIPS pode trabalhar em uma das duas orientações:

Procurarei saber mais a respeito do arquivo de entrada.

Vamos supor, apenas para simplificar, que o arquivo só contenha instruções, que todas as instruções sejam de 32 bits, e que os bytes venham em ordem natural.
Vamos supor também que unsigned int, no seu compilador C, tenha exatamente 32 bits.
Você faria algo como:

...
unsigned int getInstruction (unsigned char bytes[]) {
    return (bytes[0] << 24) | (bytes[1]<<16) | (bytes[2] <<8) | bytes[3];
}
...
FILE *f = fopen (....);
unsigned char bytes[4];
unsigned int instruction;
int nBytes;
while ((nBytes = fread (bytes, 1, sizeof(bytes), f) > 0) {
    instruction = getInstruction (bytes);
    if ((instruction & 0x07FF) == 0x0020)) {
    /* Instrução ADD rd, rs, rt */
    /* A decodificação desta instrução é por sua conta :) */
    }
}
unsigned int getInstruction (unsigned char bytes[]) {  
    return (bytes[0] << 24) | (bytes[1]<<16) | (bytes[2] <<8) | bytes[3];  
}  

O valor desta função vai ser retornado em hexa?

Segredinho que não te contaram - o computador não trabalha em hexa :slight_smile:

Ele pode imprimir o resultado de um dado em hexa, por exemplo.

unsigned char bytes[4];
unsigned int val;
bytes[0] = 0x12;
bytes[1] = 0x34;
bytes[2] = 0x56;
bytes[3] = 0x78;
val = getInstruction  (bytes);
printf ("%08X", val); /* deve imprimir 12345678 */