# x at %ebp+8, n at %ebp+12
movl 8(%ebp), %esi
movl 12(%ebp), %ebx
movl $-1, %edi
movl $1, %edx
.L2:
movl %edx, %eax
andl %esi, %eax
xorl %eax, %edi
movl %ebx, %ecx
sall %cl, %edx
testl %edx, %edx
jne .L2
movl %edi, %eax
I converted the above code to the below code, but i am not completely sure if it is correct.
int loop(int x, int n){
int result = -1;
for (mask = 1; mask >= result; mask = x&1) {
result ^= n;
}
return result;
}
x and n are two integers stored in %ebp memory and are moved to registry %esi and %ebx. Result and Mask have a value of -1 and 1 and that is from the first part of the code
I think after .L2:
the loop starts and that is where i get confused.
At the end result is returned movl %edi, %eax
Your code is completely wrong. You should have done some test by yourself before posting quesetions.
First of all, mask
in your code is not declared in your function.
Then, after declareing mask
as int
, the function loop
will fall into an infinite loop when result
won't become positive via result ^= n;
. On the other hand, the assembly code won't fall into an infinite loop unless n
is multiple of 32 (including zero).
To convert the code to assembly:
1. I did direct conversion from assembly to C.
Note that I used unsigned type uint32_t
because
uint32_t
because size of unsigned int
is dependent to environments and it may be less than 32-bit long while registers used here (except for %cl
) are 32-bit long.Quote from N1570 6.5.7 Bitwise shift operators:
4 The result of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are filled with zeros. IfE1
has an unsigned type, the value of the result isE1
× 2E2
, reduced modulo one more than the maximum value representable in the result type. IfE1
has a signed type and nonnegative value, andE1
× 2E2
is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
Also note that stdint.h
or inttypes.h
has to be included to use uint32_t
.
The width to shift is masked to 5-bit long in x86 CPUs that is 80286 or later.
uint32_t loop(uint32_t x, uint32_t n) {
uint32_t esi = x; /* movl 8(%ebp), %esi */
uint32_t ebx = n; /* movl 12(%ebp), %ebx */
uint32_t edi = -1; /* movl $-1, %edi */
uint32_t edx = 1; /* movl $1, %edx */
uint32_t eax, ecx;
do { /* .L2: */
eax = edx; /* movl %edx, %eax */
eax &= esi; /* andl %esi, %eax */
edi ^= eax; /* xorl %eax, %edi */
ecx = ebx; /* movl %ebx, %ecx */
edx <<= (ecx & 0xff) & 31; /* sall %cl, %edx */
} while (edx != 0); /* testl %edx, %edx ; jne .L2 */
eax = edi; /* movl %edi, %eax */
return eax;
}
2. I introduced variable names to make their roles clear.
uint32_t loop(uint32_t x, uint32_t n) {
uint32_t result = -1;
uint32_t mask = 1;
uint32_t eax, ecx;
do {
eax = mask;
eax &= x;
result ^= eax;
ecx = n;
mask <<= (ecx & 0xff) & 31;
} while (mask != 0);
return result;
}
3. I merged some expressions.
uint32_t loop(uint32_t x, uint32_t n) {
uint32_t result = -1;
uint32_t mask = 1;
do {
result ^= mask & x;
mask <<= n & 31;
} while (mask != 0);
return result;
}
4. I changed do
loop to for
loop because your attempt uses it.
uint32_t loop(uint32_t x, uint32_t n) {
uint32_t result = -1;
uint32_t mask;
for (mask = 1; mask != 0; mask <<= n & 31) {
result ^= mask & x;
}
return result;
}
Full code for testing and demo:
#include <stdio.h>
#include <inttypes.h>
#include <limits.h>
__asm__ (
/* support both environments that does and doesn't add underscore before function name */
"loop_asm:\n"
"_loop_asm:\n"
"push %ebp\n"
"mov %esp, %ebp\n"
"push %esi\n"
"push %edi\n"
"push %ebx\n"
"# x at %ebp+8, n at %ebp+12\n"
"movl 8(%ebp), %esi\n"
"movl 12(%ebp), %ebx\n"
"movl $-1, %edi\n"
"movl $1, %edx\n"
".L2_test:\n" /* rename .L2 to .L2_test to avoid collision */
"movl %edx, %eax\n"
"andl %esi, %eax\n"
"xorl %eax, %edi\n"
"movl %ebx, %ecx\n"
"sall %cl, %edx\n"
"testl %edx, %edx\n"
"jne .L2_test\n"
"movl %edi, %eax\n"
"pop %ebx\n"
"pop %edi\n"
"pop %esi\n"
"leave\n"
"ret\n"
);
uint32_t loop_asm(uint32_t, uint32_t);
uint32_t loop_convert(uint32_t x, uint32_t n) {
uint32_t result = -1;
uint32_t mask;
for (mask = 1; mask != 0; mask <<= n & 31) {
result ^= mask & x;
}
return result;
}
int mask;
int loop(int x, int n){
int result = -1;
for (mask = 1; mask >= result; mask = x&1) {
result ^= n;
}
return result;
}
int main(void) {
int x, n;
uint32_t raw, test, conv;
int miss_count = 0;
/* search for mismatch in some range */
for (n = 1; n < 32; n++) {
uint32_t x_test;
for (x_test = 0; x_test < UINT32_C(100000); x_test++) {
if (loop_asm(x, n) != loop_convert(x, n)) {
printf("mismatch at x=%"PRIu32", n=%d\n", x_test, n);
if (miss_count < INT_MAX) miss_count++;
}
}
}
printf("%d mismatch(es) found.\n", miss_count);
/* print some examples */
x = 100;
n = 5;
raw = loop_asm(x, n);
conv = loop_convert(x, n);
printf("loop_asm(%d, %d) = %"PRIu32"\n", x, n, raw);
printf("loop_convert(%d, %d) = %"PRIu32"\n", x, n, conv);
fflush(stdout);
test = loop(x, n);
printf("loop(%d, %d) = %"PRIu32"\n", x, n, test);
return 0;
}