0

I am trying to assemble some 64-bit code and the assembling fails on the line:

addq $0xffffff7fc0005000, %rax

with the error:

Error operand type mismatch for `add'

The first operand is a 64-bit value and the latter a register which should assemble fine. This instruction is preceded by a .code64 pseudo-op. I am assembling with

x86_64-elf-as test.s -o test.o --64

As for the assembler itself, when called with --version it returns:

GNU assembler (GNU Binutils) 2.32
Copyright (C) 2019 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `x86_64-elf'.
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
brenden
  • 574
  • 3
  • 16
  • 2
    huh, that's a confusing error message vs. a warning for an out-of-range / not-encodeable immediate. I'd call that a usability bug. They could easily have written an error message that wouldn't have sent you off to SO to ask a question about it. – Peter Cordes Oct 06 '19 at 17:21
  • 1
    I'm jus curious. Do you happen to be writing a 64-bit OS with a higher half kernel? – Michael Petch Oct 06 '19 at 17:54
  • I ask because previously you asked a question about ensuring something was 0x200 bytes in size. AT the time I believed you might have been writing a custom bootloader. In this question I noticed you are using a cross compiler version of binutils. Something I found interesting is that addq `$0xffffff7fc0005000` almost looks like what someone would do if they were writing a higher half kernel with the kernel in the last 2GiB of virtual address space. If that were true then `addq $0xffffff7fc0005000` is wrong and likely should have been the canonical address `$0xffffffffc0005000` – Michael Petch Oct 06 '19 at 18:54
  • 1
    You wouldn't have gotten an error with `addq $0xffffffffc0005000, %rax` since `$0xffffffffc0005000` can be represented as a 32 bit signed value `$0xc0005000` which when sign extended to 64-bits is also `$0xffffffffc0005000`. (Bit 31 the top most bit of 0xc0005000 is the value 1 so when sign extended all the bits in the 64-bit value take on the value 1). – Michael Petch Oct 06 '19 at 18:59
  • [Can I add 64bit constants to 64bit registers?](https://stackoverflow.com/q/20020589) is the NASM version of the same question. (NASM has a better error message: `warning: signed dword immediate exceeds bounds`) – Peter Cordes Oct 10 '20 at 03:33

1 Answers1

5

The first operand is a 64bit value and the latter a register which should assemble fine.

It shouldn't, the 64bit version of add can take an 8bit or 32bit sign-extended immediate, but not a 64bit immediate, which in general is rare in x64. This can be verified by looking in the Intel Software Developer's Manual or various other places, such as this online copy of the ADD lemma.

The only instruction that can take a full 64-bit immediate (not 32-bit sign-extended) is mov. (Or movabs as GAS likes to call this variant, although with a large numeric constant mov $0x123456789abc, %rcx will pick the necessary encoding, not truncate the number).

Normally you'd mov a 64-bit immediate into a register and then use that.

Another option is to put the value in memory and use it in an add with a memory operand.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
harold
  • 61,398
  • 6
  • 86
  • 164