1

Lest assume I have a struct like

struct color {
    int16_t r;
    int16_t g;
    int16_t b;
};

and also an array of points

struct color** colors = (struct color**) malloc(rows*sizeof(struct color*));
for (int i=0; i < rows; i++) {
    colors[i] = (struct color*) malloc(columns*sizeof(struct color));
    for (int j=0; j < columns; j++) {
        colors[i][j].r=0;
        colors[i][j].g=0;
        colors[i][j].b=0;
    }
}

I want to pass it to a function

void some_function(struct color** colors);

colors are now on rdi. I want to iterate over that array and add 1 to r, 2 to g and 3 to b, in assambler. I know that rdi is pointer to colors, [rdi] is pointer to colors[0], [rdi + 8] is pointer to colors[1], but how to access colors[1][2].r and colors[1][2].g

5
  • Dereference some more and apply the appropriate offset. You might understand it better if you rewrite the C code using pointers instead of indexing, then you can translate that directly to asm. (Don't forget that C pointer arithmetic scales automatically, but in asm you use byte offsets.) Commented Nov 29, 2016 at 16:12
  • 1
    There is no 2D array in your C code, noting which can point to one or represent one! A pointer is not an array. Commented Nov 29, 2016 at 16:22
  • OTOH an 2D array defined in C would end with "flat" memory model, so it's not interchangeable with his solution. But I agree, he has list of pointers to rows. Weird inefficient design. Commented Nov 29, 2016 at 16:27
  • have you considered using the -S option in gcc and see the asm code it generates? Commented Nov 29, 2016 at 16:31
  • If you care about performance, you probably need to redesign your array of pointers to rows into a single flat array. SSE2 / AVX2 will work better on one large buffer instead of separate arrays for each row. Commented Nov 29, 2016 at 17:17

1 Answer 1

1

[rdi] is pointer to colors[0], [rdi + 8] is pointer to colors[1], but how to access colors[1][2].r and colors[1][2].g

mov  rsi,[rdi + row*8]  ; rsi = pointer to single row data

mov  ax,[rsi + column*size_of_color + offset_of_r/g/b] ; value of r/g/b

From usage of rdi I guess you are working on 64b code.

So I guess the color structure is 8B aligned, so it's size is probably 24B and offsets of [r, g, b] will be probably [+0, +8, +16].

So to pick "b" value from [13][7] color the code would be:

mov rsi,[rdi + 13*8]
mov eax,7 * 24
mov ax,[rsi + eax + 16] ; ax = "colors[13][7].b"

Why am I using words like "guess" and "probably" toward structure size/offsets. Because that's C-compiler implementation and configuration dependent. I believe what you did want is to have the struct tightly memory packed (ie. size 6B and offsets [+0, +2, +4]).

Search for your compiler directive to achieve that, here is some pragma documentation for gcc and here attributes.

struct color {
    int16_t r;
    int16_t g;
    int16_t b;
    // if you are not short of memory, consider to bump the size to 8B
    // int16_t padding2B;   // *8 multiplier is available in ASM addressing
                            // like mov ax,[rsi + ebx*8 + 2]
} __attribute__ ((packed));
// gcc will now compile this as 6B structure
// Performance warning:
// also it will stop assume anything about alignment
// so the C compiled machine code can be less optimal
// than for "unpacked" struct

As you already realized, the 2D arrays are PITA in ASM, so why don't you go for flat memory structure? Especially with fixed columns size being some power of two the flat memory structure will be not just simpler to code for, but also it may receive considerable performance boost from having the rows in continuous memory. Your solution depends on malloc allocation strategy and with fragmented heap you may end with each row of colors in different cache-page, having several additional cache-misses (than flat structure).

struct color* colors = (struct color*) malloc(rows*columns*sizeof(struct color));
colors[row * columns + column].r = 0;

Then for asm you have to provide not only the pointer, but also the columns size (and I can't see how omitting rows is possible for anything a bit meaningful either).


Final note. Why don't you simply write some example in C accessing that structure, compile it, and check the generated assembler, to get idea how to access members of the structure (it may also use some trick how to do those *24/etc in fast way on your target platform).

Sign up to request clarification or add additional context in comments.

4 Comments

I guess the color structure is 8B aligned Why would it be? It's 2 byte aligned, and its size is 6.
@Jester because I'm confused from one other platform + having different defaults. Plus whenever I forget to explicitly specify any interface structure for my Assembly, it always backfires (but then again I never use them for struct consisting of the same type of variable). You are right, godbolt shows it's 6B size and 2B alignment by default.
won't struct color* colors = (struct color*) malloc(rowscolumnssizeof(struct color)); colors[row * columns + column].r = 0; produce 1d array? can I access it in c like colors[i][j]?
@MichałPiotrStankiewicz no, you can't, you have to access it by 1D index [row * colums + column] (or any other mapping function, but for performance you want to access rather element by element, not jumping too much around). Why do you want two [][]? If it is real 2D C++ array, it will compile into 1D flat memory anyway. Your list of pointers can't do that.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.