x86 Assembly pushl/popl don't work with "Error: suffix or operands invalid"

27,944

Solution 1

In 64-bit mode you cannot push and pop 32-bit values; you need pushq and popq.

Also, you will not get a proper exit this way. On 32-bit x86, you would need to set %eax to 1 to select the exit() system call, and set %ebx to the exit code you actually wish. On 64-bit x86 (that's what you are using), conventions are different: the system call number for exit() is 60, not 1; the first system call parameter goes in %rdi, not %rbx; the system-call invocation opcode is not int $0x80 but the special, x86-64-only opcode syscall.

Which leads to:

.section .data
.section .text
.globl _start
_start:
    pushq   $60
    popq    %rax
    pushq   $1
    popq    %rdi
    syscall

(each push/pop sequence can be replaced with a simple mov (like mov $60, %eax) of course; I suppose that you are trying to explicitly test push and pop, optimize for code-size, or avoid 0 bytes in the machine code (for an exploit payload))


Related:

Solution 2

I recently started following these examples too, I found the following worked:

  1. Add .code32 to the top of your assembly code
  2. Assemble with the --32 flag
  3. Link with the -m elf_i386 flag

You can see my example here

Solution 3

You need to replace the push/pop sequence with

pushq $1       # push the value 1 onto the stack
popq %rax      # pop 1 off the stack and into the %eax register

Note the error message is "suffix or operand invalid", you only checked the second part of the logical OR in the error message, maybe because you weren't exactly sure what the suffix means: it's the "l".

Edit: Please see Thomas answer for an explanation why your code won't work anyway even if it assembles.

Solution 4

I ran into this error working through the same book. I created the following shell script (att.sh):

#!/bin/sh
as --32 $1.s -o $1
ld -melf_i386 $1.o -o $1
./$1
echo $?

Which I then made executable and ran (assuming an input file myfile.s):

chmod +x ./att.sh
./att.sh myfile
Share:
27,944
maxm
Author by

maxm

Updated on December 02, 2020

Comments

  • maxm
    maxm over 3 years

    I'm a newbie to assembly programming, working through Programming Ground Up on an Ubuntu x86_64 desktop with GNU assembler v2.20.1.

    I've been able to assemble/link execute my code, up until I get to using pushl/popl instructions for manipulating the stack. The following code fails to assemble:

     .section .data  # empty
    
     .section .text
    .globl _start
    _start:
     pushl $1       # push the value 1 onto the stack
     popl %eax      # pop 1 off the stack and into the %eax register
     int $0x80      # exit the program with exit code '1'
    

    Using "as test.s -o test.o", these errors appear on the terminal and test.o is not created:

    test.s: Assembler messages: 
    test.s:9: Error: suffix or operands invalid for 'push'
    test.s:10:  Error: suffix or operands invalid for 'popl'
    

    I've checked the documentation, and the operands I'm using for pushl and popl are valid. This isn't exactly a debugging question--so what's wrong with my code? Or is it my assembler?

  • maxm
    maxm about 13 years
    thank you, you guys both rock :) and yes, I was just using push/pop to demonstrate the problem, not reinventing mov. Though I was ignorant of the fact that x32 vs. x64 architecture was an issue.
  • maxm
    maxm about 13 years
    Yeah, I think I just mentally blocked the suffix part bcs I had no idea what it meant. Thank you for clarifying
  • FigmentEngine
    FigmentEngine about 13 years
    where would a good reference on the differences between 32/64 be found? i.e. what resource can I use in conjunction with this book to program on 64bit?
  • Thomas Pornin
    Thomas Pornin about 13 years
    You may want to have a look at Intel's manuals: intel.com/products/processor/manuals/index.htm (that's complete and quite readable, but huge).
  • FigmentEngine
    FigmentEngine about 13 years
    thanks Thomas, there seems to be a starting article before this software.intel.com/en-us/articles/introduction-to-x64-assemb‌​ly/…
  • sinceq
    sinceq over 9 years
    In 32-bit instruction, link with the -m elf_i386 flag,the program can run correctly. But how to make it work in 64-bit instruction? stackoverflow.com/questions/25401047/…
  • Peter Cordes
    Peter Cordes over 6 years
    You're totally missing the point. The OP has 32-bit code, and accidentally built it as 64-bit. They want to do a 32-bit push to match the pop %eax as a 3-byte way to set eax=1 Your code would need movzbl (%rsp), %eax to do that. Also, you usually don't want to misalign %rsp like that, because a signal handler could run at any time. And no, you can't always use %rbp; making a frame pointer is optional.
  • Peter Cordes
    Peter Cordes over 6 years
    And anyway, the OP didn't want to avoid push/pop. push $1 works fine in 64-bit mode (as a 64-bit push.)
  • Peter Cordes
    Peter Cordes over 6 years
    You don't need .code32, and in fact should avoid it so you get noisy failure at build time (from instructions like push %eax) if you forget the other 2 steps and build as 64-bit. All .code32 does is let you put 32-bit machine code inside a 64-bit executable, where it will decode "wrong" at run-time. (Or to switch back to 32-bit after .code16 or .code32). If that's not what you want, don't use it! See also building 32-bit executables with 64-bit GNU tools
  • Peter Cordes
    Peter Cordes over 6 years
    The 32-bit int $0x80 ABI is available (but not recommended) in 64-bit mode , so the OP's program does successfully invoke sys_exit(0) instead of crashing. (Linux initializes all the regs to 0 before entering user-space, so EBX will be 0 unless the binary is dynamically linked, in which case it will contain whatever ld.so left.) See What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?