/* Chrysalide - Outil d'analyse de fichiers binaires * pseudo.c - implémentation des pseudo-fonctions de spécification * * Copyright (C) 2014-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "pseudo.h" #include #include /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * carry = retenue enventuelle à constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'LSL_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_lsl_c(uint32_t x, unsigned int n, unsigned int shift, bool *carry, uint32_t *value) { if (n > 32) return false; if (shift == 0) return false; if (carry != NULL) *carry = x & (1 << (n - 1)); *value = x << shift; return true; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'LSL'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_lsl(uint32_t x, unsigned int n, unsigned int shift, uint32_t *value) { bool result; /* Bilan final à retourner */ if (shift == 0) result = true; else result = armv7_lsl_c(x, n, shift, NULL, value); return result; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * carry = retenue enventuelle à constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'LSR_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_lsr_c(uint32_t x, unsigned int n, unsigned int shift, bool *carry, uint32_t *value) { if (n > 32) return false; if (shift == 0) return false; if (carry != NULL) *carry = x & (1 << (shift - 1)); *value = x >> shift; return true; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'LSR'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_lsr(uint32_t x, unsigned int n, unsigned int shift, uint32_t *value) { bool result; /* Bilan final à retourner */ if (shift == 0) result = x; else result = armv7_lsr_c(x, n, shift, NULL, value); return result; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * carry = retenue enventuelle à constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ASR_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_asr_c(uint32_t x, unsigned int n, unsigned int shift, bool *carry, uint32_t *value) { if (n > 32) return false; if (shift == 0) return false; if (carry != NULL) *carry = x & (1 << (shift - 1)); *value = ((int32_t)x) >> shift; return true; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ASR'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_asr(uint32_t x, unsigned int n, unsigned int shift, uint32_t *value) { bool result; /* Bilan final à retourner */ if (shift == 0) result = true; else result = armv7_asr_c(x, n, shift, NULL, value); return result; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * carry = retenue enventuelle à constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ROR_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_ror_c(uint32_t x, unsigned int n, unsigned int shift, bool *carry, uint32_t *value) { if (n > 32) return false; if (shift == 0) return false; *value = (x >> shift) | (x << (32 - shift)); if (carry != NULL) *carry = *value & (1 << (n - 1)); return true; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * shift = nombre de décalages visés. * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ROR'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_ror(uint32_t x, unsigned int n, unsigned int shift, uint32_t *value) { bool result; /* Bilan final à retourner */ if (shift == 0) result = true; else result = armv7_ror_c(x, n, shift, NULL, value); return result; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * carry = retenue enventuelle à utiliser puis constituer. [OUT]* * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'RRX_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_rrx_c(uint32_t x, unsigned int n, bool *carry, uint32_t *value) { bool new_c; /* Nouvelle retenue à retenir */ new_c = x & 0x1; *value = (*carry ? 1 : 0) << (n - 1) | x >> 1; *carry = new_c; return true; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * carry = retenue enventuelle à utiliser. * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'RRX'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_rrx(uint32_t x, unsigned int n, bool carry, uint32_t *value) { return armv7_rrx_c(x, n, &carry, value); } /****************************************************************************** * * * Paramètres : imm12 = valeur sur 32 bits maximum à traiter. * * carry = retenue enventuelle à utiliser / constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ARMExpandImm_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_arm_expand_imm_c(uint32_t imm12, bool *carry, uint32_t *value) { bool result; /* Bilan final à retourner */ uint32_t unrotated; /* Transformation à décaller */ /** * Selon les spécifications, x contient toujours 12 bits utiles seulement. */ unrotated = armv7_zero_extend(imm12 & 0xff, 8, 32); result = armv7_shift(unrotated, 32, SRType_ROR, 2 * ((imm12 >> 8) & 0xf), carry, value); return result; } /****************************************************************************** * * * Paramètres : imm12 = valeur sur 32 bits maximum à traiter. * * carry = retenue enventuelle à utiliser / constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ARMExpandImm'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_arm_expand_imm(uint32_t imm12, uint32_t *value) { return armv7_arm_expand_imm_c(imm12, (bool []) { false /* FIXME : APSR.C */ }, value); } /****************************************************************************** * * * Paramètres : imm12 = valeur sur 32 bits maximum à traiter. * * carry = retenue enventuelle à utiliser / constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ThumbExpandImm_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_thumb_expand_imm_c(uint32_t imm12, bool *carry, uint32_t *value) { bool result; /* Conclusion à faire remonter */ uint8_t byte; /* Octet à reproduire */ uint32_t unrotated; /* Transformation à décaller */ result = true; if (((imm12 >> 10) & b11) == b00) { byte = imm12 & 0xff; switch ((imm12 >> 8) & b11) { case b00: *value = armv7_zero_extend(byte, 8, 32); break; case b01: if (byte == 0) result = false; else *value = byte << 16 | byte; break; case b10: if (byte == 0) result = false; else *value = byte << 24 | byte << 8; break; case b11: if (byte == 0) result = false; else *value = byte << 24 | byte << 16 | byte << 8 | byte; break; } } else { unrotated = 1 << 7 | (imm12 & 0x3f); result = armv7_ror_c(unrotated, 32, (imm12 >> 7) & 0x1f, carry, value); } return result; } /****************************************************************************** * * * Paramètres : imm12 = valeur sur 32 bits maximum à traiter. * * carry = retenue enventuelle à utiliser / constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'ThumbExpandImm'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_thumb_expand_imm(uint32_t imm12, uint32_t *value) { return armv7_thumb_expand_imm_c(imm12, (bool []) { false /* FIXME : APSR.C */ }, value); } /****************************************************************************** * * * Paramètres : type2 = type de décalage encodé sur 2 bits. * * imm5 = valeur de décalage entière sur 5 bits. * * type = type de décalage à constituer. [OUT] * * value = valeur pleine et entière à utiliser. [OUT] * * * * Description : Traduit la fonction 'DecodeImmShift'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_decode_imm_shift(uint8_t type2, uint8_t imm5, SRType *type, uint8_t *value) { bool result; /* Bilan à retourner */ result = true; switch (type2) { case b00: *type = SRType_LSL; *value = imm5; break; case b01: *type = SRType_LSR; *value = (imm5 == 0 ? 32 : imm5); break; case b10: *type = SRType_ASR; *value = (imm5 == 0 ? 32 : imm5); break; case b11: if (imm5 == 0) { *type = SRType_RRX; *value = 1; } else { *type = SRType_ROR; *value = imm5; } break; default: result = false; break; } return result; } /****************************************************************************** * * * Paramètres : type2 = type de décalage encodé sur 2 bits. * * type = type de décalage à constituer. [OUT] * * * * Description : Traduit la fonction 'DecodeRegShift'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_decode_reg_shift(uint8_t type2, SRType *type) { bool result; /* Bilan à retourner */ result = true; switch (type2) { case b00: *type = SRType_LSL; break; case b01: *type = SRType_LSR; break; case b10: *type = SRType_ASR; break; case b11: *type = SRType_ROR; break; default: result = false; break; } return result; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * type = type d'opération à mener. * * amount = quantité liée à l'opération à mener. * * carry = retenue enventuelle à utiliser / constituer. [OUT] * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'Shift_C'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_shift_c(uint32_t x, unsigned int n, SRType type, unsigned int amount, bool *carry, uint32_t *value) { bool result; /* Bilan final à retourner */ if (type == SRType_RRX && amount != 1) return false; if (amount == 0) { *value = x; return true; } result = true; /* Pour GCC... */ switch (type) { case SRType_LSL: result = armv7_lsl_c(x, n, amount, carry, value); break; case SRType_LSR: result = armv7_lsr_c(x, n, amount, carry, value); break; case SRType_ASR: result = armv7_asr_c(x, n, amount, carry, value); break; case SRType_ROR: result = armv7_ror_c(x, n, amount, carry, value); break; case SRType_RRX: result = armv7_rrx_c(x, n, carry, value); break; } return result; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * type = type d'opération à mener. * * amount = quantité liée à l'opération à mener. * * carry = retenue enventuelle à utiliser. * * value = nouvelle valeur calculée. [OUT] * * * * Description : Traduit la fonction 'Shift'. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool armv7_shift(uint32_t x, unsigned int n, SRType type, unsigned int amount, bool carry, uint32_t *value) { return armv7_shift_c(x, n, type, amount, &carry, value); } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * n = nombre de bits à prendre en compte. * * i = taille finale à obtenir. * * * * Description : Traduit la fonction 'ZeroExtend'. * * * * Retour : Nouvelle valeur calculée. * * * * Remarques : - * * * ******************************************************************************/ uint32_t armv7_zero_extend(uint32_t x, unsigned int n, unsigned int i) { return x; } /****************************************************************************** * * * Paramètres : x = valeur sur 32 bits maximum à traiter. * * t = bit de poids nombre de bits à prendre en compte. * * i = taille finale à obtenir. * * * * Description : Fournit une aide pour la fonction 'SignExtend'. * * * * Retour : Nouvelle valeur calculée. * * * * Remarques : - * * * ******************************************************************************/ uint32_t armv7_sign_extend(uint32_t x, unsigned int t, unsigned int i) { uint32_t result; /* Valeur à retourner */ bool set; /* Bit de poids fort à 1 ? */ unsigned int k; /* Boucle de parcours */ result = 0; set = (x & (1 << t)); switch (i) { #define SIGN_EXTEND_CASE(sz) \ case sz: \ result = x; \ if (set) \ for (k = t + 1; k < sz; k++) \ result |= (1 << k); \ break; SIGN_EXTEND_CASE(4); SIGN_EXTEND_CASE(8); SIGN_EXTEND_CASE(16); SIGN_EXTEND_CASE(32); } return result; }