5

I am trying to understand xmr-stak miner program. I have understood most of it but having hard time visualizing some pointer manipulation in below code. Its been over 10 years for me to go through any CPP program, any help is apprenticed.

So the question is, what is being assigned to following some of the pointer variables like piHashVal, or piNonce. I have commented my assumptions on each line, but not sure if that is correct. Any explanation with example is very much helpful.

void minethd::work_main() { uint64_t* piHashVal; uint32_t* piNonce;

//assign pointer of bResult + 24 bits
piHashVal = (uint64_t*)(result.bResult + 24); 

//assign pointer of bWorkBlob + 39 bit - piNonce is at 39th bit of blob provided by pool.
piNonce = (uint32_t*)(oWork.bWorkBlob + 39); 


        //value at piNonce is increamented by 1 or address of piNonce is increamented by 1?
        *piNonce = ++result.iNonce;

        //value at piHashVal is compared with target
        if (*piHashVal < oWork.iTarget) {
            executor::inst()->push_event(ex_event(result, oWork.iPoolId));
        }

}

2 Answers 2

7

piHashVal = (uint64_t*)(result.bResult + 24);

result.bResult is a pointer to some data structure, it's storing the memory address at which the structure begins. We're not interested in the beginning of that data blob, but want to access some 64-bits starting at offset 24. The above expression increments the address by offset 24 and casts the result to pointer to uint64_t. This means that the expression *piHashVal will return value of those 64-bits, interpreted as unsigned int. Note about the offset, how much bytes it offsets will depend on the type of pointer result.bResult. See also: Pointer Arithmetic for Structs

Example when offseting pointers of different types

piNonce = (uint32_t*)(oWork.bWorkBlob + 39);

This does similar, only we're taking the 32-bits starting at offset 39 from beginning of oWork.bWorkBlob data structure.

*piNonce = ++result.iNonce;

Increment the result.iNonce by 1, and assign the resulting value to *piNonce which is the data stored at memory address piNonce. Note that both variables result.iNonce and *piNonce are changed here. By doing this, we surgically changed some 32-bits in the oWork.BworkBlob data structure since the piNonce points to a part of it and we accessed that part directly with *piNonce.

if (*piHashVal < oWork.iTarget) {
    executor::inst()->push_event(ex_event(result, oWork.iPoolId));
}

So here we compare those 64-bits from the start with the target. We're accessing the value *piHashVal stored at memory location piHashVal.

Appendix - Pointer Example

#include <stdio.h>
#define ARLEN 2

int main(void)
{
    unsigned long a[ARLEN];
    unsigned long *b;
    unsigned char *c;
    
    for(int i=0; i<ARLEN; ++i)
        a[i] = 100 + i*100;

    b = &a[0];
    /* Note that b = a is equivalent to the above expression, because when a is
     * declared as an array it becomes a pointer but the memory block for the array
     * is allocated at declaration as well. The [] is also known as offset operator.
     * and can be applied to any pointer.
     * After the above assignment, a[i] and b[i] will be equivalent.
    **/
    
    c = (char*) b;
    
    printf("Accessing using offset operator:\n");
    for(int i=0; i<ARLEN; ++i)
        printf("a[%d] = %lu = 0x%02X;\n",i,a[i],a[i]);
    
    printf("Accessing using dereference operator:\n");
    for(int i=0; i<ARLEN; ++i)
        printf("*(b+%d) = %lu = 0x%02X\n",i,*(b+i),*(b+i));
    
    printf("Reading individual bytes of the array using char pointer:\n");
    for(int i=0; i < (ARLEN*sizeof(long)/sizeof(char)); ++i)
        printf("*(c+%d) = %hhu = 0x%02X;\n",i,*(c+i),*(c+i));
    
    printf("Setting odd bytes to 0xFF:\n");
    for(int i=0; i < (ARLEN*sizeof(long)/sizeof(char)); ++i)
    {
        if (i%2==1)
            *(c+i)=0xFF;
        printf("*(c+%d) = %hhu = 0x%02X;\n",i,*(c+i),*(c+i));
    }
    
    printf("Printing the modified long array:\n");
    for(int i=0; i < ARLEN; ++i)
    {
        printf("a[%d] = %lu = 0x%02X;\n",i,a[i],a[i]);
    }
    return 0;
}

Program output (compiled on x86-64 system):

Accessing using offset operator:
a[0] = 100 = 0x64;
a[1] = 200 = 0xC8;
Accessing using dereference operator:
*(b+0) = 100 = 0x64
*(b+1) = 200 = 0xC8
Reading individual bytes of the array using char pointer:
*(c+0) = 100 = 0x64;
*(c+1) = 0 = 0x00;
*(c+2) = 0 = 0x00;
*(c+3) = 0 = 0x00;
*(c+4) = 0 = 0x00;
*(c+5) = 0 = 0x00;
*(c+6) = 0 = 0x00;
*(c+7) = 0 = 0x00;
*(c+8) = 200 = 0xC8;
*(c+9) = 0 = 0x00;
*(c+10) = 0 = 0x00;
*(c+11) = 0 = 0x00;
*(c+12) = 0 = 0x00;
*(c+13) = 0 = 0x00;
*(c+14) = 0 = 0x00;
*(c+15) = 0 = 0x00;
Setting odd bytes to 0xFF:
*(c+0) = 100 = 0x64;
*(c+1) = 255 = 0xFF;
*(c+2) = 0 = 0x00;
*(c+3) = 255 = 0xFF;
*(c+4) = 0 = 0x00;
*(c+5) = 255 = 0xFF;
*(c+6) = 0 = 0x00;
*(c+7) = 255 = 0xFF;
*(c+8) = 200 = 0xC8;
*(c+9) = 255 = 0xFF;
*(c+10) = 0 = 0x00;
*(c+11) = 255 = 0xFF;
*(c+12) = 0 = 0x00;
*(c+13) = 255 = 0xFF;
*(c+14) = 0 = 0x00;
*(c+15) = 255 = 0xFF;
Printing the modified long array:
a[0] = 18374966859414962020 = 0xFF00FF64;
a[1] = 18374966859414962120 = 0xFF00FFC8;
1
  • Thank you very much, that helped a lot. I always had hard time visualizing pointer.
    – Rahul
    Commented Nov 6, 2017 at 21:32
2

idk anything about monero source code but:

first thing is that if you mean byte 0 as first then say byte 7 is 8th ,not 7th .

second is that when you deal with structures it has alignment.And my bet is that it's not 1 here. It's not so complex stuff if use it in structure you know.But it's complex to understand abstract.

to tell long story short: if you need say offset of the 4th member of structure it is:

count of padding bytes of second and third members(means second_count + third_count) + its sizes + size of first member + 4th_member_padding_bytes_count.

about padding bytes: padding = (align - (offset & (align - 1))) & (align - 1)

where 'offset' means offset of byte next to last_occupied_byte(previous members are deployed already,current is not ,yet). and you'll have more fun counting it 'from screen' then out of seekin bugs after above stuff.

hard-core post about that: https://en.wikipedia.org/wiki/Data_structure_alignment

(unexpected for wikipedia)

and... with bits and addresses on scene in same time

pointer=smth+4;

means smth + 4 bytes(coz of unsigned char* pointers - only thing that gives direct bytes order needed for memory i/o) ,not bits.

there is some info about pointer + smth and how it looks in real code. https://www.cs.uaf.edu/courses/cs301/2014-fall/notes/pointer-arithmetic/

in table's last row QWORD[..] is just differently worded unsigned long long* . It's size of memory block followed by its address.

so with

long* a=some_address;
long* b = a+1;
long  c = *b;

we have: https://en.wikipedia.org/wiki/Addressing_mode#Base_plus_index

which also means specific assembly instruction set.

with unsigned char* we have https://en.wikipedia.org/wiki/Addressing_mode#Base_plus_offset.2C_and_variations

15
  • It's not always a byte, though. Isn't it +4 sizeof(type)?
    – JollyMort
    Commented Nov 7, 2017 at 21:28
  • maybe yeah but it's not bits
    – Alex
    Commented Nov 7, 2017 at 21:35
  • yup, that's for sure
    – JollyMort
    Commented Nov 7, 2017 at 21:38
  • Yup, I have putting multiple printf(s) to see what is going on there and yes, +4, +24 or +39 are not bits nor bytes, they are just incrementing pointer address by 1. in my example, bworkBlob is array of uint8 so +39 pushes bWorkBlob[39th ], since 0 to 38th are 39 addresses. Thanks guys!!
    – Rahul
    Commented Nov 7, 2017 at 21:50
  • 'incrementing pointer address by 1' means exactly bytes. (unsigned char*)some_pointer + 1 .Yeah arrays (within or outside of structures) has no alignment inside it ,it works coz of this.
    – Alex
    Commented Nov 7, 2017 at 23:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.