Siler
Siler

Reputation: 9494

Yasm with 64-bit instructions

I'm trying to assemble some assembly source code for x86_64 written in Intel syntax that uses 64-bit registers. I use the following command line flags:

yasm foo.asm -a x86 -m amd64

I keep getting errors like:

warning: `rbp' is a register in 64-bit mode
foo.asm:23: error: undefined symbol `rbp' (first use)

So, I've seen a similar question on stackoverflow, as well as numerous resources on the web that indicate that this problem can be solved by specifying the "BITS" directive, specifically like:

BITS 64

The problem is, it's unclear to me what that even means. I don't understand what a "directive" is. It seems to be something you need to specify in the assembly code itself. But in this case, I don't control the code, so I'm just trying to find a command line flag to assemble it.

Is there a way to specify the BITS directive in a command line flag that I can pass to yasm?

Upvotes: 4

Views: 3685

Answers (2)

Peter Cordes
Peter Cordes

Reputation: 364468

Use -felf64 to assemble x86-64 code into a 64-bit ELF .o.

If you're making a flat binary (not a .o or .obj) use BITS 64 at the top of your file. Otherwise avoid it, you normally don't want to put 64-bit machine code into a 32-bit .o; a build-time error is better.


Despite the documentation in the manual, YASM's -a x86 -m amd64 options don't override the default for the default -fbin flat binary output format, which is to assemble assuming the code will be executed in 16-bit mode. (Exactly like NASM).

Using -m x86 does prevent -felf64, or BITS 64 inside a file, from working. It's part of YASM's CPU-feature limits support, that can help stop you from accidentally using ISA features not supported by the target CPU. (e.g. CPU Conroe AMD enables everything up to SSSE3, and AMD64 instructions like syscall, while disabling SSE4 and AVX. The default is no limits.)


BITS 16 is the default mode with -fbin.

The assembler has to know what mode the CPU is expected to execute your code in. For example, mov eax,ecx is 89 C8 in 32-bit mode, but 66 89 C8 in 16-bit mode (operand-size override prefix and then the same opcode + modrm as for 32-bit mode).

64-bit operand-size and address-size, and 64-bit registers in general, are only encodeable in 64-bit mode, hence the error when trying to assemble code using rbp when the assembler is making code that will execute in 16-bit mode.

A bootloader that starts in 16-bit mode might switch to 32 and/or 64-bit mode, so you'd need a BITS 32 or BITS 64 directive in front of the jump target for the jmp far that switches to 32-bit or 64-bit mode.

This is the normal use-case for a BITS directive. Unfortunately, like NASM, there doesn't seem to be a command-line option that will assemble a flat binary in your choice of mode. It would be cool if you could put inc eax into a file and get 66 40, 40, or FF C0 without editing the file, just using command-line options, but we can't.

Upvotes: 4

Dr.Gray
Dr.Gray

Reputation: 21

If i understand correctly, your question is: How to "activate" 64-bit mode??

It's really simple.

If your code is:

mov rax, [rbp - 2]
mov rbx, rax
syscall  ;just to call some or for end of code

Then change it to:

bits 64

mov rax, [rbp - 2]
mov rbx, rax
syscall  ;just to call some or for end of code

Simply put, put the "bits 64" in the start of your code!

Upvotes: 2

Related Questions