ASM access dynamic 2d array of c structures

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

Upvotes: 1

Views: 449

Answers (1)

Ped7g
Ped7g

Reputation: 16586

[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).

Upvotes: 1

Related Questions