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 termi开发者_高级运维nal 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?
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:
- What are the calling conventions for UNIX & Linux system calls on i386 and x86-64
- What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?
I recently started following these examples too, I found the following worked:
- Add
.code32
to the top of your assembly code - Assemble with the
--32
flag - Link with the
-m elf_i386
flag
You can see my example here
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.
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
You may push any value without push command like that
decq %rsp
movb $0, (%rsp)
push 1 byte on stack and pop after
movb (%rsp), %al
incq %rsp
And any other size. As compilator don't generate any error and all will work good! To address may use rbp register instead of rsp. Now is allowed.
精彩评论