3

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
Shahriyar
  • 1,251
  • 3
  • 20
  • 36
  • 3
    You need to read the old full 64-bit value. Mask out the lower 32 bits and add in your special value in the low 32 bits. – Some programmer dude Mar 08 '20 at 11:18
  • 3
    `and` the original with `0xffffffff00000000` then `or` with `0xf0ffffff` – David C. Rankin Mar 08 '20 at 11:28
  • possible duplicate of [How to set first three bytes of integer? in C++](https://stackoverflow.com/q/34357968/995714), [How do you set only certain bits of a byte without affecting the rest?](https://stackoverflow.com/q/4439078/995714), [replace byte in 32 bit number](https://stackoverflow.com/q/10132906/995714) – phuclv Mar 08 '20 at 12:26
  • Does this answer your question? [How to set first three bytes of integer? in C++](https://stackoverflow.com/questions/34357968/how-to-set-first-three-bytes-of-integer-in-c) – phuclv Mar 08 '20 at 12:27

5 Answers5

2

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;
Ofek Shilon
  • 11,558
  • 3
  • 52
  • 86
2

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.

Andreas Wenzel
  • 4,984
  • 2
  • 7
  • 24
1

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));
}

https://gcc.godbolt.org/z/nkMSvw

PSkocik
  • 52,186
  • 6
  • 79
  • 122
1

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,

Abdurrahim
  • 1,832
  • 1
  • 15
  • 15
0

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.

lenerdv
  • 125
  • 12
  • 1
    If I am not mistaken, the posted code violates the [strict aliasing rule](https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule), which can at least theoretically cause [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). – Andreas Wenzel Mar 08 '20 at 15:22
  • @AndreasWenzel short answer: yup. long answer: it depends (you weren't expecting that, right?). basically, problems can arise if either: the punned type and the punning type have different sizes; at least one of the punned types is a class; arithmetic is done with the pointers. this is why it should _almost_ never be done. – lenerdv Mar 08 '20 at 16:57
  • What you say may currently be true. However, compiler optimizations are becoming more and more aggressive. Whenever the compiler encounters code which causes undefined behavior, it can treat that code as unreachable, which means the compiler can simply optimize it away. See [this very interesting answer by Microsoft Blogger Raymond Chen](https://stackoverflow.com/a/9452284) for more information on that topic. – Andreas Wenzel Mar 10 '20 at 23:17
  • @AndreasWenzel oh, I was completely unaware of that. The answer is informative and all round well worth reading. thanks! – lenerdv Mar 11 '20 at 08:10