void Binary::shift_command(size_t width, size_t from_offset) {
  const SegmentCommand* segment = segment_from_offset(from_offset);

  size_t __text_base_addr = 0;
  size_t virtual_address = 0;

  if (segment != nullptr) {
    virtual_address = segment->virtual_address() + from_offset;
  }

  if (const SegmentCommand* text = get_segment("__TEXT")) {
    __text_base_addr = text->virtual_address();
  }


  // Shift symbols command
  // =====================
  if (SymbolCommand* sym_cmd = symbol_command()) {

    if (sym_cmd->symbol_offset() > from_offset) {
      sym_cmd->symbol_offset(sym_cmd->symbol_offset() + width);
    }

    if (sym_cmd->strings_offset() > from_offset) {
      sym_cmd->strings_offset(sym_cmd->strings_offset() + width);
    }

    for (std::unique_ptr<Symbol>& s : symbols_) {
      static constexpr size_t N_TYPE = 0x0e;
      if (static_cast<N_LIST_TYPES>(s->type() & N_TYPE) == N_LIST_TYPES::N_SECT) {
        uint64_t value = s->value();
        if (value > from_offset) {
          s->value(value + width);
        }
      }
    }
  }

  // Data In Code
  // ============
  if (DataInCode* data_code_cmd = data_in_code()) {
    if (data_code_cmd->data_offset() > from_offset) {
      data_code_cmd->data_offset(data_code_cmd->data_offset() + width);
    }
  }


  // Code Signature
  // ==============
  if (CodeSignature* sig = code_signature()) {
    if (sig->data_offset() > from_offset) {
      sig->data_offset(sig->data_offset() + width);
    }
  }

  if (CodeSignatureDir* sig_dir = code_signature_dir()) {
    if (sig_dir->data_offset() > from_offset) {
      sig_dir->data_offset(sig_dir->data_offset() + width);
    }
  }

  if (SegmentSplitInfo* ssi = segment_split_info()) {
    if (ssi->data_offset() > from_offset) {
      ssi->data_offset(ssi->data_offset() + width);
    }
  }

  // Shift Main Command
  // ==================
  if (MainCommand* main_cmd = main_command()) {
     if ((__text_base_addr + main_cmd->entrypoint()) > virtual_address) {
      main_cmd->entrypoint(main_cmd->entrypoint() + width);
    }
  }

  // Patch function starts
  // =====================
  if (FunctionStarts* fs = function_starts()) {
    if (fs->data_offset() > from_offset) {
      fs->data_offset(fs->data_offset() + width);
    }
    for (uint64_t& address : fs->functions()) {
      if ((__text_base_addr + address) > virtual_address) {
        address += width;
      }
    }
  }

  // Dynamic symbol command
  // ======================
  if (DynamicSymbolCommand* dyn_cmd = dynamic_symbol_command()) {
    if (dyn_cmd->toc_offset() > from_offset) {
      dyn_cmd->toc_offset(dyn_cmd->toc_offset() + width);
    }

    if (dyn_cmd->module_table_offset() > from_offset) {
      dyn_cmd->module_table_offset(dyn_cmd->module_table_offset() + width);
    }

    if (dyn_cmd->external_reference_symbol_offset() > from_offset) {
      dyn_cmd->external_reference_symbol_offset(dyn_cmd->external_reference_symbol_offset() + width);
    }

    if (dyn_cmd->indirect_symbol_offset() > from_offset) {
      dyn_cmd->indirect_symbol_offset(dyn_cmd->indirect_symbol_offset() + width);
    }

    if (dyn_cmd->external_relocation_offset() > from_offset) {
      dyn_cmd->external_relocation_offset(dyn_cmd->external_relocation_offset() + width);
    }

    if (dyn_cmd->local_relocation_offset() > from_offset) {
      dyn_cmd->local_relocation_offset(dyn_cmd->local_relocation_offset() + width);
    }
  }

  // Patch Dyld
  // ==========
  if (DyldInfo* dyld = dyld_info()) {

    // Shift underlying containers offset
    if (dyld->rebase().first > from_offset) {
      dyld->set_rebase_offset(dyld->rebase().first + width);
    }

    if (dyld->bind().first > from_offset) {
      dyld->set_bind_offset(dyld->bind().first + width);
    }

    if (dyld->weak_bind().first > from_offset) {
      dyld->set_weak_bind_offset(dyld->weak_bind().first + width);
    }

    if (dyld->lazy_bind().first > from_offset) {
      dyld->set_lazy_bind_offset(dyld->lazy_bind().first + width);
    }

    if (dyld->export_info().first > from_offset) {
      dyld->set_export_offset(dyld->export_info().first + width);
    }


    // Shift Relocations
    // -----------------
    // TODO: Optimize this code
    for (Relocation& reloc : relocations()) {
      if (reloc.address() > virtual_address) {
        if (is64_) {
          patch_relocation<uint64_t>(reloc, /* from */ virtual_address, /* shift */ width);
        } else {
          patch_relocation<uint32_t>(reloc, /* from */ virtual_address, /* shift */ width);
        }
        reloc.address(reloc.address() + width);
      }
    }

    // Shift Export Info
    // -----------------
    for (ExportInfo& info : dyld->exports()) {
      if (info.address() > virtual_address) {
        info.address(info.address() + width);
      }
    }

    // Shift bindings
    // --------------
    for (DyldBindingInfo& info : dyld->bindings()) {
      if (info.address() > virtual_address) {
        info.address(info.address() + width);
      }
    }
  }

  if (DyldChainedFixups* fixups = dyld_chained_fixups()) {
    fixups->data_offset(fixups->data_offset() + width);

    // Update relocations
    for (auto& entry : fixups->chained_starts_in_segments()) {
      for (auto& reloc : entry.segment.relocations()) {
        if (RelocationFixup::classof(reloc)) {
          auto& fixup = static_cast<RelocationFixup&>(reloc);
          if (fixup.offset() > from_offset) {
            fixup.offset(fixup.offset() + width);
          }
          if (fixup.target() > virtual_address) {
            fixup.target(fixup.target() + width);
          }
          // No need to update the virtual address since
          // it is bound to the offset
        }
      }
    }
    for (ChainedBindingInfo& bind : fixups->bindings()) {
      if (bind.offset() > from_offset) {
        bind.offset(bind.offset() + width);
      }
      // We don't need to update the virtual address,
      // as it is bound to the offset
    }
  }

  if (DyldExportsTrie* exports = dyld_exports_trie()) {
    for (ExportInfo& info : exports->exports()) {
      if (virtual_address >= info.address()) {
        info.address(info.address() + width);
      }
    }
    if (exports->data_offset() > from_offset) {
      exports->data_offset(exports->data_offset() + width);
    }
  }

  if (LinkerOptHint* opt = linker_opt_hint()) {
    if (opt->data_offset() > from_offset) {
      opt->data_offset(opt->data_offset() + width);
    }
  }

  if (TwoLevelHints* two = two_level_hints()) {
    if (two->offset() > from_offset) {
      two->offset(two->offset() + width);
    }
  }

  for_commands<EncryptionInfo>([from_offset, width] (EncryptionInfo& enc) {
    if (enc.crypt_offset() > from_offset) {
      enc.crypt_offset(enc.crypt_offset() + width);
    }
  });

}
void Binary::shift_command(size_t width, size_t from_offset) {
  const SegmentCommand* segment = segment_from_offset(from_offset);

  size_t __text_base_addr = 0;
  size_t virtual_address = 0;

  if (segment != nullptr) {
    virtual_address = segment->virtual_address() + from_offset;
  }

  if (const SegmentCommand* text = get_segment("__TEXT")) {
    __text_base_addr = text->virtual_address();
  }


   
   
  if (SymbolCommand* sym_cmd = symbol_command()) {

    if (sym_cmd->symbol_offset() > from_offset) {
      sym_cmd->symbol_offset(sym_cmd->symbol_offset() + width);
    }

    if (sym_cmd->strings_offset() > from_offset) {
      sym_cmd->strings_offset(sym_cmd->strings_offset() + width);
    }

    for (std::unique_ptr<Symbol>& s : symbols_) {
      static constexpr size_t N_TYPE = 0x0e;
      if (static_cast<N_LIST_TYPES>(s->type() & N_TYPE) == N_LIST_TYPES::N_SECT) {
        uint64_t value = s->value();
        if (value > from_offset) {
          s->value(value + width);
        }
      }
    }
  }

   
   
  if (DataInCode* data_code_cmd = data_in_code()) {
    if (data_code_cmd->data_offset() > from_offset) {
      data_code_cmd->data_offset(data_code_cmd->data_offset() + width);
    }
  }


   
   
  if (CodeSignature* sig = code_signature()) {
    if (sig->data_offset() > from_offset) {
      sig->data_offset(sig->data_offset() + width);
    }
  }

  if (CodeSignatureDir* sig_dir = code_signature_dir()) {
    if (sig_dir->data_offset() > from_offset) {
      sig_dir->data_offset(sig_dir->data_offset() + width);
    }
  }

  if (SegmentSplitInfo* ssi = segment_split_info()) {
    if (ssi->data_offset() > from_offset) {
      ssi->data_offset(ssi->data_offset() + width);
    }
  }

   
   
  if (MainCommand* main_cmd = main_command()) {
     if ((__text_base_addr + main_cmd->entrypoint()) > virtual_address) {
      main_cmd->entrypoint(main_cmd->entrypoint() + width);
    }
  }

   
   
  if (FunctionStarts* fs = function_starts()) {
    if (fs->data_offset() > from_offset) {
      fs->data_offset(fs->data_offset() + width);
    }
    for (uint64_t& address : fs->functions()) {
      if ((__text_base_addr + address) > virtual_address) {
        address += width;
      }
    }
  }

   
   
  if (DynamicSymbolCommand* dyn_cmd = dynamic_symbol_command()) {
    if (dyn_cmd->toc_offset() > from_offset) {
      dyn_cmd->toc_offset(dyn_cmd->toc_offset() + width);
    }

    if (dyn_cmd->module_table_offset() > from_offset) {
      dyn_cmd->module_table_offset(dyn_cmd->module_table_offset() + width);
    }

    if (dyn_cmd->external_reference_symbol_offset() > from_offset) {
      dyn_cmd->external_reference_symbol_offset(dyn_cmd->external_reference_symbol_offset() + width);
    }

    if (dyn_cmd->indirect_symbol_offset() > from_offset) {
      dyn_cmd->indirect_symbol_offset(dyn_cmd->indirect_symbol_offset() + width);
    }

    if (dyn_cmd->external_relocation_offset() > from_offset) {
      dyn_cmd->external_relocation_offset(dyn_cmd->external_relocation_offset() + width);
    }

    if (dyn_cmd->local_relocation_offset() > from_offset) {
      dyn_cmd->local_relocation_offset(dyn_cmd->local_relocation_offset() + width);
    }
  }

   
   
  if (DyldInfo* dyld = dyld_info()) {

     
    if (dyld->rebase().first > from_offset) {
      dyld->set_rebase_offset(dyld->rebase().first + width);
    }

    if (dyld->bind().first > from_offset) {
      dyld->set_bind_offset(dyld->bind().first + width);
    }

    if (dyld->weak_bind().first > from_offset) {
      dyld->set_weak_bind_offset(dyld->weak_bind().first + width);
    }

    if (dyld->lazy_bind().first > from_offset) {
      dyld->set_lazy_bind_offset(dyld->lazy_bind().first + width);
    }

    if (dyld->export_info().first > from_offset) {
      dyld->set_export_offset(dyld->export_info().first + width);
    }


     
     
     
    for (Relocation& reloc : relocations()) {
      if (reloc.address() > virtual_address) {
        if (is64_) {
          patch_relocation<uint64_t>(reloc,   virtual_address,   width);
        } else {
          patch_relocation<uint32_t>(reloc,   virtual_address,   width);
        }
        reloc.address(reloc.address() + width);
      }
    }

     
     
    for (ExportInfo& info : dyld->exports()) {
      if (info.address() > virtual_address) {
        info.address(info.address() + width);
      }
    }

     
     
    for (DyldBindingInfo& info : dyld->bindings()) {
      if (info.address() > virtual_address) {
        info.address(info.address() + width);
      }
    }
  }

  if (DyldChainedFixups* fixups = dyld_chained_fixups()) {
    fixups->data_offset(fixups->data_offset() + width);

     
    for (auto& entry : fixups->chained_starts_in_segments()) {
      for (auto& reloc : entry.segment.relocations()) {
        if (RelocationFixup::classof(reloc)) {
          auto& fixup = static_cast<RelocationFixup&>(reloc);
          if (fixup.offset() > from_offset) {
            fixup.offset(fixup.offset() + width);
          }
          if (fixup.target() > virtual_address) {
            fixup.target(fixup.target() + width);
          }
           
           
        }
      }
    }
    for (ChainedBindingInfo& bind : fixups->bindings()) {
      if (bind.offset() > from_offset) {
        bind.offset(bind.offset() + width);
      }
       
       
    }
  }

  if (DyldExportsTrie* exports = dyld_exports_trie()) {
    for (ExportInfo& info : exports->exports()) {
      if (virtual_address >= info.address()) {
        info.address(info.address() + width);
      }
    }
    if (exports->data_offset() > from_offset) {
      exports->data_offset(exports->data_offset() + width);
    }
  }

  if (LinkerOptHint* opt = linker_opt_hint()) {
    if (opt->data_offset() > from_offset) {
      opt->data_offset(opt->data_offset() + width);
    }
  }

  if (TwoLevelHints* two = two_level_hints()) {
    if (two->offset() > from_offset) {
      two->offset(two->offset() + width);
    }
  }

  for_commands<EncryptionInfo>([from_offset, width] (EncryptionInfo& enc) {
    if (enc.crypt_offset() > from_offset) {
      enc.crypt_offset(enc.crypt_offset() + width);
    }
  });

}