I am trying to use AAD instruction in NASM 64-bit but it shows an error at compile time:
error: instruction not supported in 64-bit mode
Is there a way I can still use this instruction in 64-bit mode?
Is there any other equivalent instruction I should be aware of?
The AAD instruction is invalid in 64-bit mode, but its operation is described in Intel's Software Developer's Manual, so you can implement the same functionality yourself if you need it:
tempAL ← AL;
tempAH ← AH;
AL ← (tempAL + (tempAH ∗ imm8)) AND FFH;
(* imm8 is set to 0AH for the AAD mnemonic.*)
AH ← 0;
The SF, ZF, and PF flags are set according to the resulting binary value in the AL register; the OF, AF, and CF flags
are undefined.
Related
Below is the code for reset vector as defined arm linux (arch/arm/kernel/entry-armv.S)
vector_rst:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
b vector_und
What does the instruction swi SYS_ERROR0 do ? When I checked, I found SYS_ERROR0 in arch/arm/kernel/asm-offsets.c
DEFINE(SYS_ERROR0, 0x9f0000);
I was unable to find anything related to it on internet. Can someone explain what does this instruction do ? What is SYS_ERROR0 ?
I was unable to find anything related to it on internet. Can someone explain what does this instruction do ? What is SYS_ERROR0 ?
DEFINE(SYS_ERROR0, 0x9f0000);
The swi instruction is typically a call from user mode to system mode. Ie, User space to the Linux kernel. Lower numbers are standard Linux system call such as open(), sbrk(), etc.
If you look at uapi/asm/unistd.h in arch/arm you can see some defines like __ARM_NR_BASE which is __NR_SYSCALL_BASE+0x0f0000. This can be 0x9f0000 for OABI systems. Basically, these are secret system calls that are ARM specific kernel calls. For instance, __ARM_NR_get_tls is only used for libc thread management on the ARM. Other CPUs may have different non-syscall mechanisms to do the same thing and/or the syscall interface may be different than on the ARM CPU.
So SYS_ERROR0 is a special ARM system call. By the way, asm-offset.c is never used directly. It is compiled and the object is scanned by a script to get assembler offsets to structures, etc. So if a compiler packs structures differently, then in theory, the assembler will be in-sync with the compiler version. We start here,
.L__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, .L__vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
The swi is a vector handled by W(ldr) pc, .L__vectors_start + 0x1000, so the code is 4k after the vector table. This is vector_swi and you can see the code in entry-common.S. There are two methods of making a syscall. The older one (OABI) encodes the call in the SWI instruction. This is bad as the ICACHE must be examined as data (DCACHE). The newer systems pass the syscall in r7. There are two jump tables; sys_call_table and sys_oabi_call_table to handle OABI and the newer mechanism. In both case, higher __NR_SYSCALL_BASE are special cased and use arm_syscall in traps.c. So SYS_ERROR0 is the case 0: /* branch through 0 */ code in traps.c. The message branch through zero is printed (because user space jump to the reset vector which can be at address 0) and the user space gets a signal.
Here are the pop instructions that use the shortcut opcodes on page 1159 of the intel x64 manual:
58+ rw POP r16 Pop top of stack into r16; increment stack
pointer.
58+ rd POP r64 Pop top of stack into r64; increment stack
pointer.
Do these instructions use Rex.R or Rex.B to encode registers 9-16 or are they just added to the opcode? Also does the 64-bit version use Rex.W? I've just never run into these register shortcut instructions before.
Instructions that encode a register operand as part of the opcode use the REX.B field to access registers r8 and so on.
64bit pushes and pops do not need a REX.W, they are 64bit by default and there is no way to make them 32bit. They can be made 16bit by using the 66h prefix.
I have been looking around on NASM tutorials and I have noticed that in all the references to the DIV instruction, when discussing 32-bit division, say something along the lines of:
DIV ECX ; EDX:EAX / ECX
What does the EDX:EAX mean? Why are two registers being divided by one register?
Thanks in advance
This is a spanned register, or register pair, its used for 64-bit math in this case (so you can use a 64-bit quotient, IIRC this was added to allow arbitrary point arithmatic).
EDX contains the high DWORD and sign, EAX the low DWORD.
The same logic is used for returning 64-bit results. Also, it should be noted, this has nothing to do with NASM, its part of the x86 architecture (which also defines 32-bit pairs, like DX:AX when using 16-bit instructions).
While investigating a crash, I came across the following code snippet and immediately recognized that the mov instruction should actually be movq to get the correct 64-bit register operation.
#elif defined(__x86_64__)
unsigned long rbp;
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
sp = (void **) rbp;
#else
Further to this, I also found documentation that claims that the rbp register for x86-64 is general purpose and does not contain the address of the current frame. I have also found documentation that claims that rbp does contain the address of the current frame. Can someone clarify?
Regarding the first part of your question (movq instead of mov), the assembler (as, in this case), will recognize that your operand is 64 bits, and will correctly use movq. mov is not a valid instruction, it's a way to tell the assembler "use the right mov variant depending on the operands".
Regarding the second part, it's actually both: it's a general purpose register, in the sense that it can hold any value. It is also used as a stack-frame base pointer. The '2.4 Stack operation' section of the AMD64 Application programming manual says:
A stack is a portion of a stack segment in memory that is used to link
procedures. Software conventions typically define stacks using a
stack frame, which consists of two registers—a stack-frame base
pointer (rBP) and a stack pointer (rSP)—
Ok, I get this compile error:
Error: suffix or operands invalid for `push'
when I use this line:
pushw %es;
I know it is either the %es or w as I have been successfully porting others push, pop commands for 64 bit assembler.
%es is an existing register according to some documentaion I have found and isn't referenced differently I think.
So what could be my problem? I am extremely rusty on my asm and I think it could be the w.
Thanks for any help.
As Zimbaboa already explained, there is no segmentation in 64-bit mode.
Moreover, if you look at Intel's manuals, Instruction Set Reference, M-Z, you will see that push ES is an invalid instruction altogether in 64-bit mode (page 423):
Opcode Instruction Op/ 64-Bit Compat/ Description
En Mode Leg Mode
...
0E PUSH CS NP Invalid Valid Push CS.
16 PUSH SS NP Invalid Valid Push SS.
1E PUSH DS NP Invalid Valid Push DS.
06 PUSH ES NP Invalid Valid Push ES.
0F A0 PUSH FS NP Valid Valid Push FS.
0F A8 PUSH GS NP Valid Valid Push GS.
Is this the Pentium instruction set? If so, then yes, I think ES (capitalized) is a 16-bit segment register. The instruction is just "push %ES" according to this site: http://faydoc.tripod.com/cpu/index.htm.
Wish I could help more, but I only code in MIPS assembly.
You are using instruction PUSHW which is push word to stack. On 64bit machines wordsize is 64 and you are trying to push 16bit ES register using a wrong instruction.
Try just using push, but take care that your pop is also matching.
Edit1: Checked the processor documentation, segmentation is disable in 64bit mode of x86_64
Check section 4 of above document.
64-bit mode, segmentation is disabled, creating a flat 64-bit virtual-address space. As will be seen, certain functions of some segment registers, particularly the system-segment registers, continue to be used in 64-bit mode.
Again in section 4.5.3
DS, ES, and SS Registers in 64-Bit Mode. In 64-bit mode, the contents of the ES, DS, and SS segment registers are ignored. All fields (base, limit, and attribute) in the hidden portion of the segment registers are ignored.
So in your code just safely ignore any references to these registers.