Hand inline assembly in gcc

I have some problems with some inline build code. I know what to do, but I skip the how!

I have this checksum function that "almost" works:

static unsigned long cksum_unroll( unsigned short **w, int *mlen) { int len; unsigned short *w0; unsigned long sum=0; len = *mlen; w0 = *w; while( len >= 8) { asm volatile ( "ldmia %[w0]!, {v1, v2}\n\t" "adds %[sum], %[sum], v1\n\t" "adcs %[sum], %[sum], v2\n\t" "adcs %[sum], %[sum], #0" : [sum] "+r" (sum) : [w0] "r" (w0) ); len -= 8; } *mlen = len; *w = w0; return (sum); } 

My problem, I believe, is on the line " : [sum]" + r "(sum): [w0]" r "(w0) " On the first assembly line, w0 processes ldmia correctly (when the line is executed, the data is in r4, r5 and w0 increase). But the increment of the value of w0 is not saved somewhere and when the code loop, the original value of w0 is loaded again (see Assembler code below). I assume that I should store the value of w0 in the line :: [sum] "+ r" (sum): [w0] "r" (w0) ", but I do not know how ...

Here is the disassembly code of the built-in part of the function assembly:

Note that:

 len is stored at r11, #-16 w0 is stored at r11, #-20 sum is stored at r11, #-24 

The following code has been compiled:

 asm volatile ( "ldmia %[w0]!, {v1, v2}\n\t" "adds %[sum], %[sum], v1\n\t" "adcs %[sum], %[sum], v2\n\t" "adcs %[sum], %[sum], #0" : [sum] "+r" (sum) : [w0] "r" (w0) ); len -= 8; 

Generate:

 00031910: ldr r3, [r11, #-20] 00031914: ldr r2, [r11, #-24] 00031918: mov r4, r2 0003191c: ldm r3!, {r4, r5} 00031920: adds r4, r4, r4 00031924: adcs r4, r4, r5 00031928: adcs r4, r4, #0 0003192c: str r4, [r11, #-24] 00031930: ldr r3, [r11, #-16] 00031934: sub r3, r3, #8 00031938: str r3, [r11, #-16] 

As you can see, I would like to add something like "str r3, [r11, # -20]" between lines 31928 and 3192c, because when the program loop to line 31910, r3 loads with the initial value r3 ...

I think this isn’t easy for a community build specialist!

By the way, I'm working on an ARM7TDMI processor (but this may not be relevant for this issue ...)

Thanks in advance!

EDIT:

To test my idea, I tested the following:

 asm volatile ( "ldmia %[w0]!, {v1, v2}\n\t" "adds %[sum], %[sum], v1\n\t" "adcs %[sum], %[sum], v2\n\t" "adcs %[sum], %[sum], #0\n\t" "str %[w0], [r11, #-20]" : [sum] "+r" (sum) : [w0] "r" (w0) ); 

And it works. This may be a solution, but what am I using to replace "r11, # 20", which is likely to change if I change the function?

+4
source share
1 answer

The problem seems to be that you are specifying w0 as an INPUT operand, when in fact it should be an OUTPUT read-write operand, such as sum . In addition, you need to indicate that these are clobbers v1 and v2, since you are using these registers (otherwise gcc might put some other var in these registers and wait for them to be saved.)

So you should have:

 asm volatile ( "ldmia %[w0]!, {v1, v2}\n\t" "adds %[sum], %[sum], v1\n\t" "adcs %[sum], %[sum], v2\n\t" "adcs %[sum], %[sum], #0" : [sum] "+r" (sum) , [w0] "+r" (w0) : : "v1", "v2" ); 

that is, two read and write I / O operands, not only input operands and two registration buffers

+4
source

Source: https://habr.com/ru/post/1396730/


All Articles