Skip to content

Instantly share code, notes, and snippets.

@ericherman
Last active July 10, 2016 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericherman/9d1a646ad380b27d42b9ff8497e69f32 to your computer and use it in GitHub Desktop.
Save ericherman/9d1a646ad380b27d42b9ff8497e69f32 to your computer and use it in GitHub Desktop.
except in some rare cases, xor swapping is probably silly
eric@titan:~/src/code-snips/c$ cat swap-em.c
#include <stdio.h>
#include <stdint.h>
/* this is the way to swap pointers */
void standard_swap(char **left, char **right)
{
char *tmp;
tmp = *left;
*left = *right;
*right = tmp;
}
/*
* The xor swapping of pointers is doable, but dumb.
* Typically bitwise operations do not work on pointers in C.
* Casting to intptr_t is a work-around, but ugly.
* Even so, the result does not look a lot more opimized to me.
* $ gcc -S -O3 swap-em.c
* $ cat swap-em.s
*/
void xor_swap(char **left, char **right)
{
*left = (char*) (((intptr_t)*left) ^ ((intptr_t)*right));
*right = (char*) (((intptr_t)*left) ^ ((intptr_t)*right));
*left = (char*) (((intptr_t)*left) ^ ((intptr_t)*right));
}
int main(int argc, char **argv)
{
char *a, *b;
char *o, *t;
o = "one";
t = "two";
a = o;
b = t;
printf("initial state: %s, %s\n", a, b);
standard_swap(&a, &b);
printf("standard swap: %s, %s\n", a, b);
xor_swap(&a, &b);
printf("xor swap back: %s, %s\n", a, b);
return 0;
}
From x86:
eric@titan:~/src/code-snips/c$ gcc -S -O3 swap-em.c
eric@titan:~/src/code-snips/c$ cat swap-em.s
.file "swap-em.c"
.text
.p2align 4,,15
.globl standard_swap
.type standard_swap, @function
standard_swap:
.LFB24:
.cfi_startproc
pushl %ebx
.cfi_def_cfa_offset 8
.cfi_offset 3, -8
movl 8(%esp), %edx
movl 12(%esp), %eax
movl (%edx), %ecx
movl (%eax), %ebx
movl %ebx, (%edx)
movl %ecx, (%eax)
popl %ebx
.cfi_restore 3
.cfi_def_cfa_offset 4
ret
.cfi_endproc
.LFE24:
.size standard_swap, .-standard_swap
.p2align 4,,15
.globl xor_swap
.type xor_swap, @function
xor_swap:
.LFB25:
.cfi_startproc
movl 4(%esp), %eax
movl 8(%esp), %ecx
movl (%eax), %edx
xorl (%ecx), %edx
movl %edx, (%eax)
xorl (%ecx), %edx
movl %edx, (%ecx)
xorl %edx, (%eax)
ret
.cfi_endproc
.LFE25:
.size xor_swap, .-xor_swap
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "two"
.LC1:
.string "one"
.LC2:
.string "initial state: %s, %s\n"
.LC3:
.string "standard swap: %s, %s\n"
.LC4:
.string "xor swap back: %s, %s\n"
.section .text.startup,"ax",@progbits
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB26:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
movl $.LC0, 12(%esp)
movl $.LC1, 8(%esp)
movl $.LC2, 4(%esp)
movl $1, (%esp)
call __printf_chk
movl $.LC1, 12(%esp)
movl $.LC0, 8(%esp)
movl $.LC3, 4(%esp)
movl $1, (%esp)
call __printf_chk
movl $.LC0, 12(%esp)
movl $.LC1, 8(%esp)
movl $.LC4, 4(%esp)
movl $1, (%esp)
call __printf_chk
xorl %eax, %eax
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE26:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
.section .note.GNU-stack,"",@progbits
eric@titan:~/src/code-snips/c$
From ARM:
eric@localhost:~/src/code-snips/c$ gcc -S -O3 swap-em.c
eric@localhost:~/src/code-snips/c$ cat swap-em.s
.arch armv7-a
.eabi_attribute 28, 1
.fpu vfpv3-d16
.eabi_attribute 20, 1
.eabi_attribute 21, 1
.eabi_attribute 23, 3
.eabi_attribute 24, 1
.eabi_attribute 25, 1
.eabi_attribute 26, 2
.eabi_attribute 30, 2
.eabi_attribute 34, 1
.eabi_attribute 18, 4
.file "swap-em.c"
.text
.align 2
.global standard_swap
.syntax unified
.thumb
.thumb_func
.type standard_swap, %function
standard_swap:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r3, [r0]
ldr r2, [r1]
str r2, [r0]
str r3, [r1]
bx lr
.size standard_swap, .-standard_swap
.align 2
.global xor_swap
.syntax unified
.thumb
.thumb_func
.type xor_swap, %function
xor_swap:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
@ link register save eliminated.
ldr r2, [r0]
ldr r3, [r1]
eors r3, r3, r2
str r3, [r0]
ldr r2, [r1]
eors r3, r3, r2
str r3, [r1]
ldr r2, [r0]
eors r3, r3, r2
str r3, [r0]
bx lr
.size xor_swap, .-xor_swap
.section .text.startup,"ax",%progbits
.align 2
.global main
.syntax unified
.thumb
.thumb_func
.type main, %function
main:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
push {r3, r4, r5, lr}
movw r5, #:lower16:.LC0
movw r4, #:lower16:.LC1
movt r5, #:upper16:.LC0
movt r4, #:upper16:.LC1
movw r1, #:lower16:.LC2
mov r3, r5
movt r1, #:upper16:.LC2
mov r2, r4
movs r0, #1
bl __printf_chk
mov r3, r4
mov r2, r5
movw r1, #:lower16:.LC3
movs r0, #1
movt r1, #:upper16:.LC3
bl __printf_chk
mov r3, r5
mov r2, r4
movw r1, #:lower16:.LC4
movs r0, #1
movt r1, #:upper16:.LC4
bl __printf_chk
movs r0, #0
pop {r3, r4, r5, pc}
.size main, .-main
.section .rodata.str1.4,"aMS",%progbits,1
.align 2
.LC0:
.ascii "two\000"
.LC1:
.ascii "one\000"
.LC2:
.ascii "initial state: %s, %s\012\000"
.space 1
.LC3:
.ascii "standard swap: %s, %s\012\000"
.space 1
.LC4:
.ascii "xor swap back: %s, %s\012\000"
.ident "GCC: (Ubuntu/Linaro 5.4.0-3ubuntu1~12.04) 5.4.0 20160603"
.section .note.GNU-stack,"",%progbits
eric@localhost:~/src/code-snips/c$ cat /proc/cpuinfo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment