diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2020-01-27 18:48:58 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2020-01-27 18:48:58 (GMT) |
commit | c1ca03be00a4e975f89d30edfb72b57fb5612282 (patch) | |
tree | 4884513252458a261eb1290c93748b2bbbd98ff8 /src/format | |
parent | 1b3887c5609831bc2aee2f00f6a4d31d7406a225 (diff) |
Created a huge optimization for the Dex format loading.
Diffstat (limited to 'src/format')
-rw-r--r-- | src/format/format.c | 107 | ||||
-rw-r--r-- | src/format/format.h | 3 |
2 files changed, 110 insertions, 0 deletions
diff --git a/src/format/format.c b/src/format/format.c index ab4864f..f6a4bd0 100644 --- a/src/format/format.c +++ b/src/format/format.c @@ -871,6 +871,113 @@ bool g_binary_format_add_symbol(GBinFormat *format, GBinSymbol *symbol) /****************************************************************************** * * +* Paramètres : format = informations chargées à compléter. * +* symbols = ensemble de symboles à ajouter à la liste. * +* count = taille de cet ensemble. * +* * +* Description : Ajoute plusieurs symboles à la collection du format binaire. * +* * +* Retour : true si les symboles dûment localisés ont été insérés. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_binary_format_add_symbols(GBinFormat *format, GBinSymbol **symbols, size_t count) +{ + bool result; /* Statut d'ajout à retourner */ +#ifndef NDEBUG + phys_t last; /* Dernière position rencontrée*/ +#endif + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + const mrange_t *range; /* Couverture du symbole */ + const vmpa2t *addr; /* Emplacement du symbole */ +#endif + size_t index; /* Indice du point d'insertion */ + + /** + * Pour que les fonctions de recherche basées sur _g_binary_format_find_symbol() + * fassent bien leur office, il faut que les symboles soient triés. + * + * Cependant, les localisations à satisfaire lors d'une recherche recontrent + * un problème si les positions physiques ne sont pas renseignées. En effet + * les adresses virtuelles en sont potentiellement décorrélées (c'est le cas + * avec le format ELF par exemple, où les zones en mémoire ne suivent pas le + * même ordre que les segments du binaire). + * + * Comme les comparaisons entre localisations se réalisent sur les éléments + * renseignés communs, à commencer par la position physique si c'est possible, + * une localisation s'appuyant uniquement sur une adresse virtuelle va être + * analysée suivant une liste non triée d'adresses virtuelles. + * + * On corrige donc le tir si besoin est en forçant la comparaison via les + * positions physiques. + */ + +#ifndef NDEBUG + last = VMPA_NO_PHYSICAL; + + for (i = 0; i < count; i++) + { + range = g_binary_symbol_get_range(symbols[i]); + addr = get_mrange_addr(range); + + assert(has_phys_addr(addr) + || g_binary_symbol_get_status(symbols[i]) == SSS_IMPORTED + || g_binary_symbol_get_status(symbols[i]) == SSS_DYNAMIC); + + + if (has_phys_addr(addr)) + { + assert(last == VMPA_NO_PHYSICAL || last <= get_phy_addr(addr)); + last = get_phy_addr(addr); + } + + } +#endif + + g_binary_format_lock_unlock_symbols_wr(format, true); + + /** + * Avec tous les traitements parallèles, il est possible que plusieurs chemins d'exécution + * amènent à la création d'un même symbole. + * + * Plutôt que de verrouiller la liste des symboles en amont (et donc assez longtemps) + * pour faire une vérification avant construction puis ajout, on préfère limiter + * l'état figé à cette seule fonction, quitte à annuler le travail fourni pour la + * construction du symbole dans les cas peu fréquents où le symbole était déjà en place. + */ + + result = bsearch_index(symbols[0], format->symbols, format->sym_count, + sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp, &index); + + if (!result) + { + for (i = 0; i < count; i++) + g_object_ref(G_OBJECT(symbols[i])); + + format->symbols = _qinsert_batch(format->symbols, &format->sym_count, + sizeof(GBinSymbol *), symbols, count, index); + + format->sym_stamp++; + result = true; + + } + + g_binary_format_lock_unlock_symbols_wr(format, false); + + if (result) + for (i = 0; i < count; i++) + g_signal_emit_by_name(format, "symbol-added", symbols[i]); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : format = informations chargées à compléter. * * index = indice du symbole à retirer de la liste. * * * diff --git a/src/format/format.h b/src/format/format.h index 748fd54..b001a15 100644 --- a/src/format/format.h +++ b/src/format/format.h @@ -129,6 +129,9 @@ GBinSymbol *g_binary_format_get_symbol(const GBinFormat *, size_t); /* Ajoute un symbole à la collection du format binaire. */ bool g_binary_format_add_symbol(GBinFormat *, GBinSymbol *); +/* Ajoute plusieurs symboles à la collection du format binaire. */ +bool g_binary_format_add_symbols(GBinFormat *, GBinSymbol **, size_t); + /* Retire un symbole de la collection du format binaire. */ void g_binary_format_remove_symbol(GBinFormat *, GBinSymbol *); |