4

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?

Siler
  • 8,976
  • 11
  • 64
  • 124
  • `bits 64` simply says to encode the instructions assuming the code will be running in a 64-bit mode. – Michael Petch Jan 04 '18 at 15:55
  • 1
    `-m amd64` as per the [manual](http://www.tortall.net/projects/yasm/manual/html/running-arch.html). – Jester Jan 04 '18 at 16:01
  • 1
    @Jester `-m amd64` controls the object file format, the OP already included it. However, I don't see why they can't simply add `BITS 64` and the source to a temporary file. – Margaret Bloom Jan 04 '18 at 16:04
  • 1
    @Jester : He is already using `-m amd64` according to the question. I don't know if this is an OSDev question or not, but I assume the reason is that you aren't specifying a `-f` option and it is defaulting to `-fbin` which will assume `bits 16` by default – Michael Petch Jan 04 '18 at 16:05
  • No idea how I missed the `-m amd64` in the question, I stopped reading at `-a x86` :D – Jester Jan 04 '18 at 16:08
  • Use `-felf64` make 64-bit ELF object files where BITS 64 is the default. Avoid BITS if possible, because it doesn't change the object file format, i.e. it will let you assemble 64-bit machine code into an executable that will be run in 32-bit mode. (Although to link it you'd have to use `gcc -m32` or something. Usually the problem is the other way around when people use `.code32` in gas syntax, where the default is the native mode for the platform, e.g. x86-64). – Peter Cordes Jan 05 '18 at 00:50
  • That is assuming he wants to make an elf executable. I don't know if it was his intention to not use the `-f` option (defaulting to `-f bin`. If this was for an OSDev project then it would make sense but there really isn't enough to know for certain how the code is being used with what is presented. `-felf64` also may make an assumption that he isn't on something like MacOS where they might be using macho64 or Win64 on Windows. – Michael Petch Jan 05 '18 at 03:54
  • Are we sure that yasm actually supports intel syntax? I don't see anything in their docs that says so. The `bits` directive only talks about what code it is going to *generate*, not how it interprets the source. If yasm is interpreting intel syntax as at&t, then the errors above make perfect sense. – David Wohlferd Jan 05 '18 at 05:38

2 Answers2

3

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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
1

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!

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Dr.Gray
  • 11
  • 4
  • And those error that you get are because: 1.) the rbp is 64 and normally it is in 16-32. 2.) the second error comes because the warning from the first error because it could't make the rbp – Dr.Gray Feb 22 '19 at 18:33