I'm writing an arm64 assembly program to check if number is even or odd.
//**********************************
// Check if number is even or not *
//**********************************
.global _start
_start: MOV X5, #13 // Load the number
// Set up everything for print
mov X0, #1 // 1 = StdOut
mov X8, #64 // Linux write system call
// If number is divisible by two, C flag is clear
LSR X6, X5, #1 // Divide by 2
B.CS odd // If NOT divisible by 2, jump to odd
even: ldr X1, =evenD // Load addr of even str
mov X2, #11 // Set up length of even str
B end // B to avoid odd case
odd: ldr X1, =oddD // Load addr of odd string
mov X2, #12 // Set up length of odd str
end: svc 0 // Tell Linux to print
mov X0, #0 // Ret code 0
mov X8, #93 // Code 93 to terminate
svc 0 // Tell linux to terminate
// Data section
.data
evenD: .ascii "It's even!\n"
oddD: .ascii "That's odd!\n"
Behaviour that I'd expect is that LSR will divide the number at X5 by 2 and if number is odd, then C flag will be set. If flag is set (number is odd) program branches to odd label.
The problem is that carry flag is not set. When I inspect cpsr register in gdb it doesn't change after LSR instruction. I've also tried to use LSRS
as many data processing instructions without S don't affect carry flags, but that instruction doesn't exist:
as -g even.s -o even.o
even.s: Assembler messages:
even.s:10: Error: unknown mnemonic `lsrs' -- `lsrs X6,X5,#1'
As a result, no matter which number I use, according to my program they are all even. So the question is: why C flag in cpsr doesn't change when I shift out 1 from the register?
CodePudding user response:
Both lsr
and lsl
instructions are actually aliases of ubfm
that doesn't affect the cpsr
on aarch64
You are right. I don't like it either. Stupid IMO.
You should amend your code :
tst x5, #1
b.ne odd