x86, asm: Refactor atomic64_386_32.S to support old binutils and be cleaner

The old code didn't work on binutils 2.12 because setting a symbol to
a register apparently requires a fairly recent version.

This commit refactors the code to use the C preprocessor instead, and
in the process makes the whole code a bit easier to understand.

The object code produced is unchanged as expected.

This fixes kernel bugzilla 16506.

Reported-by: Dieter Stussy <kd6lvw+software@kd6lvw.ampr.org>
Signed-off-by: Luca Barbieri <luca@luca-barbieri.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Cc: <stable@kernel.org> 2.6.35
LKML-Reference: <tip-*@git.kernel.org>
This commit is contained in:
Luca Barbieri 2010-08-06 04:04:38 +02:00 committed by H. Peter Anvin
parent 8fd49936a8
commit 30246557a0

View file

@ -25,150 +25,170 @@
CFI_ADJUST_CFA_OFFSET -4 CFI_ADJUST_CFA_OFFSET -4
.endm .endm
.macro BEGIN func reg #define BEGIN(op) \
$v = \reg .macro END; \
CFI_ENDPROC; \
ENDPROC(atomic64_##op##_386); \
.purgem END; \
.endm; \
ENTRY(atomic64_##op##_386); \
CFI_STARTPROC; \
LOCK v;
ENTRY(atomic64_\func\()_386) #define RET \
CFI_STARTPROC UNLOCK v; \
LOCK $v
.macro RETURN
UNLOCK $v
ret ret
.endm
.macro END_ #define RET_END \
CFI_ENDPROC RET; \
ENDPROC(atomic64_\func\()_386) END
.purgem RETURN
.purgem END_
.purgem END
.endm
.macro END #define v %ecx
RETURN BEGIN(read)
END_ movl (v), %eax
.endm movl 4(v), %edx
.endm RET_END
#undef v
BEGIN read %ecx #define v %esi
movl ($v), %eax BEGIN(set)
movl 4($v), %edx movl %ebx, (v)
END movl %ecx, 4(v)
RET_END
#undef v
BEGIN set %esi #define v %esi
movl %ebx, ($v) BEGIN(xchg)
movl %ecx, 4($v) movl (v), %eax
END movl 4(v), %edx
movl %ebx, (v)
movl %ecx, 4(v)
RET_END
#undef v
BEGIN xchg %esi #define v %ecx
movl ($v), %eax BEGIN(add)
movl 4($v), %edx addl %eax, (v)
movl %ebx, ($v) adcl %edx, 4(v)
movl %ecx, 4($v) RET_END
END #undef v
BEGIN add %ecx #define v %ecx
addl %eax, ($v) BEGIN(add_return)
adcl %edx, 4($v) addl (v), %eax
END adcl 4(v), %edx
movl %eax, (v)
movl %edx, 4(v)
RET_END
#undef v
BEGIN add_return %ecx #define v %ecx
addl ($v), %eax BEGIN(sub)
adcl 4($v), %edx subl %eax, (v)
movl %eax, ($v) sbbl %edx, 4(v)
movl %edx, 4($v) RET_END
END #undef v
BEGIN sub %ecx #define v %ecx
subl %eax, ($v) BEGIN(sub_return)
sbbl %edx, 4($v)
END
BEGIN sub_return %ecx
negl %edx negl %edx
negl %eax negl %eax
sbbl $0, %edx sbbl $0, %edx
addl ($v), %eax addl (v), %eax
adcl 4($v), %edx adcl 4(v), %edx
movl %eax, ($v) movl %eax, (v)
movl %edx, 4($v) movl %edx, 4(v)
END RET_END
#undef v
BEGIN inc %esi #define v %esi
addl $1, ($v) BEGIN(inc)
adcl $0, 4($v) addl $1, (v)
END adcl $0, 4(v)
RET_END
#undef v
BEGIN inc_return %esi #define v %esi
movl ($v), %eax BEGIN(inc_return)
movl 4($v), %edx movl (v), %eax
movl 4(v), %edx
addl $1, %eax addl $1, %eax
adcl $0, %edx adcl $0, %edx
movl %eax, ($v) movl %eax, (v)
movl %edx, 4($v) movl %edx, 4(v)
END RET_END
#undef v
BEGIN dec %esi #define v %esi
subl $1, ($v) BEGIN(dec)
sbbl $0, 4($v) subl $1, (v)
END sbbl $0, 4(v)
RET_END
#undef v
BEGIN dec_return %esi #define v %esi
movl ($v), %eax BEGIN(dec_return)
movl 4($v), %edx movl (v), %eax
movl 4(v), %edx
subl $1, %eax subl $1, %eax
sbbl $0, %edx sbbl $0, %edx
movl %eax, ($v) movl %eax, (v)
movl %edx, 4($v) movl %edx, 4(v)
END RET_END
#undef v
BEGIN add_unless %ecx #define v %ecx
BEGIN(add_unless)
addl %eax, %esi addl %eax, %esi
adcl %edx, %edi adcl %edx, %edi
addl ($v), %eax addl (v), %eax
adcl 4($v), %edx adcl 4(v), %edx
cmpl %eax, %esi cmpl %eax, %esi
je 3f je 3f
1: 1:
movl %eax, ($v) movl %eax, (v)
movl %edx, 4($v) movl %edx, 4(v)
movl $1, %eax movl $1, %eax
2: 2:
RETURN RET
3: 3:
cmpl %edx, %edi cmpl %edx, %edi
jne 1b jne 1b
xorl %eax, %eax xorl %eax, %eax
jmp 2b jmp 2b
END_ END
#undef v
BEGIN inc_not_zero %esi #define v %esi
movl ($v), %eax BEGIN(inc_not_zero)
movl 4($v), %edx movl (v), %eax
movl 4(v), %edx
testl %eax, %eax testl %eax, %eax
je 3f je 3f
1: 1:
addl $1, %eax addl $1, %eax
adcl $0, %edx adcl $0, %edx
movl %eax, ($v) movl %eax, (v)
movl %edx, 4($v) movl %edx, 4(v)
movl $1, %eax movl $1, %eax
2: 2:
RETURN RET
3: 3:
testl %edx, %edx testl %edx, %edx
jne 1b jne 1b
jmp 2b jmp 2b
END_ END
#undef v
BEGIN dec_if_positive %esi #define v %esi
movl ($v), %eax BEGIN(dec_if_positive)
movl 4($v), %edx movl (v), %eax
movl 4(v), %edx
subl $1, %eax subl $1, %eax
sbbl $0, %edx sbbl $0, %edx
js 1f js 1f
movl %eax, ($v) movl %eax, (v)
movl %edx, 4($v) movl %edx, 4(v)
1: 1:
END RET_END
#undef v