I have a int64 variable with a random value. I want to modify the lower 32 bits of it to 0xf0ffffff
The variable is rdx register but i want to edit edx value
ContextRecord->Rdx = 0xf0ffffff; // Not correct
I have a int64 variable with a random value. I want to modify the lower 32 bits of it to 0xf0ffffff
The variable is rdx register but i want to edit edx value
ContextRecord->Rdx = 0xf0ffffff; // Not correct
Read the whole value, mask out the lower bits and bitwise-OR it with the 32 bit value you want there:
#include <stdint.h>
void f(int64_t *X)
{
*X = (*X & ~(uint64_t)0xffffffff) //mask out the lower 32 bits
| 0xf0ffffff; //<value to set into the lower 32 bits
}
gcc
and clang
on little-endian architectures optimize it to a direct mov
into the lower 32 bits, i.e., the equivalent of:
#include <string.h>
//only works on little-endian architectures
void g(int64_t *X)
{
uint32_t y = 0xf0ffffff;
memcpy(X,&y,sizeof(y));
}
If you were doing this in straight assembly, you could just
mov edx 0xf0ffffff
as edx is an alias to the lower 32 bits of rdx. Since it seems you want to do it in C/C++, you need to adjust Rdx directly. Something like -
CONTEXT ctx;
GetThreadContext(hYourThread,&ctx); // check return value, handle errors
DWORD64 newRdx = ctx->Rdx;
newRdx &= 0xfffffffff0ffffff;
newRdx |= 0xf0ffffff;
The variable is rdx register but i want to edit edx value
I assume that this means that you want to keep the most significant 32-bits intact and only change the least significant 32-bits.
Assuming that the data member ContextRecord->Rdx
contains the original value and you want to write back the edited value to this data member, then you could use the following code:
auto temp = ContextRecord->Rdx;
temp &= 0xffffffff00000000; //set least significant 32-bits to 00000000
temp |= 0x00000000f0ffffff; //set least significant 32-bits to f0ffffff
ContextRecord->Rdx = temp;
Of course, these lines could be combined into a single line, like this:
ContextRecord->Rdx = ContextRecord->Rdx & 0xffffffff00000000 | 0x00000000f0ffffff;
Please note that this line only works because &
has a higher operator precedence than |
, otherwise additional parentheses would be required.
Need to write some unit tests as I haven't tested this for all types in all architectures but a template something like below maybe what you are looking for
#include <cassert>
#include <cstdint>
#include <iostream>
#include <limits>
#include <type_traits>
template <const int bits, class /* This is where I wish concepts were completed */ T>
constexpr T modifyBits(T highPart, T lowPart)
{
// std::numeric_limits<T>::max() will fail on bits == 0 or float types
static_assert(bits != 0);
static_assert(std::is_signed<T>::value || std::is_unsigned<T>::value);
constexpr T almostallSetMask = std::numeric_limits<T>::max();
constexpr T bitmaskRaw = almostallSetMask >> (bits - (std::is_signed<T>::value ? 1 : 0));
constexpr T bitmaskHigh = bitmaskRaw << bits;
constexpr T bitmaskLow = ~bitmaskHigh;
return (highPart & bitmaskHigh) | (lowPart & bitmaskLow);
}
int main()
{
// Example usage
constexpr int64_t value = 0xFFFFFFFF00000000LL;
constexpr int64_t updated = modifyBits<32, int64_t>(value, 0xFFFFFFFFLL);
static_assert(updated == -1LL); // has to pass
return 0;
}
As you can see I can use static assert and const_expr in a generic way like this. The motto is: Write it once use everywhere. Be warned though, without unit tests this is not complete at all. Feel free to copy this if you like, you can consider it as CC0 or public domain,
A slightly more cheaty and less recommendable way to do it would be type punning:
struct splitBytes {
__int32 lower, upper;
}
void changeLower(__int64* num) {
splitBytes* pun = (splitBytes*)*num;
pun->lower = 0xf0ffffff;
}
note: type punning is pretty risky, so you really shouldn't use unless it's unavoidable. It basically lets you treat a block of memory as if it were of a different type. Really, don't use it if you can avoid it. I'm just putting it out there.