Home > Enterprise >  Undefined Symbol rax,rbx,rcx,rdx in MASM Visual Studio
Undefined Symbol rax,rbx,rcx,rdx in MASM Visual Studio

Time:10-08

Following is the code:

.386

.model flat, stdcall

.stack 4096

    ExitProcess PROTO, dwExitCode:DWORD

    .DATA

    .code

Main proc

mov rax,0

mov rbx,0

mov rcx,0

mov rdx,0

       mov al, 0F0H           ;using 8-bit register

    mov bx, 1012H            ;using 16-bit register

    mov ecx, 15284H          ;using 32-bit register
   
    mov rdx, 3578815H        ;using 64-bit register


INVOKE ExitProcess, 0

main ENDP

END main

Whenever i run this, it says :undefined symbol rax, rbx, rcx,rdx

But it works when I use:
.386
.model flat, stdcall
.stack 4096
    ExitProcess PROTO, dwExitCode:DWORD
    .DATA
    .code
Main proc

mov eax,0

mov ebx,0

mov ecx,0

mov edx,0

       mov al, 0F0H           ;using 8-bit register

    mov bx, 1012H            ;using 16-bit register

    mov ecx, 15284H          ;using 32-bit register  
 
    mov edx, 3578815H        ;using 64-bit register  

INVOKE ExitProcess, 0

main ENDP

END main

I'm using x86 configuration. x64 doesn't work for me. Could someone tell me why rax,rbx,rcx and rdx arent working?

CodePudding user response:

For Visual Studio, a 64 bit build would use ML64.EXE instead of MASM.EXE. Don't use .386 directive. There is no .model directive for ML64.EXE, since the 64 bit calling convention is fixed.

CodePudding user response:

You can't use 64-bit registers in 32-bit code.

In 16-bit mode, 32-bit registers are usable in machine code with 66h and 67h prefixes. So 16 and 32-bit code can both use instructions like movzx ax, byte ptr [ecx] (assuming the code is running on a 386 or newer, of course, hence .model 386 telling the assembler that it should let you write code like that).

But for x86-64, there wasn't an unused byte left for use as a prefix in 32-bit mode, so the AMD64 architects had to do it differently. The new features of x86-64 are only available in 64-bit mode, not in 32-bit compat mode.

The actual mechanism they picked was to remove the 1-byte encodings for inc reg and dec reg, and reuse those 0x4? bytes as REX prefixes, including a Width bit to distinguish add eax, ecx from add rax, rcx, and 3 extra bits for register numbers, allowing access to r8-r15 for instructions like add r8d, [r9 r10].


As https://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix says, The REX prefix is only available in long mode.

Fun fact: If you try to execute 64-bit machine code with the CPU in 32-bit mode (e.g. from using NASM bits 64 in the source and assembling with nasm -fwin32), the REX prefixes will decode as inc or dec instructions.

You can play fun tricks like making machine code that runs 3 different ways depending on what mode it executes in. For example, x86-32 / x86-64 polyglot machine-code fragment that detects 64bit mode at run-time?. Also a 3-way codegolf answer shows disassembly of the same code 3 different ways.

  • Related