Home > Back-end >  ARM 7 Assembly - ADC with immediate 0
ARM 7 Assembly - ADC with immediate 0

Time:03-03

I have written a little c function on godbolt.org and I am curious about a certain line inside the assembly. Here is the function:

unsigned long long foo(uint64_t a, uint8_t b){
    // unsigned long long fifteen = 15 * b;
    // unsigned long long result  = a   fifteen;
    // unsigned long long resultfinal = result / 2;
    // return resultfinal;

    return (a (15*b)) / 2;
}

The generated assembly:

rsb     r2, r2, r2, lsl #4
adds    r0, r2, r0
adc     r1, r1, #0
lsrs    r1, r1, #1
rrx     r0, r0

Now I dont understand why the line with the ADC instruction happens. It adds 0 to the high of the 64 bit number. Why does it do that?

Here is the link if you want to play yourself: Link to assembly

CodePudding user response:

The arm32 is only 32 bits. The value 'a' is 64bits. The instructions that you are seeing are to allow computations of sizes larger than 32bits.

rsb     r2, r2, r2, lsl #4   # 15*b -> b*16-b
adds    r0, r2, r0           # a (15*b) !LOW 32 bits! could carry.
adc     r1, r1, #0           # add a carry bit to the high portion
lsrs    r1, r1, #1           # divide high part by 2; (a (15*b))/2
rrx     r0, r0               # The opposite of add with carry flowing down.

Note: if you are confused by the adc instruction, then the rrx will also be confusing? It is a 'dual' of the addition/multiplication. For division you need to take care of underflow in the higher part and put it in the next lower value.


I think the important point is that you can 'carry' this logic to arbitrarily large values. It has applications in cryptography, large value finance and other high accuracy science and engineering applications.

See: Gnu Multi-precision library, libtommath, etc.

  • Related