parsing some special arm instructions

This commit is contained in:
nganhkhoa 2024-08-26 15:59:43 +07:00
parent 04979b0afd
commit d9024990f9
2 changed files with 175 additions and 0 deletions

View File

@ -0,0 +1,168 @@
#include <stdio.h>
#include <stdint.h>
#define true 1
#define false 0
// this file encodes and decodes arm instructions
// only support for ARMv8 or (aarch64) because
// it is the default ISA in Apple devices
// https://yurichev.com/mirrors/ARMv8-A_Architecture_Reference_Manual_(Issue_A.a).pdf
// using bit field in little endian is crazy
// but clang does not support switching endianess (fuck u llvm)
// gcc does, but default on Apple compiler is clang
// TODO: default to using big endian for bit field parsing
// this file assumes everything is LITTLE ENDIAN
// the struct is assigned as bit field, and parsed using get_bits
// to encode the instruction, can use the bit field and load each bits
// through shifting, by default it has 0 padded so should work
// mask to delete last 12 bits
uint32_t ZEROS_12_LOWER = ~0xFFF;
uint32_t get_bits(uint32_t value, uint32_t from, uint32_t to) {
// should assert compiler error
if (to < from) return false;
if (from == to) {
// bit at position is set
return (value & (1 << from)) != 0;
}
int32_t mask = ~(1U << (to - from + 1));
return (value & mask) >> from;
}
int is_bit_set(uint32_t value, uint32_t at) {
return (value & (1 << at)) != 0;
}
struct add {
uint32_t sf : 1;
uint32_t op : 1;
uint32_t s : 1;
uint32_t sig : 5;
uint32_t imm : 12;
uint32_t rn : 5;
uint32_t rd : 5;
};
struct add to_add(uint32_t inst) {
struct add parsed;
parsed.sf = is_bit_set(inst, 31);
parsed.op = is_bit_set(inst, 30);
parsed.s = is_bit_set(inst, 29);
parsed.sig = get_bits(inst, 24, 28);
parsed.imm = get_bits(inst, 10, 21);
parsed.rn = get_bits(inst, 5, 9);
parsed.rd = get_bits(inst, 0, 4);
return parsed;
}
void from_add(struct add parsed, uint32_t *inst) {
*inst = 0;
*inst |= parsed.sf << 31;
*inst |= parsed.op << 30;
*inst |= parsed.s << 29;
*inst |= parsed.sig << 24;
*inst |= parsed.imm << 10;
*inst |= parsed.rn << 5;
*inst |= parsed.rd;
}
int add_imm_set(uint32_t *inst, uint32_t offset) {
struct add parsed = to_add(*inst);
if (parsed.op != 0 || parsed.sig != 0b10001) {
return false;
}
parsed.imm = offset; // auto truncate?
from_add(parsed, inst);
return true;
}
uint32_t add_imm_get(uint32_t inst) {
struct add parsed = to_add(inst);
return parsed.imm;
}
int is_add(uint32_t inst) {
struct add parsed = to_add(inst);
if (parsed.op != 0 || parsed.sig != 0b10001) {
return false;
}
return true;
}
struct adrp {
uint32_t op : 1;
uint32_t immlo : 2;
uint32_t sig : 5;
uint32_t immhi : 19;
uint32_t rd : 5;
};
struct adrp to_adrp(uint32_t inst) {
struct adrp parsed;
parsed.op = is_bit_set(inst, 31);
parsed.immlo = get_bits(inst, 29, 30);
parsed.sig = get_bits(inst, 24, 28);
parsed.immhi = get_bits(inst, 5, 23);
parsed.rd = get_bits(inst, 0, 4);
return parsed;
}
void from_adrp(struct adrp parsed, uint32_t *inst) {
*inst = 0;
*inst |= parsed.op << 31;
*inst |= parsed.immlo << 29;
*inst |= parsed.sig << 24;
*inst |= parsed.immhi << 5;
*inst |= parsed.rd;
}
int is_adrp(uint32_t inst) {
struct adrp parsed = to_adrp(inst);
if (parsed.op != 1 || parsed.sig != 0b10000) {
return false;
}
return true;
}
// change adrp imm to something else
int adrp_imm_set(uint32_t *inst, uint32_t offset) {
struct adrp parsed = to_adrp(*inst);
if (parsed.op != 1 || parsed.sig != 0b10000) {
return false;
}
// uint32_t imm = 0;
// imm = parsed.immhi << 14;
// imm |= parsed.immlo << 12;
// printf("old adrp is %x\n", imm);
// printf(" immlo %x\n", parsed.immlo);
// printf(" immhi %x\n", parsed.immhi);
// adrp: register = (base masked lower 12-bit) + imm
parsed.immlo = get_bits(offset >> 12, 0, 1);
parsed.immhi = offset >> 14;
// imm = parsed.immhi << 14;
// imm |= parsed.immlo << 12;
// printf("new adrp is %x\n", imm);
// printf(" immlo %x\n", parsed.immlo);
// printf(" immhi %x\n", parsed.immhi);
from_adrp(parsed, inst);
return true;
}
uint32_t adrp_imm_get(uint32_t inst) {
struct adrp parsed = to_adrp(inst);
uint32_t imm = 0;
imm = parsed.immhi << 14;
imm |= parsed.immlo << 12;
return imm;
}

View File

@ -0,0 +1,7 @@
int is_add(uint32_t inst);
int add_imm_set(uint32_t *inst, uint32_t offset);
uint32_t add_imm_get(uint32_t inst);
int is_adrp(uint32_t inst);
int adrp_imm_set(uint32_t *inst, uint32_t offset);
uint32_t adrp_imm_get(uint32_t inst);