20

I am trying to study passing arguments into a function via stack in assembly. I am using fedora 20, a 64-bit system.

when I try the following code,

pushl %ebp

popl %ebp

I get the error, Error: invalid instruction suffix for `push'

how will I overcome this error!

i compiled it by, as -ggstabs -o Function_Stack.o Function_Stack.c

AsukaMinato
  • 1,017
  • 12
  • 21
Melvin
  • 301
  • 1
  • 3
  • 7

1 Answers1

40

The error you're getting comes out from a very simple fact : the push instruction in 32-bit mode accepts 16-bit and 32-bit immediates as arguments. However, the push instruction used in 64-bit mode accepts only 16-bit and 64-bit immediates. Since you're clearly compiling your code as 64-bit, the assembler throws an error, since it cannot possibly encode such an instruction. Also, do keep in mind that you force the operand size yourself by adding the l suffix to the push instruction. Everything I just wrote here is exactly the same for pop, except that it accepts registers/memory, not immediates.

However, you also need to keep in mind the differences in the ABI between 32-bit and 64-bit Linux systems. The ABI specifies, among other things, how parameters are passed to functions, and how to call the kernel from user-mode applications. Your code is clearly written for 32-bit mode, seeing how it uses the stack for passing arguments and the (very) obsolete int $0x80 way of invoking syscalls. In order to learn about the 64-bit ABI, see this document.

Alternatively, you have the option of compiling 32-bit code on a 64-bit system. Such an executable will work if you have the necessary 32-bit runtime libraries installed on your 64-bit system. Most distributions allow you to do that in different ways. Your compiler, as, has the --32 switch for emitting 32-bit code.

Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64
  • 8
    I used --32 switch and it created obj successfully. Now it throws error for ld prog.0 -o prog ,ld: i386 architecture of input file `prog.o' is incompatible with i386:x86-64 output. What should be that flag for ld? – Sreeraj Chundayil Apr 30 '15 at 16:07
  • 6
    (just for reference) try using the "-melf_i386"-flag for ld. – Fabio Feb 15 '17 at 16:04
  • 1
    That works fine, but then I get "cannot execute binary file: Exec format error" Guess I can't run it then? =S – Ray Mar 04 '17 at 22:40
  • https://stackoverflow.com/questions/30419857/accessing-a-corrupted-shared-library – John DeBord May 21 '19 at 05:06
  • 1
    In 64-bit mode, push *operand-size* is 16 or 64 (pushw or pushq). But the *immediate* width is either sign-extended-8-bit or sign-extended-32-bit. (Or 16-bit for `pushw` with an immediate that doesn't fit in imm8.) The assembler will pick the immediate encoding for you for an instruction like `push $123`. See also [How many bytes does the push instruction push onto the stack when I don't specify the operand size?](https://stackoverflow.com/q/45127993). As you say, the `l` suffix is setting the operand-size, not the immediate width like NASM `push strict dword 1` – Peter Cordes Mar 15 '21 at 11:52
  • @Ray: `exec format error` sounds like you have a kernel that was compiled without COMPAT_IA32_EMULATION, perhaps WSL1, so it can't execute 32-bit binaries. You can of course use `ld` on such a system to make a 32-bit executable, you just can't run it locally if the kernel won't handle it. (Such kernels also won't accept `int $0x80` system calls from 64-bit code. [What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?](https://stackoverflow.com/q/46087730). So use native 64-bit code and interfaces, or use a different kernel.) – Peter Cordes Jul 10 '21 at 23:19
  • @PeterCordes You're probably right; I don't remember which system I used exactly. Probably some zorin or elementary OS but definitely 64-bit, not sure if they include(d) x86 compatibility. – Ray Jul 11 '21 at 17:45