I was experimenting and have the following assembly code, which works very well, except that I get a "Segmentation fault (core dumped)" message right before my program ends:
GLOBAL _start
%define ___STDIN 0
%define ___STDOUT 1
%define ___SYSCALL_WRITE 0x04
segment .data
segment .rodata
L1 db "hello World", 10, 0
segment .bss
segment .text
_start:
mov eax, ___SYSCALL_WRITE
mov ebx, ___STDOUT
mov ecx, L1
mov edx, 13
int 0x80
It doesn't matter whether or not I have ret at the end; I still get the message.
What's the problem?
I'm using x86 and nasm.
You can't ret from start; it isn't a function and there's no return address on the stack. The stack pointer points at argc on process entry.
As n.m. said in the comments, the issue is that you aren't exiting the program, so execution runs off into garbage code and you get a segfault.
What you need is:
;; Linux 32-bit x86
%define ___SYSCALL_EXIT 1
// ... at the end of _start:
mov eax, ___SYSCALL_EXIT
mov ebx, 0
int 0x80
(The above is 32-bit code. In 64-bit code you want mov eax, 231 (exit_group) / syscall, with the exit status in EDI. For example:
;; Linux x86-64
xor edi, edi ; or mov edi, eax if you have a ret val in EAX
mov eax, 231 ; __NR_exit_group
syscall
Related
I am trying to make self modifying code in Linux. I thought it would works but didn't.
section .data
section .text
global _start
_start:
mov eax, 125 ;mprotect syscall number
mov ebx, _start ; *addr
mov ecx, 0x10000 ;page interval.
mov edx, 7 ; rwx permission
int 0x80
jmp modify
target:
mov eax, edx
halt:
mov ebx, 1
mov eax, 1
int 0x80
modify:
mov ebx, [new]
mov [target], ebx
jmp target
new:
mov ebx, 0
I used nasm on ubuntu 18.04.
INT 0x80 return value is -22 0xffffffea
I don't know what is wrong.
Run your program under strace, like strace ./a.out to decode system call args and return values.
Probably your base address isn't page-aligned, or the range includes some unmapped pages. You could round down to a page boundary with and ebx, -4096, or you could align _start by putting align 4096 before it.
Or instead of calling mprotect yourself, you could link your program with ld --omagic to make the text segment read+write+exec.
I'm writing an assembly program that would print even numbers between 0-9 using a loop. I encountered this problem, segmentation fault while running the code. I check other answers on the site but couldn't find an answer that satisfies my issue.
I suspect that the function nwLine might be the source of the problem.
;;this program prints even numbers from 0-8 using loop function
section .text
global _start
cr db 10
_start: ;tell linker entry point
mov ecx, 5
mov eax, '0'
evenLoop:
mov [evnum], eax ;add eax to evnum
mov eax, 4
mov ebx, 1
push ecx
mov ecx, evnum
mov edx, 1
int 80h
call nwLine
mov eax, [evnum]
sub eax, '1'
inc eax
add eax, '2'
pop ecx
loop evenLoop
nwLine: ;function to move pointer to next line
mov eax,4 ; System call number(sys_write)
mov ebx,1 ; File descriptor 1 - standard output
mov ecx, cr
mov edx, 1
int 80h ; Call the kernel
ret
mov eax,1 ;system call number (sys_exit)
int 80h ;call kernel
section .bss
evnum resb 1
if anyone knows how to solve the problem with the nwLine function, please tell me.
Excuse me again. I am trying understand learn assembly languaje. However I have many problems. I am trying working with strings in NASM. I have copy a string constant to string variable. The maximum size is 50. So I want verify this bound. However this program throw a segmentation fault. I use a example in MASM, so perhaps exist a use error with NASM syntax.
My program is the following:
section .data
MAXTEXTSIZE equ 50
_cte_hola db "Hola", 0
_cte_mundo db "Mundo", 0
section .bss
MAIN_d resb MAXTEXTSIZE+1
section .text
global _start
strlen:
mov bx, 0
strl01:
cmp WORD [SI+BX],0 t
je strend
inc bx
jmp strl01
strend:
ret
strcpy:
call strlen
cmp bx, MAXTEXTSIZE
jle copiarsizeok
mov bx, MAXTEXTSIZE
copiarsizeok:mov cx, bx
cld
rep movsb
mov al,0
mov BYTE [DI], al
ret
_start:
mov ds, ax
mov es, ax
mov si, [MAIN_d]
mov di, [_cte_hola]
call strcpy
mov eax, 1
mov ebx, 0
int 80h
Thanks in advance and excuse me. My question are stupid for a assembly programmer.
I believe you are trying to make 32bit program in Linux, but your examples are 16bit.
In Linux, all pointers are 32bit. So, use extended registers: esi, edi, ebx etc. You still can use 8 and 16bit registers for arithmetics and data processing but not as memory pointers.
In strlen you have to compare byte [esi+ebx], 0 not word.
Don't set the segment registers in Linux. They will be set by the OS and you can't touch them. In Linux all memory is one flat area and you don't have to use segment registers anymore.
Here's a more concrete example of how you could write your strlen function (which is the first of your problems)
section .data
MAXTEXTSIZE equ 50
_cte_hola db "Hola", 0xa, 0
_cte_mundo db "Mundo", 0
section .bss
MAIN_d resb MAXTEXTSIZE+1
section .text
global _start
strlen:
mov ebx, 0
strlen_loop:
cmp BYTE [esi+ebx], 0
je strlen_end
inc ebx
jmp strlen_loop
strlen_end:
mov eax, ebx
ret
_start:
mov esi, _cte_hola
call strlen ; Get the length of _cte_hola
mov edx, eax ; The length was stored in eax by strlen
mov ecx, _cte_hola
mov ebx,1
mov eax, 4
int 0x80 ; Write to stdout
mov eax, 1
int 0x80 ; Exit
There are definitely better ways of implementing this (I'd use repne to implement strlen, for example) but I wanted to keep it close to your implementation.
Hope this helps!
I was experimenting and have the following assembly code, which works very well, except that I get a "Segmentation fault (core dumped)" message right before my program ends:
GLOBAL _start
%define ___STDIN 0
%define ___STDOUT 1
%define ___SYSCALL_WRITE 0x04
segment .data
segment .rodata
L1 db "hello World", 10, 0
segment .bss
segment .text
_start:
mov eax, ___SYSCALL_WRITE
mov ebx, ___STDOUT
mov ecx, L1
mov edx, 13
int 0x80
It doesn't matter whether or not I have ret at the end; I still get the message.
What's the problem?
I'm using x86 and nasm.
You can't ret from start; it isn't a function and there's no return address on the stack. The stack pointer points at argc on process entry.
As n.m. said in the comments, the issue is that you aren't exiting the program, so execution runs off into garbage code and you get a segfault.
What you need is:
;; Linux 32-bit x86
%define ___SYSCALL_EXIT 1
// ... at the end of _start:
mov eax, ___SYSCALL_EXIT
mov ebx, 0
int 0x80
(The above is 32-bit code. In 64-bit code you want mov eax, 231 (exit_group) / syscall, with the exit status in EDI. For example:
;; Linux x86-64
xor edi, edi ; or mov edi, eax if you have a ret val in EAX
mov eax, 231 ; __NR_exit_group
syscall
I started assembly (nasm) programming not too long ago. Now I made a C function with assembly implementation which prints an integer. I got it working using the extended registers, but when I want to write it with the x64 registers (rax, rbx, ..) my implementation fails. Does any of you see what I missed?
main.c:
#include <stdio.h>
extern void printnum(int i);
int main(void)
{
printnum(8);
printnum(256);
return 0;
}
32 bit version:
; main.c: http://pastebin.com/f6wEvwTq
; nasm -f elf32 -o printnum.o printnum.asm
; gcc -o printnum printnum.o main.c -m32
section .data
_nl db 0x0A
nlLen equ $ - _nl
section .text
global printnum
printnum:
enter 0,0
mov eax, [ebp+8]
xor ebx, ebx
xor ecx, ecx
xor edx, edx
push ebx
mov ebx, 10
startLoop:
idiv ebx
add edx, 0x30
push dx ; With an odd number of digits this will screw up the stack, but that's ok
; because we'll reset the stack at the end of this function anyway.
; Needs fixing though.
inc ecx
xor edx, edx
cmp eax, 0
jne startLoop
push ecx
imul ecx, 2
mov edx, ecx
mov eax, 4 ; Prints the string (from stack) to screen
mov ebx, 1
mov ecx, esp
add ecx, 4
int 80h
mov eax, 4 ; Prints a new line
mov ebx, 1
mov ecx, _nl
mov edx, nlLen
int 80h
pop eax ; returns the ammount of used characters
leave
ret
x64 version:
; main.c : http://pastebin.com/f6wEvwTq
; nasm -f elf64 -o object/printnum.o printnum.asm
; gcc -o bin/printnum object/printnum.o main.c -m64
section .data
_nl db 0x0A
nlLen equ $ - _nl
section .text
global printnum
printnum:
enter 0, 0
mov rax, [rbp + 8] ; Get the function args from the stac
xor rbx, rbx
xor rcx, rcx
xor rdx, rdx
push rbx ; The 0 byte of the string
mov rbx, 10 ; Dividor
startLoop:
idiv rbx ; modulo is in rdx
add rdx, 0x30
push dx
inc rcx ; increase the loop variable
xor rdx, rdx ; resetting the modulo
cmp rax, 0
jne startLoop
push rcx ; push the counter on the stack
imul rcx, 2
mov rdx, rcx ; string length
mov rax, 4
mov rbx, 1
mov rcx, rsp ; the string
add rcx, 4
int 0x80
mov rax, 4
mov rbx, 1
mov rcx, _nl
mov rdx, nlLen
int 0x80
pop rax
leave
ret ; return to the C routine
Thanks in advance!
I think your problem is that you're trying to use the 32-bit calling conventions in 64-bit mode. That won't fly, not if you're calling these assembly routines from C. The 64-bit calling convention is documented here: http://www.x86-64.org/documentation/abi.pdf
Also, don't open-code system calls. Call the wrappers in the C library. That way errno gets set properly, you take advantage of sysenter/syscall, you don't have to deal with the differences between the normal calling convention and the system-call argument convention, and you're insulated from certain low-level ABI issues. (Another of your problems is that write is system call number 1, not 4, for Linux/x86-64.)
Editorial aside: There are two, and only two, reasons to write anything in assembly nowadays:
You are writing one of the very few remaining bits of deep magic that cannot be written in C alone (a good example is the guts of libffi)
You are hand-optimizing an inner-loop subroutine that has been measured to be performance-critical and the C compiler doesn't do a good enough job on.
Otherwise just write whatever it is in C. Your successors will thank you.
EDIT: checked system call numbers.
I'm not sure if this answer is related to the problem you're seeing (since you didn't specify anything about what the failure is), but 64-bit code has a different calling convention than 32-bit code does. Both of the major 64-bit Intel ABIs (Windows & Linux/BSD/Mac OS) pass function parameters in registers and not on the stack. Your program appears to still be expecting them on the stack, which isn't the normal way to go about it.
Edit: Now that I see there is a C main() routine that calls your functions, my answer is exactly about the problem you're having.