Essentially what I am attempting to do is make a copy of a file--really, it's a lot more, but I can't get past this first hurdle--using YASM assembly on x86_64 Linux. My problem is that I seem to be unable to use fopen more than once.
My code so far:
segment .data
RW dd "w+", 0 ; RW -- read write (creates)
RO dd "r" , 0 ; RO -- read only
po dq 0 ; po -- pointer original
pn dq 0 ; pn -- pointer new
segment .text
global border
extern fopen
extern fclose
extern fputc
border:
push rbp
mov rbp, rsp
mov r8, rdi ; r8 -- the original file name
mov r9, rsi ; r9 -- the destination file
mov rdi, r8
lea rsi, [RO]
call fopen
mov [po], rax
mov rdi, r9
lea rsi, [RW]
call fopen
mov [pn], rax
mov rdi, "B" ; Just a test to know if worked.
mov rsi, [pn]
call fputc
EXIT:
mov rdi, [po]
call fclose
mov rdi, [pn]
call fclose
mov rsp, rbp
pop rbp
ret
And it's called from the following C program:
char* source = "TestNorm.txt";
char* dest = "TestDest.txt";
border(source, dest);
I've tried a few things, but ultimately it comes down to the second fopen not working--the file is not opened, and I obviously get a seg fault when I try to use the file pointer for it--but the first one works perfectly.
I'm utterly stumped on this one. Any help would be much appreciated.
Related
hope you can help me with that problem. I've to read data from an other file in nasm and I wanted to check the registers value with gdb but I found out that we can't so I hard coded the file value in a "String". I'm pretty sure I did something awful and that's why it isn't working but since I'm a beginner in nasm I am not able to find my mistake.
With that code, isn't eax supposed to be the value of the buffer ? (value of DebugStr in the example) ? Why do I see 0x31313130 ? I really hope you guys can help me
SECTION .data
DebugStr: db "01111100 10101010 01111000", 10
DebugStrLen: equ 32
SECTION .bss
SECTION .text
global _start
_start:
xor rax, rax ; rax = 0
xor rbx, rbx ; rbx = 0
xor rcx, rcx ; rcx = 0
xor rdx, rdx ; rdx = 0
mov r8, DebugStr ; r8 = address of ReadBuffer
mov r9, Output ; r9 = address of OutputBuffer
;mov rax, 0 ; Specify sys_read call
;mov rdi, 0 ; Specify File Descriptor 0: Standard Input
;mov rsi, r8 ; Pass offset of the buffer to read to
;mov rdx, ReadBufferSize ; Pass number of bytes to read at one pass
;syscall
mov eax, [r8] ; eax = ReadBuffer value to eax = 01111100 10101010 01111000
I have a small program in assembler that loads an .so file using dlopen, and then tries to load a function pointer using dlsym. Calling dlopen seems to be fine but it crashes when I call dlsym.
SECTION .text
;default rel
EXTERN dlopen ; loads a dynamic library
EXTERN dlsym ; retrieves the address for a symbol in the dynamic library
; inputs:
; rdi: rdi the pointer to print
printHex:
sub rsp, 19 ; allocate space for the string 0x0123456789ABCDEF\n
mov BYTE [rsp + 0], '0'
mov BYTE [rsp + 1], 'x'
xor rcx, rcx ; int loop variable to 0
.LOOP1:
lea rsi, [rsp + rcx] ; rsi will we the offset where we will store the next hex charcter
mov rax, rdi
and rax, 0xf
sar rdi, 4 ; shift right 4 bits (divide by 16)
lea rdx, [hexLookUp + rax]
mov bl, [rdx]
mov BYTE [rsi +18], bl
dec rcx ; rcx--
cmp rcx, -16 ; while rcx > -16
jne .LOOP1
mov BYTE [rsp + 18], 10
; print
mov rax, 1 ; syscall: write
mov rdi, 1 ; stdout
mov rsi, rsp
mov rdx, 19
syscall
; release stack memory
add rsp, 19
ret
global _start ; "global" means that the symbol can be accessed in other modules. In order to refer to a global symbol from another module, you must use the "extern" keyboard
_start:
; load the library
mov rdi, str_libX11so
mov rsi, 2; RTLD_NOW=2
call dlopen wrt ..plt
; PLT stands for Procedure Linkage Table:
; used to call external library functions whose address is not know at link time,
; so it must be resolved by the dynamic linker at run time
; more info: https://reverseengineering.stackexchange.com/questions/1992/what-is-plt-got
mov [ptr_libX11so], rax ; the previous function call returned the value in rax
mov rdi, rax
call printHex
; load the function
mov rdi, [str_libX11so]
mov rsi, fstr_XOpenDisplay
call dlsym wrt ..plt
mov [fptr_XOpenDisplay], rax
mov rdi, rax
call printHex
mov rax, 60 ; syscal: exit
mov rdi, 0 ; return code
syscall
hexLookUp: db "0123456789ABCDEF"
str_libX11so: db "libX11.so", 0
; X11 function names
fstr_XOpenDisplay: db "XOpenDisplay", 0
SECTION .data
ptr_libX11so: dq 0 ; ptr to the X11 library
; X11 function ptrs
fptr_XOpenDisplay: dq 0
I have tried to make the same program in C and it seems to work. So I must be doing something wrong.
extern void* dlopen(const char* name, int);
extern void* dlsym(void* restrict handle, const char* restrict name);
int main()
{
void* libX11so = dlopen("libX11.so", 2);
void (*XOpenDisplay)() = dlsym(libX11so, "XOpenDisplay");
}
I tried to disassemble the C version and compare, but I can't still figure out what is the problem.
An interesting thing I noticed is that the pointer returned by dlopen (which is different in each execution), in the asm version is quite small compared to the C version (e.g 0x0000000001A932D vs 0x5555555592d0). But maybe that could be because I'm using the -no-pie flag for linking:
nasm -f elf64 -g -F dwarf minimal.asm && gcc -nostartfiles -no-pie minimal.o -ldl -o minimal && ./minimal
I just noticed my mistake:
; load the function
mov rdi, [str_libX11so]
should be:
; load the function
mov rdi, [ptr_libX11so]
I am trying to build a malloc function in assembly. My plan is to use the brk syscall, however in order to do this, I need to be able to know where the end of the current segment is. In c I could use sbrk(0) however this isn't available in assembly. Is there anyway to get the end of the data segment, aside from just putting a label at the bottom.
I am using Ubuntu, nasm, and ld if it helps.
I am assembling and linking with:
nasm -f elf64 mem.s -o mem.o
ld -m elf_x86_64 -o mem mem.o -e _start
mem.asm
global _start
%include "stdasm.s"
section .text
_start:
mov rax, 1
mov rbx, str
call print
mov rax, 0x0123456789ABCDEF
call regPrint
mov rax, end
call regPrint
mov rax, _end
call regPrint
call exit
section .data
str: db 'Hello, world!',0x0A,0
end:
stdasm.s
section .text
exit:
mov rax, 1
mov rbx, 0
int 0x80
print:;rax = fd, rbx = string
push rdx
push rcx
mov rcx, rbx
mov rbx, rax
.loop:
cmp byte [rcx], 0
je .exit
mov rdx, 1
mov rax, 4
int 0x80
inc rcx
jmp .loop
.exit:
pop rcx
pop rdx
ret
regPrint:
push rbx
push rcx
push rdx
xor rcx, rcx
mov rbx, regPrintBuf
.loop:
rol rax, 4
mov dl, al
and rdx, 0x0F
add rdx, hexStr
mov dl, byte [rdx]
mov byte [rbx], dl
inc rcx
inc rbx
cmp rcx, 16
jl .loop
mov rbx, regPrintBuf
mov rax, 1
call print
pop rdx
pop rcx
pop rbx
ret
section .data
hexStr: db '0123456789ABCDEF'
regPrintBuf: db '0000000000000000', 0x0A,0
The linker creates the symbol _end pointing to the end of the data segment at link time. You can use this symbol to find the end of the data segment.
The area allocated by brk is not continuous with the data segment of the executable unless address space layout randomisation is disabled.
To find the current end of this area call brk with an argument of 0. At program start the size is zero so the end address is the same as the start address.
My asm function segfaults at return.
Here is the function prototype : void ft_cat(int fd);
Basically it get a fd from a C main and act like cat shell command.
I get no problem if I removed read and write parts so maybe the problem is around syscalls. I just can't tell. I already spent hours and hours looking for it.
Any clue ?
%define MACH_SYSCALL(nb) 0x2000000 | nb
%define READ 3
%define WRITE 4
%define LSEEK 19
%define STDOUT 1
%define SEEK_CUR 1
section .text
global _ft_cat
_ft_cat:
push rbp ; save base pointer
mov rbp, rsp ; place base pointer on stack
sub rsp, 16 ; align stack to keep 16 bytes for buffering
push rdi ; save function parameter (int fd)
read:
mov rdi, [rsp] ; 1st param - get fd from stack
mov rsi, rbp ; 2nd param - buffer
mov rdx, 16 ; 3rd param - buffer size
mov rax, MACH_SYSCALL(READ)
syscall
cmp rax, 0 ; if read return <= 0 jump to end
jng end
write:
push rax ; save read return
mov rdi, STDOUT ; 1st param
mov rsi, rbp ; 2nd param - buffer
mov rdx, rax ; 3rd param - read return
mov rax, MACH_SYSCALL(WRITE)
syscall
pop rax
cmp rax, 16 ; if read return < 16 then it is finished
je read
end:
mov rsp, rbp ; restore stack and base pointers
pop rbp ;
ret ; return >> segfault
Your allocated buffer is 16 bytes below ebp but you pass ebp to the read syscall so you overwrite the saved rbp, the return address and other things in the caller's frame. You want lea rsi, [rbp-16] instead.
I am writing a program in AMD64 linux Assembly code (assembler Nasm) that does a whole bunch of stuff. Basicly, my question right now is how can I open a file, and write some data to it.
My code I have seems like it should work.
Basically I want to open a .ppm image file and write the header to it. My professor gave me some pseudo code to to help and here is that code for just the part I am trying to accomplish.
fd = open("gradient.ppm", 577, 0o644)
if fd < 0: return 1 (error)
bufsize = writeHeader(buffer, 256, 256)
status = write(fd, buffer, bufsize)
if status < 0: return 2 (error)
Here is my code. My professor has some test program written in c++ that will run my code and test to see if it works correctly, so I am not running directly from this file. (BTW, the writeheader file has been confirmed to work)
global start
extern writeRGB
extern writeHeader
section .data
filename: db "gradient.ppm",0
section .bss
buffer resb 5000
section .text
; rdi,rsi,rdx
start:
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
; open file
; sys_open: rax=2, rdi=char filename, rsi=int flags, rdx=int mode
mov rax, 2 ; 2 is system call number for sys_open
mov rdi, filename ; filname is in data section
mov rsi, 577 ; flag that is just given to me
mov rdx, 0o644 ; Octol number of the mode that is just given to me
syscall ; execute the sys_open system call
mov r9, rax ; r9 will hold file handle (fd)
; check for error
; compare 0 and data returned to rax from opening file.
; if data in rax < 0, store 1 in r11 and jump .error which will return the 1
mov r11, 1
cmp r9, 0
jl .error
; call writeheader
; writeHeader(rdi = buffer, rsi = 256, rdx = 256)
mov rdi, buffer
mov rsi, 256
mov rdx, 256
call writeHeader
mov r8, rax ; store the buffer size (bufsize) in r8
; status = write(fd, buffer, bufsize)
; sys_write: rax=1, rdi=fd, rsi=buffer, rdx=bufsize)
mov rax, 1 ; 1 is the system call number for sys_write
mov rdi, r9 ; the file handle (fd) is stored in r9
mov rsi, buffer ; the buffer is in the .bss section
mov rdx, r8 ; r8 holds the buffer size (bufsize)
syscall ; execute the sys_write system call
mov r10, rax ; status will be stored in r10
; check for error
; compare 0 and data returned to rax from opening file.
mov r11, 2
cmp r9, 0
jl .error
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
mov rax, 0
ret
.error:
; mov error code in r11 into rax to indicate error, and return it
mov rax, r11 ; rll holds error code
ret
If my code should work, then there is probably something wrong in which the way the test file is accessing it, if thats the case just let me know so that I can focus my resources on fixing that problem rather than fixing my code that already works.
cmp r9, 0
jb .error ; <-- This will never happen!
When testing for a negative number don't use jb. That's reserved to work with unsigned numbers. Use jl.
cmp r9, 0
jl .error
;open file give it a name in section .data file: db "......", 0
mov rsi, 577
mov rdx, 0o644
mov rdi, file
mov rax, sys_open
syscall
mov r13, rax ;save file descriptor
cmp rax, 0 ;return error if negative
jl .error
Copy/paste related error in your code!
; status = write(fd, buffer, bufsize)
; sys_write: rax=1, rdi=fd, rsi=buffer, rdx=bufsize)
mov rax, 1 ; 1 is the system call number for sys_write
mov rdi, r9 ; the file handle (fd) is stored in r9
mov rsi, buffer ; the buffer is in the .bss section
mov rdx, r8 ; r8 holds the buffer size (bufsize)
syscall ; execute the sys_write system call
mov r10, rax ; status will be stored in r10
; check for error
; compare 0 and data returned to rax from opening file.
mov r11, 2
cmp r9, 0
jl .error
You have put the status in R10 but are comparing the value in R9.