📄 packer.cpp
字号:
//patchPackHeader(p, lsize); ph.putPackHeader(p); }#endif}/*************************************************************************// Try compression with several methods and filters, choose the best/ or first working one. Needs buildLoader().//// Required inputs:// this->ph// ulen// parm_ft// clevel// addvalue// buf_len (optional)//// - updates this->ph// - updates *ft// - i_ptr[] is restored to the original unfiltered version// - o_ptr[] contains the best compressed version//// filter_strategy:// n: try the first N filters, use best one// -1: try all filters, use first working one// -2: try only the opt->filter filter// -3: use no filter at all//// This has been prepared for generalization into class Packer so that// opt->all_methods and/or opt->all_filters are available for all// executable formats.//// It will replace the tryFilters() / compress() call sequence.//// 2006-02-15: hdr_buf and hdr_u_len are default empty input "header" array// to fix a 2-pass problem with Elf headers. As of today there can be// only one decompression method per executable output file, and that method// is the one that gives best compression for .text and loader. However,// the Elf headers precede .text in the output file, and are written first.// "--brute" compression often compressed the Elf headers using nrv2b// but the .text (and loader) with nrv2e. This often resulted in SIGSEGV// during decompression.// The workaround is for hdr_buf and hdr_u_len to describe the Elf headers// (typically less than 512 bytes) when .text is passed in, and include// them in the calculation of shortest output. Then the result// this->ph.method will say which [single] method to use for everything.// The Elf headers are never filtered. They are short enough (< 512 bytes)// that compressing them more than once per method (once here when choosing,// once again just before writing [because compressWithFilters discards])// is OK because of the simplicity of not having two output arrays.**************************************************************************/static int prepareMethods(int *methods, int ph_method, const int *all_methods){ int nmethods = 0; if (!opt->all_methods || all_methods == NULL) { methods[nmethods++] = ph_method; return nmethods; } for (int mm = 0; all_methods[mm] != M_END; ++mm) { int method = all_methods[mm]; if (method == M_ULTRA_BRUTE && !opt->ultra_brute) break; if (method == M_SKIP || method == M_ULTRA_BRUTE) continue; if (opt->all_methods && !opt->all_methods_use_lzma && M_IS_LZMA(method)) continue; // use this method assert(Packer::isValidCompressionMethod(method)); methods[nmethods++] = method; } return nmethods;}static int prepareFilters(int *filters, int &filter_strategy, const int *all_filters){ int nfilters = 0; // setup filter filter_strategy if (filter_strategy == 0) { if (opt->all_filters) // choose best from all available filters filter_strategy = INT_MAX; else if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters)) // try opt->filter filter_strategy = -2; else // try the first working filter filter_strategy = -1; } assert(filter_strategy != 0); if (filter_strategy == -3) goto done; if (filter_strategy == -2) { if (opt->filter >= 0 && Filter::isValidFilter(opt->filter, all_filters)) { filters[nfilters++] = opt->filter; goto done; } filter_strategy = -1; } assert(filter_strategy >= -1); while (all_filters && *all_filters != FT_END) { int filter_id = *all_filters++; if (filter_id == FT_ULTRA_BRUTE && !opt->ultra_brute) break; if (filter_id == FT_SKIP || filter_id == FT_ULTRA_BRUTE) continue; if (filter_id == 0) continue; // use this filter assert(Filter::isValidFilter(filter_id)); filters[nfilters++] = filter_id; if (filter_strategy >= 0 && nfilters >= filter_strategy) break; }done: // filter_strategy now only means "stop after first successful filter" filter_strategy = (filter_strategy < 0) ? -1 : 0; // make sure that we have a "no filter" fallback for (int i = 0; i < nfilters; i++) if (filters[i] == 0) return nfilters; filters[nfilters++] = 0; return nfilters;}void Packer::compressWithFilters(upx_bytep i_ptr, unsigned i_len, upx_bytep o_ptr, upx_bytep f_ptr, unsigned f_len, const upx_bytep hdr_ptr, unsigned hdr_len, Filter *parm_ft, const unsigned overlap_range, const upx_compress_config_t *cconf, int filter_strategy){ parm_ft->buf_len = f_len; // struct copies const PackHeader orig_ph = this->ph; PackHeader best_ph = this->ph; const Filter orig_ft = *parm_ft; Filter best_ft = *parm_ft; // best_ph.c_len = i_len; best_ph.overlap_overhead = 0; unsigned best_ph_lsize = 0; unsigned best_hdr_c_len = 0; // preconditions assert(orig_ph.filter == 0); assert(orig_ft.id == 0); // prepare methods and filters int methods[256]; int nmethods = prepareMethods(methods, ph.method, getCompressionMethods(M_ALL, ph.level)); assert(nmethods > 0); assert(nmethods < 256); int filters[256]; int nfilters = prepareFilters(filters, filter_strategy, getFilters()); assert(nfilters > 0); assert(nfilters < 256);#if 0 printf("compressWithFilters: m(%d):", nmethods); for (int i = 0; i < nmethods; i++) printf(" %d", methods[i]); printf(" f(%d):", nfilters); for (int i = 0; i < nfilters; i++) printf(" %d", filters[i]); printf("\n");#endif // update total_passes; previous (ui_total_passes > 0) means incremental if (uip->ui_total_passes > 0) uip->ui_total_passes -= 1; if (filter_strategy < 0) uip->ui_total_passes += nmethods; else uip->ui_total_passes += nfilters * nmethods; // Working buffer for compressed data. Don't waste memory and allocate as needed. upx_bytep o_tmp = o_ptr; MemBuffer o_tmp_buf; // compress using all methods/filters int nfilters_success_total = 0; for (int mm = 0; mm < nmethods; mm++) // for all methods { assert(isValidCompressionMethod(methods[mm])); unsigned hdr_c_len = 0; if (hdr_ptr != NULL && hdr_len) { if (nfilters_success_total != 0 && o_tmp == o_ptr) { // do not overwrite o_ptr o_tmp_buf.allocForCompression(UPX_MAX(hdr_len, i_len)); o_tmp = o_tmp_buf; } int r = upx_compress(hdr_ptr, hdr_len, o_tmp, &hdr_c_len, NULL, methods[mm], 10, NULL, NULL); if (r != UPX_E_OK) throwInternalError("header compression failed"); if (hdr_c_len >= hdr_len) throwInternalError("header compression size increase"); } int nfilters_success_mm = 0; for (int ff = 0; ff < nfilters; ff++) // for all filters { assert(isValidFilter(filters[ff])); // get fresh packheader ph = orig_ph; ph.method = methods[mm]; ph.filter = filters[ff]; ph.overlap_overhead = 0; // get fresh filter Filter ft = orig_ft; ft.init(ph.filter, orig_ft.addvalue); // filter optimizeFilter(&ft, f_ptr, f_len); bool success = ft.filter(f_ptr, f_len); if (ft.id != 0 && ft.calls == 0) { // filter did not do anything - no need to call ft.unfilter() success = false; } if (!success) { // filter failed or was useless if (filter_strategy >= 0) { // adjust ui passes if (uip->ui_pass >= 0) uip->ui_pass++; } continue; } // filter success#if 0 printf("filter: id 0x%02x size %6d, calls %5d/%5d/%3d/%5d/%5d, cto 0x%02x\n", ft.id, ft.buf_len, ft.calls, ft.noncalls, ft.wrongcalls, ft.firstcall, ft.lastcall, ft.cto);#endif if (nfilters_success_total != 0 && o_tmp == o_ptr) { o_tmp_buf.allocForCompression(i_len); o_tmp = o_tmp_buf; } nfilters_success_total++; nfilters_success_mm++; ph.filter_cto = ft.cto; ph.n_mru = ft.n_mru; // compress if (compress(i_ptr, i_len, o_tmp, cconf)) { unsigned lsize = 0; // findOverlapOperhead() might be slow; omit if already too big. if (ph.c_len + lsize + hdr_c_len <= best_ph.c_len + best_ph_lsize + best_hdr_c_len) { // get results ph.overlap_overhead = findOverlapOverhead(o_tmp, i_ptr, overlap_range); buildLoader(&ft); lsize = getLoaderSize(); assert(lsize > 0); }#if 0 printf("\n%2d %02x: %d +%4d +%3d = %d (best: %d +%4d +%3d = %d)\n", ph.method, ph.filter, ph.c_len, lsize, hdr_c_len, ph.c_len + lsize + hdr_c_len, best_ph.c_len, best_ph_lsize, best_hdr_c_len, best_ph.c_len + best_ph_lsize + best_hdr_c_len);#endif bool update = false; if (ph.c_len + lsize + hdr_c_len < best_ph.c_len + best_ph_lsize + best_hdr_c_len) update = true; else if (ph.c_len + lsize + hdr_c_len == best_ph.c_len + best_ph_lsize + best_hdr_c_len) { // prefer smaller loaders if (lsize + hdr_c_len < best_ph_lsize + best_hdr_c_len) update = true; else if (lsize + hdr_c_len == best_ph_lsize + best_hdr_c_len) { // prefer less overlap_overhead if (ph.overlap_overhead < best_ph.overlap_overhead) update = true; } } if (update) { assert((int)ph.overlap_overhead > 0); // update o_ptr[] with best version if (o_tmp != o_ptr) memcpy(o_ptr, o_tmp, ph.c_len); // save compression results best_ph = ph; best_ph_lsize = lsize; best_hdr_c_len = hdr_c_len; best_ft = ft; } } // restore - unfilter with verify ft.unfilter(f_ptr, f_len, true); if (filter_strategy < 0) break; } assert(nfilters_success_mm > 0); } // postconditions 1) assert(nfilters_success_total > 0); assert(best_ph.u_len == orig_ph.u_len); assert(best_ph.filter == best_ft.id); assert(best_ph.filter_cto == best_ft.cto); // FIXME assert(best_ph.n_mru == best_ft.n_mru); // copy back results this->ph = best_ph; *parm_ft = best_ft; // finally check compression ratio if (best_ph.c_len + best_ph_lsize >= best_ph.u_len) throwNotCompressible(); if (!checkCompressionRatio(best_ph.u_len, best_ph.c_len)) throwNotCompressible(); // postconditions 2) assert(best_ph.overlap_overhead > 0); // convenience buildLoader(&best_ft);}/*************************************************************************//**************************************************************************/void Packer::compressWithFilters(Filter *ft, const unsigned overlap_range, const upx_compress_config_t *cconf, int filter_strategy){ compressWithFilters(ft, overlap_range, cconf, filter_strategy, 0, 0, 0, NULL, 0);}void Packer::compressWithFilters(Filter *ft, const unsigned overlap_range, const upx_compress_config_t *cconf, int filter_strategy, unsigned filter_off, unsigned ibuf_off, unsigned obuf_off, const upx_bytep hdr_ptr, unsigned hdr_len){ ibuf.checkState(); obuf.checkState(); upx_bytep i_ptr = ibuf + ibuf_off; unsigned i_len = ph.u_len; upx_bytep o_ptr = obuf + obuf_off; upx_bytep f_ptr = ibuf + filter_off; unsigned f_len = ft->buf_len ? ft->buf_len : i_len; assert(f_ptr + f_len <= i_ptr + i_len); compressWithFilters(i_ptr, i_len, o_ptr, f_ptr, f_len, hdr_ptr, hdr_len, ft, overlap_range, cconf, filter_strategy); ibuf.checkState(); obuf.checkState();}/*vi:ts=4:et:nowrap*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -