负数的表示方法,补码
比如一个正数 1的补码就是 加上就溢出等于0的值,
byte范围内,256就溢出了,所以1的补码就是256-1=255,0xFF,所以-1就是FF
另一种计算方法是,负数等于正数的反码加一;
1补数就是反码!
大小端:arm同时支持大小端,但一般都采用小端,
carry flag 就是2大数相加溢出;
逻辑左移或右移,简单粗暴的按位移动,移出的最后一位进入carry flag
算术右移,正数左边补0,负数左边补1.
伪指令:为了尽可能减少指令种类,伪指令能增加可读性,使用objdump时 添加参数 -M no-aliases 可以看到真实底层指令
mov 的立即数 只能是16bit,移位只能是0,16,32,48;
movk,move keep :把数移到某16位,其他位不变
操作数2的三种形式!
1,寄存器 和一个移动
MOV X1, X2, LSL #1 // Logical shift left
上面的可以写成下面的伪指令
2,寄存器和一个扩展
3,一个小立即数和位移
movn move not,就是反码,0的反码是-1, 1的反码是-2, 2的反码是-3 ,正数的补码等于其反码加一,那么正数的反码就是正数的补码(就是相反数)减一;
用movn和add两条指令完成求相反数!取反加一
Remember that the negative of a number is the
乘 -1 ,也就是取相反数,不要用 mul 指令,因为乘法指令比较慢,可以用取反加一两条指令,2个时钟周期完成;
move.s
// // Examples of the MOV instruction. // .global _start // Provide program starting address // Load X2 with 0x1234FEDC4F5D6E3A first using MOV and MOVK _start: MOV X2, #0x6E3A MOVK X2, #0x4F5D, LSL #16 MOVK X2, #0xFEDC, LSL #32 MOVK X2, #0x1234, LSL #48 // Just move W2 into W1 MOV W1, W2 // Now lets see all the shift versions of MOV MOV X1, X2, LSL #1 // Logical shift left MOV X1, X2, LSR #1 // Logical shift right MOV X1, X2, ASR #1 // Arithmetic shift right MOV X1, X2, ROR #1 // Rotate right // Repeat the above shifts using mnemonics. LSL X1, X2, #1 // Logical shift left LSR X1, X2, #1 // Logical shift right ASR X1, X2, #1 //Arithmetic shift right ROR X1, X2, #1 // Rotate right // Example that works with 8 bit immediate and shift MOV X1, #0xAB000000 // Too big for #imm16 // Example of MOVN MOVN W1, #45 // Example of a MOV that the Assembler will change to MOVN MOV W1, #0xFFFFFFFE // (-2) // Setup the parameters to exit the program // and then call Linux to do it. MOV X0, #0 // Use 0 return code MOV X8, #93 // Serv command code 93 terms SVC 0 // Call linux to terminate
Makefile:
TARGET=move $(TARGET): $(TARGET).o ld -o $@ $^ %.o:%.s as -o $@ $<
A=a 类似声明变量,$(A) 取变量A的内容;
目标:依赖
命令内容
冒号前面是目标【类似汇编的label】,冒号后面的是依赖,可以是多个依赖,$@ 取目标内容;$< 取第一个依赖;$^ 取所有依赖;
makefile 写法: https://seisman.github.io/how-to-write-makefile/
经测试,linux返回值好像确实只返回一个无符号byte!
指令追加s则set 32位操作码的bit29 通知设置标志位,标志好像有4种,后面学;
.global _start
_start: mov w0,0xffff0000 add w0,w0,w0 b.cs ret1 b ret0 ret0: mov w0,0 mov x8,93 svc 0 ret1: mov w0,1 mov x8,93 svc 0
上面的代码返回0,把add换成adds则会设carry标志返回1,因为相加进位溢出了,b.cs = Carry set 跳转
adc add with carry flag。
下面例子中adds进位了,set carry,adc命令中 x0=x2+x4+1
// // Example of 128-Bit addition with the ADD/ADC instructions. // .global _start // Load the registers with some data // First 64-bit number is 0x0000000000000003FFFFFFFFFFFFFFFF _start: mov x2,0x0000000000000003 mov x3,0xffffffffffffffff //Assem will change to MOVN // Second 64-bit number is 0x00000000000000050000000000000001 mov x4,0x0000000000000005 mov x5,0x0000000000000001 adds x1,x3,x5 // Lower order 64-bits adc x0,x2,x4 // Higher order 64-bits // Setup the parameters to exit the program // and then call Linux to do it. // W0 is the return code and will be what we // calculated above. mov x8,93 svc 0
// // do the exercise 7 of chapter 2,write a program that performs 128-bit subtraction // .global _start _start: mov x2 ,0x9 mov x3,0x1 mov x4,3 mov x5,2 subs x1,x3,x5 //negative,C clear sbc x0,x2,x4 //x0=5 is expected mov x8,93 svc 0
For now,chapter2 ended;