For my own sick pleasure, I'm writing a small program in x86_64 assembly for Linux. However, I've encountered a segfault that makes absolutely no sense to me, in an instruction comparing an immediate operand to a register. What gives?
Here's the code leading up to the crash:
_start:
sub $8, %rsp
mov %rsp, %rbx
lea le_string(%rip), %rsi
mov %rsi, %rdi
add $8, %rdi
mov $26, %cl
mov (%rsi), %al
cmp 'A', %al /* This line segfaults */
/* snip code that never runs */
le_string:
.ascii "YrFgevat"
I'm assembling with gcc -nostdlib, which is calling the GNU assembler.
Dumping the registers after the crash reveals:
%rsi contains the expected pointer to the string
%al contains the expected first character in the string
%rip points to an instruction that doesn't touch memory
Please ignore the lack of normal calling conventions—I'm not calling out to anything besides the syscall interface, and this crashes before it's even gotten that far!
'A' is being interpreted as an address after all. If you want to use it as a constant, you need to write:
cmp $'A', %al
Related
This question already has an answer here:
Nasm segmentation fault on RET in _start
(1 answer)
Closed 11 months ago.
I wrote some simple assembly code like below:
.global _start
.text
_start:
call _sum
subq $0x8, %rsp
popq %rax
ret
_sum:
ret
In order to get the value of %rax after 'popq' instruction,
I assembled that code using 'as' and 'ld' command.
and I started gdb debugger by putting break point at '_start'
and the result comes like below:
B+> │0x400078 <_start> callq 0x400083 <_sum>
│ │0x40007d <_start+5> sub $0x8,%rsp
│ │0x400081 <_start+9> pop %rax
│ │0x400082 <_start+10> retq
│ │0x400083 <_sum> retq
However, before going into pop instruction,
There comes an error message saying that
Program received signal SIGSEGV, Segmentation fault.
Cannot access memory at address 0x1
(when I changed the $0x8 into $0x0~$0x7, it all worked.)
It seems like at the first stage the sum function might be the problem. because It literally does nothing but return.
So, How can I modify this code to get the value of %rax after the popq instruction?
Thanks.
I think probably this question is a duplicate, but anyway, there is one problem in your code.
.global _start
.text
_start:
call _sum
subq $0x8, %rsp
popq %rax
ret # <-- return to where?
_sum:
ret
A main in C has to can return because _start eventually calls main, but here, you are writing _start directly. It returns to nowhere if you put a ret.
In place of ret, put this instead.
movl $60, %eax # syscall number for sys_exit
movl $0, %edi # or whatever value you want your process
# to return with from 0 to 255;
# xor %edi, %edi is usually better if you want 0
syscall
Leave a comment if it still crashes.
BTW, I was assuming your platform is Linux (because of the AT&T syntax..). The syscalls can be different for a different platform.
I'm trying to learn some assembly, and I'm starting out by outputting text to the screen. I'm starting to think it might be my environment and/or compilation: by now, I'm so frustrated that I've literally copy-pasted assembly code but it just won't call the system calls. Here is the source code (mainly adapted from https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux)
.section .data
msg: .ascii "Hello World\n"
.section .text
.global main
main:
movq $1, %rdi # write to stdout
movq $msg, %rsi # use string "Hello World"
movq $12, %rdx # write 12 characters
syscall # make syscall
movq $60, %rax # use the _exit syscall
movq $0, %rdi # error code 0
syscall # make syscall
I'm on a 64-bit machine running Kali Linux, and am compiling with GCC. Like so:
gcc -c test.s
gcc test.o -no-pie
I've debugged the program with GDB and the syscall instruction always sets the eax register to 0xffffffffffffffda (-38) which does not seem right...
Can anyone give an insight?
Syscalls usually return a negative value in case of error, the absolute value being the errno value itself.
In your case 38is ENOSYS: Function not implemented.
But what syscall function are you calling? Let's see, the function number is stored into rax (eax in 32-bits) before issuing the syscall and your program loads... nothing!
It looks like you lost one line in your copy/paste:
movq $1, %rax ; use the write syscall
Your code is missing the first instruction from the sample code:
movq $1, %rax ; use the write syscall
Without this code, it ends up executing an unexpected (and probably invalid) system call, based on whatever happened to be in %rax when main was called.
I have a basic asm program that checks if a string is a digit. I was adding in code to read from command line arguements, put it keeps seg faulting.
if what I have read is right, this should get the amount of arguments passed to the program, which should be stored in 0(%ebp). What am i doing wrong?
The entirity of the code can be found here: http://pastebin.com/kGV2Mxx4
The problem is the first 3-5 lines of _start.
upon Looking at lscpu's output, I have an i868 cpu. Although, it says it can operate in 32-bit and 64-bit. I am running 32 bit linux (Arch linux x86)
I fixed the issue. I did 2 pop's, one to bypass the programs name, the next to get the first argument. the updated code can be found here: http://pastebin.com/xewyeHYf
Can someone please tell me why I could not just do the following:
pushl 8(%ebp)
or
movl 8(%ebp), %eax
Here is a little tutorial I wrote on the subject:
NASM - Linux Getting command line parameters
You could write this:
_start:
b1: movl 0(%ebp), %eax
cmpl $1, %eax
je load_msg
b2: pushl 8(%ebp)
b4: call check
To understand why your previous attempts didn't work, draw stack diagrams.
Compile a small C program that does something like what you want to do, and compile it to assembly language to find out exactly how to access arguments. The x86_32 code doesn't look at all like any of the above, BTW:
int main(int argc, char *argv[])
{
return argv[1][0];
}
gives (yes, some is superfluous stack bookkeeping, but anyway):
.file "tst.c"
.text
.globl main
.type main, #function
main:
.LFB0:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
movl 12(%ebp), %eax
addl $4, %eax
movl (%eax), %eax
movzbl (%eax), %eax
movsbl %al, %eax
popl %ebp
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 4.7.2 20121109 (Red Hat 4.7.2-8)"
.section .note.GNU-stack,"",#progbits
movl %ebx, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
I use the following asm code to print what is in EBX register. When I use
movl $1,%eax
int 0x80
and the echo $? I get the correct answer but segmentation fault in the first case. I am using the GNU Assembler and AT&T syntax. How can I fix this problem?
Judging by the code, you are probably in 64 bit mode (please confirm) in which case pointers are 64 bit in size. In a position-depended executable on Linux movl $.LC1, %edi is safe and what compilers use, but to make your code position-independent and able to handle symbol addresses being outside the low 32 bits you can use leaq .LC1(%rip), %rdi.
Furthermore, make sure that:
you are preserving value of rbx in your function
stack pointer is aligned as required
This code works for me in 64 bit:
.globl main
main:
push %rbx
movl $42, %ebx
movl %ebx, %esi
leaq .LC1(%rip), %rdi
movl $0, %eax
call printf
xor %eax, %eax
pop %rbx
ret
.data
.LC1: .string "%d\n"
Edit: As Jester noted, this answer only applies to x86 (32 bits) asm whereas the sample provided is more likely for x86-64.
That's because printf has a variable number of arguments. The printf call doesn't restore the stack for you, you need to do it yourself.
In your example, you'd need to write (32 bits assembly):
push %ebx
push $.LC1
call printf
add $8, %esp // 8 : 2 argument of 4 bytes
When assembling a file with GNU assembler I get the following error:
hello.s:6: Error: invalid instruction suffix for `push'
Here's the file that I'm trying to assemble:
.text
LC0:
.ascii "Hello, world!\12\0"
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $LC0, (%esp)
call _printf
movl $0, %eax
leave
ret
What is wrong here and how do I fix it?
The problem is somewhat related to this question although errors and instructions in questions are different.
Prepend .code32 as your first line.
--32 option will change the target to 32 bit platform.
64bit instructions
By default most operations remain 32-bit and the 64-bit counterparts are invoked by the fourth bit in the REX prefix. This means that each 32-bit instruction has it's natural 64-bit extension and that extended registers are for free in 64-bit instructions
movl $1, %eax # 32-bit instruction
movq $1, %rax # 64-bit instruction
pushl %eax # Illegal instruction
pushq %rax # 1 byte instruction encoded as pushl %eax in 32 bits
pushq %r10 # 2 byte instruction encoded as pushl preceeded by REX
Are you assembling with a 64-bit assembler? Your code looks like it's 32-bit. I get this error with your code when using a 64-bit assembler:
example.s:6:suffix or operands invalid for `push'
But it works fine with a 32-bit assembler.
You have to use a "64 bit syntax", or you can use the " --32 " option: by this way the assembler chages its target to the i386 platform.