[patch/peflags] Allow to change PE header stack and heap sizes
Charles Wilson
cygwin@cwilson.fastmail.fm
Wed Aug 10 03:22:00 GMT 2011
On 8/9/2011 8:19 AM, Corinna Vinschen wrote:
> Hi Chuck,
>
> here's the change to peflags which allows to change the stack size and
> other stuff.
Cool, thanks.
> Here's the patch. Builds and works fine on Cygwin and x86_64-mingw64.
Needs one small tweak for MSYS, but works fine after that. Sadly,
__builtin_offset was not added until gcc-4.0:
#if defined(__GNUC__) && (__GNUC__ >= 4)
> +sizeof_values_t sizeof_vals[5] = {
> + { 0, "stack reserve size ", "bytes", 0, FALSE,
> + __builtin_offsetof (IMAGE_NT_HEADERS64, OptionalHeader.SizeOfStackReserve),
> + __builtin_offsetof (IMAGE_NT_HEADERS32, OptionalHeader.SizeOfStackReserve),
> + },
> + { 0, "stack commit size ", "bytes", 0, FALSE,
> + __builtin_offsetof (IMAGE_NT_HEADERS64, OptionalHeader.SizeOfStackCommit),
> + __builtin_offsetof (IMAGE_NT_HEADERS32, OptionalHeader.SizeOfStackCommit),
> + },
> + { 0, "Win32 heap reserve size ", "bytes", 0, FALSE,
> + __builtin_offsetof (IMAGE_NT_HEADERS64, OptionalHeader.SizeOfHeapReserve),
> + __builtin_offsetof (IMAGE_NT_HEADERS32, OptionalHeader.SizeOfHeapReserve),
> + },
> + { 0, "Win32 heap commit size ", "bytes", 0, FALSE,
> + __builtin_offsetof (IMAGE_NT_HEADERS64, OptionalHeader.SizeOfHeapCommit),
> + __builtin_offsetof (IMAGE_NT_HEADERS32, OptionalHeader.SizeOfHeapCommit),
> + },
> + { 0, "initial Cygwin heap size", "MB", 0, TRUE,
> + __builtin_offsetof (IMAGE_NT_HEADERS64, OptionalHeader.LoaderFlags),
> + __builtin_offsetof (IMAGE_NT_HEADERS32, OptionalHeader.LoaderFlags),
> + }
> +};
#else
... repeat above, using the offsetof () macro. Can't #define
my_offsetof in terms of offsetof() or __builtin_offsetof() because that
requires double macro subst (*)
#endif
(*) Unless you do something like this:
#if defined(__GNUC__) && (__GNUC__ < 4)
# define my_offsetof(st, m) \
((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
#else
# define my_offsetof(st, m) __builtin_offsetof(st, m)
#endif
...with proper care for safe type punning(?), etc etc... I think it's
simpler just to duplicate the five struct member initializations.
> new_coff_characteristics = old_coff_characteristics;
> new_coff_characteristics |= coff_characteristics_set;
> @@ -349,20 +426,47 @@ do_mark (const char *pathname)
> if (verbose
> || !mark_any
> || coff_characteristics_show
> - || pe_characteristics_show)
> + || pe_characteristics_show
> + || handle_any_sizeof != DONT_HANDLE)
I'm a little confused by this logic (above and below). You basically have:
if (a || !b || !c)
{
if (a || (!b && c))
where
a = verbose || coff_characteristics_show || pe_characteristics_show
b = mark_any
c = handle_any_sizeof == DONT_HANDLE
Is that right?
[time passes]
Oh, wait, I get it. If the user only specified "display" stack/heap
data, then you don't want to gratuitously show the pe/coff flags. And
vice versa: if the use only specified "display" pe/coff flags, you don't
want to gratuitously show stack/heap data.
But if she specified "display" (at least one pe/coff) and (at least one
stack/heap) -- then you want to display both types.
> + if (verbose
> + || (!mark_any && handle_any_sizeof == DONT_HANDLE)
> + || coff_characteristics_show || pe_characteristics_show)
> + {
> + display_flags ("coff", coff_symbolic_flags,
> + coff_characteristics_show ?:
> + verbose ? old_coff_characteristics : 0,
> + old_coff_characteristics,
> + new_coff_characteristics);
> + display_flags ("pe", pe_symbolic_flags,
> + pe_characteristics_show ?:
> + verbose ? old_pe_characteristics : 0,
> + old_pe_characteristics,
> + new_pe_characteristics);
> + puts ("");
> + printed_characteristic = TRUE;
> + }
>
> +
> +static void
> handle_pe_flag_option (const char *option_name,
> const char *option_arg,
> WORD flag_value)
> @@ -537,6 +672,16 @@ parse_args (int argc, char *argv[])
> c = getopt_long (argc, argv, short_options, long_options, &option_index);
> if (c == -1)
> break;
> + /* Workaround the problem that option_index is not valid if the user
> + specified a short option. */
> + if (option_index == 0 && c != 'd')
This threw me for a loop, for a minute. It depends on the fact that the
0th entry in long_options has short option value 'd'. Maybe this would
be better (especially if we ever re-order long_options)?
> + if (option_index == 0 && c != long_options[0].val)
> + {
> + for (option_index = 1;
> + long_options[option_index].name;
> + ++option_index)
> + if (long_options[option_index].val == c)
> + break;
> + }
>
> +void
> +get_and_set_size (const pe_file *pep, sizeof_values_t *val)
> +{
> + if (val->handle == DO_READ)
> + {
> + if (!pep->is_64bit)
> + val->value = *pulong (pep->ntheader32, val->offset32);
> + else if (val->is_ulong)
> + val->value = *pulong (pep->ntheader64, val->offset64);
> + else
> + val->value = *pulonglong (pep->ntheader64, val->offset64);
> + }
> + else if (val->handle == DO_WRITE)
> + {
> + if (!pep->is_64bit)
> + *pulong (pep->ntheader32, val->offset32) = val->value;
is there an issue here, with this assignment:
*ULONG = (ULONGLONG) value; ?
> + else if (val->is_ulong)
> + *pulong (pep->ntheader64, val->offset64) = val->value;
ditto here?
I'm just wondering if, to avoid warnings, we need to explicitly cast the
RHS to ULONG.
DO_READ doesn't have the same issue, because we're assigning a smaller
type to a larger storage, in that case; it just gets sign-extended.
> + else
> + *pulonglong (pep->ntheader64, val->offset64) = val->value;
> + }
> +}
--
Chuck
More information about the Cygwin-apps
mailing list