From 67d09c125b8becff728b98ea4132e3fc98dfd0d0 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 31 Mar 2018 17:46:28 -0600 Subject: [PATCH] Fix Intersection bucket retrievals --- bktr.c | 25 +++++++++++++++++++------ bktr.h | 3 +++ nca.c | 24 ++++++++++++++++++++---- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/bktr.c b/bktr.c index 37d2863..1fe982d 100644 --- a/bktr.c +++ b/bktr.c @@ -1,6 +1,10 @@ #include "bktr.h" #include "utils.h" +bktr_relocation_bucket_t *bktr_get_relocation_bucket(bktr_relocation_block_t *block, uint32_t i) { + return (bktr_relocation_bucket_t *)((uint8_t *)block->buckets + (sizeof(bktr_relocation_bucket_t) + sizeof(bktr_relocation_entry_t)) * i); +} + /* Get a relocation entry from offset and relocation block. */ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset) { /* Weak check for invalid offset. */ @@ -9,16 +13,19 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin exit(EXIT_FAILURE); } - bktr_relocation_bucket_t *bucket = &block->buckets[0]; + uint32_t bucket_num = 0; for (unsigned int i = 1; i < block->num_buckets; i++) { - if (block->bucket_virtual_offsets[i] < offset) { - bucket++; + if (block->bucket_virtual_offsets[i] <= offset) { + bucket_num++; } } + bktr_relocation_bucket_t *bucket = bktr_get_relocation_bucket(block, bucket_num); + if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */ return &bucket->entries[0]; } + /* Binary search. */ uint32_t low = 0, high = bucket->num_entries - 1; while (low <= high) { @@ -37,6 +44,10 @@ bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uin exit(EXIT_FAILURE); } +bktr_subsection_bucket_t *bktr_get_subsection_bucket(bktr_subsection_block_t *block, uint32_t i) { + return (bktr_subsection_bucket_t *)((uint8_t *)block->buckets + (sizeof(bktr_subsection_bucket_t) + sizeof(bktr_subsection_entry_t)) * i); +} + /* Get a subsection entry from offset and subsection block .*/ bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset) { /* If offset is past the virtual, we're reading from the BKTR_HEADER subsection. */ @@ -44,13 +55,15 @@ bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uin return &block->buckets[block->num_buckets - 1].entries[block->buckets[block->num_buckets - 1].num_entries]; } - bktr_subsection_bucket_t *bucket = &block->buckets[0]; + uint32_t bucket_num = 0; for (unsigned int i = 1; i < block->num_buckets; i++) { - if (block->bucket_physical_offsets[i] < offset) { - bucket++; + if (block->bucket_physical_offsets[i] <= offset) { + bucket_num++; } } + bktr_subsection_bucket_t *bucket = bktr_get_subsection_bucket(block, bucket_num); + if (bucket->num_entries == 1) { /* Check for edge case, short circuit. */ return &bucket->entries[0]; } diff --git a/bktr.h b/bktr.h index f124ee5..0c89d37 100644 --- a/bktr.h +++ b/bktr.h @@ -69,7 +69,10 @@ typedef struct { } bktr_subsection_block_t; #pragma pack(pop) +bktr_relocation_bucket_t *bktr_get_relocation_bucket(bktr_relocation_block_t *block, uint32_t i); bktr_relocation_entry_t *bktr_get_relocation(bktr_relocation_block_t *block, uint64_t offset); + +bktr_subsection_bucket_t *bktr_get_subsection_bucket(bktr_subsection_block_t *block, uint32_t i); bktr_subsection_entry_t *bktr_get_subsection(bktr_subsection_block_t *block, uint64_t offset); #endif \ No newline at end of file diff --git a/nca.c b/nca.c index 050c9dd..ebb4371 100644 --- a/nca.c +++ b/nca.c @@ -921,13 +921,13 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) { exit(EXIT_FAILURE); } /* Allocate space for an extra (fake) relocation entry, to simplify our logic. */ - void *relocs = calloc(1, sb->relocation_header.size + sizeof(bktr_relocation_entry_t)); + void *relocs = calloc(1, sb->relocation_header.size + (0x3FF0 / sizeof(uint64_t)) * sizeof(bktr_relocation_entry_t)); if (relocs == NULL) { fprintf(stderr, "Failed to allocate relocation header!\n"); exit(EXIT_FAILURE); } /* Allocate space for an extra (fake) subsection entry, to simplify our logic. */ - void *subs = calloc(1, sb->subsection_header.size + 2 * sizeof(bktr_subsection_entry_t)); + void *subs = calloc(1, sb->subsection_header.size + (0x3FF0 / sizeof(uint64_t)) * sizeof(bktr_subsection_entry_t) + sizeof(bktr_subsection_entry_t)); if (subs == NULL) { fprintf(stderr, "Failed to allocate subsection header!\n"); exit(EXIT_FAILURE); @@ -957,8 +957,24 @@ void nca_process_bktr_section(nca_section_ctx_t *ctx) { } /* This simplifies logic greatly... */ - bktr_relocation_bucket_t *last_reloc_bucket = &ctx->bktr_ctx.relocation_block->buckets[ctx->bktr_ctx.relocation_block->num_buckets - 1]; - bktr_subsection_bucket_t *last_subsec_bucket = &ctx->bktr_ctx.subsection_block->buckets[ctx->bktr_ctx.subsection_block->num_buckets - 1]; + for (unsigned int i = ctx->bktr_ctx.relocation_block->num_buckets - 1; i > 0; i--) { + memcpy(bktr_get_relocation_bucket(ctx->bktr_ctx.relocation_block, i), &ctx->bktr_ctx.relocation_block->buckets[i], sizeof(bktr_relocation_bucket_t)); + } + for (unsigned int i = 0; i + 1 < ctx->bktr_ctx.relocation_block->num_buckets; i++) { + bktr_relocation_bucket_t *cur_bucket = bktr_get_relocation_bucket(ctx->bktr_ctx.relocation_block, i); + cur_bucket->entries[cur_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->bucket_virtual_offsets[i + 1]; + } + for (unsigned int i = ctx->bktr_ctx.subsection_block->num_buckets - 1; i > 0; i--) { + memcpy(bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, i), &ctx->bktr_ctx.subsection_block->buckets[i], sizeof(bktr_subsection_bucket_t)); + } + for (unsigned int i = 0; i + 1 < ctx->bktr_ctx.subsection_block->num_buckets; i++) { + bktr_subsection_bucket_t *cur_bucket = bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, i); + bktr_subsection_bucket_t *next_bucket = bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, i+1); + cur_bucket->entries[cur_bucket->num_entries].offset = next_bucket->entries[0].offset; + cur_bucket->entries[cur_bucket->num_entries].ctr_val = next_bucket->entries[0].ctr_val; + } + bktr_relocation_bucket_t *last_reloc_bucket = bktr_get_relocation_bucket(ctx->bktr_ctx.relocation_block, ctx->bktr_ctx.relocation_block->num_buckets - 1); + bktr_subsection_bucket_t *last_subsec_bucket = bktr_get_subsection_bucket(ctx->bktr_ctx.subsection_block, ctx->bktr_ctx.subsection_block->num_buckets - 1); last_reloc_bucket->entries[last_reloc_bucket->num_entries].virt_offset = ctx->bktr_ctx.relocation_block->total_size; last_subsec_bucket->entries[last_subsec_bucket->num_entries].offset = sb->relocation_header.offset; last_subsec_bucket->entries[last_subsec_bucket->num_entries].ctr_val = ctx->header->section_ctr_low;