Recent Posts

Pages: 1 [2] 3 4 ... 10
11
Programming with NASM / Relocatable code for .SO and .DLL libraries (Mixed C/C++/ASM)
« Last post by kanito73 on February 17, 2019, 04:19:44 AM »
Hello

I am developing a C++ library that requires some external assembly functions to be included.

Currently, the C/C++ functions are being declared this way (generic format, not the exact code):

-------------------------------------------------------------------
#if defined _WIN32
   #define DLL_ENTITY __declspec(dllexport)
#endif

#if defined _WIN32
   DLL_ENTITY
#endif
int Function (int argument);
-------------------------------------------------------------------

and compile it (using a Makefile) with GCC using the -fPIC flag to create relocatable code that can be used from the programs linked to my library. For example (one command output of my Makefile):

   g++ -I`pwd`/.. -Wall -fPIC -march=x86-64 -mtune=generic -g -c sort.cpp

and in Windows I create and configure a project with executable format DLL option in Visual Studio, then it does all the job.

Okay, my assembly functions look like this:

-------------------------------------------------------------------
global function
global _function
function:
_function:
      ENTER reserved_bytes,nest_level
      ; ...get possible parameters...
      ; ...do something...
      LEAVE
      ret
-------------------------------------------------------------------

Well, according to the NASM manual, for the Windows DLL libraries I must add something like:

   export function

My doubts are these:

1) For Linux it does not mention nothing about 'export', I guess it is the same way as the C/C++ function/class prototypes that do not require any special treatment, they are declared in the same way as in standalone programs. Is it right? Just use 'export' for Windows and nothing for Linux?

2) What about the relocatable code generation? For Windows, the 'export' keyword makes it relocatable or JUST EXPORTABLE? And for Linux, do I need to use some flag equivalent to -fPIC or I must create the relocatable code by using BASED addressing? For example:

      add WORD[BP+myNumber],10h

         instead of

      add WORD[myNumber],10h

but in this case, how can I find the base address of the function to set BP (EBP/RBP) to it?

12
Programming with NASM / Re: Interfacing NASM with g++ and VC++ 2017
« Last post by kanito73 on February 16, 2019, 06:13:20 PM »
Thanks a lot for your time and patience to write!

Now everything is clear as water... I will test on code to finally develop my library functions.

Have a nice day!  =-)
13
Programming with NASM / Re: Interfacing NASM with g++ and VC++ 2017
« Last post by fredericopissarra on February 16, 2019, 10:46:53 AM »
Hello...

1. If I pass a pointer from C++ to ASM, is it considered an INTEGER VALUE and it is passed into the registers RCX/RDX/R8/R9 (or the stack if necessary) as a normal number? And if so, is it only the OFFSET and the current DATA SEGMENT is assumed to contain the data?

Pointers are normal integer values and these integer values are used as memory addresses. Their sizes depends on the architecture.

In x86-64 mode all addresses are 64 bits in size (but only 48 bits are used - 52 if PSE is enabled for a page). The remaining bits must be a copy of the last valid bit (this is called "cannonical addressing" - take a look at topic 3.3.7 on Intel's "Software Development Manual, vol 1"). For exemple, this address is cannonical: 0x7fffffffffff; but this is not: 0x800000000000, because only bits 0~47 are valid and in the later case bit 48=1. The cannonical address here is 0xffff800000000000).

It is useful to know abour cannonical addressing, but with 48 bits it's possible to address 256 TiB of memory!!! And with 52 bits, 2 PiB!!! Without worrying about cannonization! :)

Also, in x86-64 mode no selector registers are used, except CS (only to hold the Current Privilege Level), FS and GS. The memory is always flat regarding segmentation. The protection is enforced by the paging mechanism. Take a look at any simple program with GDB and you'll see something like this:

Code: [Select]
(gdb) l
1   bits 64
2   default rel
3
4   global _start
5 _start:
6   xor   edi,edi
7   mov   eax,60
8   syscall
(gdb) b 6
Breakpoint 1 at 0x400080: file test.asm, line 6.
(gdb) r
Starting program: /mnt/vol2/Work/tmp/test

Breakpoint 1, 0x0000000000400080 in _start ()
(gdb) info registers
rax            0x0 0
rbx            0x0 0
rcx            0x0 0
rdx            0x0 0
rsi            0x0 0
rdi            0x0 0
rbp            0x0 0x0
rsp            0x7fffffffdcf0 0x7fffffffdcf0
r8             0x0 0
r9             0x0 0
r10            0x0 0
r11            0x0 0
r12            0x0 0
r13            0x0 0
r14            0x0 0
r15            0x0 0
rip            0x400080 0x400080 <_start>
eflags         0x202 [ IF ]
cs             0x33 51
ss             0x2b 43
ds             0x0 0
es             0x0 0
fs             0x0 0
gs             0x0 0

See that DS-ES are all zero? CS and SS holds information used by the kernel, but the processor will ignore everything, except the RPL field of CS.

2. If I need to pass different size arguments (byte, word, dword, qword), are they passed as full 64-bits values and just have to extract the required size, for example CL, CX, ECX or RCX according to the parameter size in C++? And, I suposse that no matter if it is a signed or unsigned value, the assembly function processes the value in the required way depending on the expected data size, let be an unsigned integer or a signed integer (maybe in two's complement if highest bit is set)?

Yes, but you don't need to initialize all 64 bits. For instance:
Code: [Select]
int f(int x) { return x+x; }
...
y=f(10);

Creates code like this:

Code: [Select]
f:
  ; The compiler uses RDI here to avoid insering an extra prefix
  ; to the instruction (0x67). Otherwise, the instruction could be
  ; lea eax,[edi+edi].
  lea   eax,[rdi+rdi]
  ret
...
mov edi,10    ; EDI, not RDI!
call f
...

For byte sized arguments there are aliases to RDI and RSI: DIL and SIL.

If an integer is interpreted as signed or unsigned is a matter of using the flags. All integer arithmetic is done if the data is unsigned and sets CF and OF accordingly.

[]s
Fred
14
Programming with NASM / Re: Interfacing NASM with g++ and VC++ 2017
« Last post by kanito73 on February 16, 2019, 04:07:03 AM »
Hi !!!

Thanks for your response. I just opened the link and the tutorial appears to be pretty complete. I think it will be a good idea to read it entirely.

Thanks!!!

No problem. Feel free to post a comment on the blog or ping me on Twitter if something doesn't make sense!


Hello

I'm still reading your tutorial, it is very complete and illustrative, congratulations! Finally reached the "The Microsoft x64 Calling Convention" and I have two doubts.

1. If I pass a pointer from C++ to ASM, is it considered an INTEGER VALUE and it is passed into the registers RCX/RDX/R8/R9 (or the stack if necessary) as a normal number? And if so, is it only the OFFSET and the current DATA SEGMENT is assumed to contain the data?

2. If I need to pass different size arguments (byte, word, dword, qword), are they passed as full 64-bits values and just have to extract the required size, for example CL, CX, ECX or RCX according to the parameter size in C++? And, I suposse that no matter if it is a signed or unsigned value, the assembly function processes the value in the required way depending on the expected data size, let be an unsigned integer or a signed integer (maybe in two's complement if highest bit is set)?

Regards,
and again, congratulations for your tutorial!
15
Programming with NASM / Re: Interfacing NASM with g++ and VC++ 2017
« Last post by sonictk on February 15, 2019, 10:44:35 PM »
Hi !!!

Thanks for your response. I just opened the link and the tutorial appears to be pretty complete. I think it will be a good idea to read it entirely.

Thanks!!!

No problem. Feel free to post a comment on the blog or ping me on Twitter if something doesn't make sense!
16
Programming with NASM / Re: Interfacing NASM with g++ and VC++ 2017
« Last post by kanito73 on February 15, 2019, 06:31:52 PM »
Hi !!!

Thanks for your response. I just opened the link and the tutorial appears to be pretty complete. I think it will be a good idea to read it entirely.

Thanks!!!
17
Programming with NASM / Re: Interfacing NASM with g++ and VC++ 2017
« Last post by sonictk on February 15, 2019, 06:11:12 PM »
Hi there:

I _just_ wrote a tutorial about working with x64 assembly on Windows that covers this topic:

https://sonictk.github.io/asm_tutorial/

You can skip to the "Using assembly in C/C++ programs" section, or take a look at the code samples and build scripts in the accompanying code repository for the tutorial.

Hope this helps!
18
Programming with NASM / Re: I have a problem with a simple 64bit programm
« Last post by fredericopissarra on February 15, 2019, 01:28:35 PM »
Instead of using glibc functions, you can create a standalone asm application. Instead of using atoi and printf, you can create your own atoi and printf routines. The question is how to get argc and argv?

They are pushed on stack by the kernel RSP points to argc and RSP+8 points to argv:

Code: [Select]
$ nasm -f elf64 -g -o args.o args.asm
$ ld -o args args.o
$ gdb -q args
Reading symbols from args...done.
(gdb) l
1   bits  64
2
3   section .text
4
5   global  _start
6
7 _start:
8   xor   edi,edi       ; syscall_exit(0)
9   mov   eax,60
10   syscall
(gdb) b 8
Breakpoint 1 at 0x400080: file args.asm, line 8.
(gdb) r
Starting program: /home/frederico/MyStuff/tmp/args

Breakpoint 1, 0x0000000000400080 in _start ()
(gdb) p *((int *)$rsp)
$1 = 1
(gdb) p ((char **)($rsp+8))[0]
$2 = 0x7fffffffdf4f "/home/frederico/MyStuff/tmp/args"
(gdb) p ((char **)($rsp+8))[1]
$3 = 0x0

So, after _start, you can do:

Code: [Select]
  mov  ecx,[rsp]  ; ECX = argc
  mov  rsi,[rsp+8]  ; RSP = argv
  mov  rbx,[rsi+8]  ; RBX = argv[1]

You can ignore argc and test if RBX is zero (NULL), meaning thare is only one argument on the command line:

Code: [Select]
_start:
  mov  rsi,[rsp+8]
  mov  rbx,[rsi+8]
  test rbx,rbx
  je   .only_arg0_error
  ...

***

To speed up the primalty test you can check only odd values lesser of equal to square root of the number.
A good square root routine for integers is this one: https://en.wikipedia.org/wiki/Integer_square_root.

atoi() is simple to implement (if you don't care with input validation): Initializing the result to 0, for each char, get the correspondent value and add to the previous times 10.

To simulate puts() you can use write syscall, writing to stdout (descriptor 1). To write a decimal number on screen it is only a matter of get the reminder of it by 10 and fill an array. Once filled, print the chars backwards.

This way, your code will be glibc free.
19
Programming with NASM / Interfacing NASM with g++ and VC++ 2017
« Last post by kanito73 on February 15, 2019, 04:42:29 AM »
Hello friends

Today is the time to interface NASM with C++ using g++ and VC++ (2017). Do you know of a tutorial that I can use?

The examples in the manual demostrate how to call assembly functions and how to pass numerical arguments, but in particular I need to pass pointers to strings and data buffers from C++ to ASM. And also require to see how to link the object file in Windows using VC++, for Linux it already shows how to do it.

In advance, thanks for your help and comments
20
Programming with NASM / Re: I have a problem with a simple 64bit programm
« Last post by Renegade on February 15, 2019, 12:18:31 AM »
Yo guyz,
I rewrote the code.
And it's running very good !
Check this out.  ;D ;D ;D ;D

Code: [Select]

;compiled with
;nasm -f elf64 prime64.asm && gcc -static -O3 prime64.o -o prime64

global main
extern printf
extern puts
extern atoi

section .text

main:
push r12 ;free r12
push r13 ;free r13
push r14 ;free r14

cmp rdi, 2 ; check if program+one arguments are given
jne error1 ; when rdi is not 3 jump to error1

mov r12, rsi ; mov argv to r12
mov rdi, [r12+8] ; mov argv[1] (number) in rdi
call atoi WRT ..plt ; convert to integer (returns to eax)
cmp eax, 2 ; compare it to 0
jl error2 ; if less than 0 jmp to error2
inc eax
mov r13d, eax ; biggest number
mov r12d, 2 ; divisor
xor r11d, 0

case2:
mov eax, 2 ; dont check if two is prime ;)
jmp first

primecheck2:
inc r14d ;actual number is in r14d
xor edx, edx ;f*** that we exclude divisibles trough 2 directly
mov eax, r14d
mov ecx, 2
div ecx
cmp edx, 0
je notprime
mov r12d, 2 ; r12d is the register which holds the divisor

primeloop:
xor edx, edx
inc r12d ; increment the divisor
cmp r12d, r14d ; is our number the divisor ? --> prime
je isprime
mov eax, r14d
mov ecx, r12d
div ecx
cmp edx, 0 ; we check remainder if its zero ? true == notprime
je notprime
jmp primeloop ; loop again

notprime:
cmp r14d, r13d ; are  we done ?
jl primecheck2 ; if not test next number
jmp done
isprime:
mov eax, r14d ; first time we print 2 directly (yeah it looks ugly) :(
first:
mov rdi, answer1 ; write ansswer to the rdi
movsxd rsi, eax ; mov eax with sign extension to rsi (conversion to 64 bit number)
mov r14d, eax ; r14d contains the actual number to check
xor rax, rax ; xor a register to itself sets it to 0
call printf WRT ..plt ; call printf
cmp r14d, r13d
jl primecheck2
jmp done

error1:
mov edi, badArgumentCount
call puts WRT ..plt ; print out badArgumentCount
jmp done

error2:
mov edi, numberUnderTwo ; the lowest prime number is 2 !
call puts WRT ..plt

done:
pop r14 ; take the values of these register from
pop r13 ; the stack to set them, how they were before
pop r12 ; running the proggy
ret ; return
 



section .data



answer1:
db "%d", 10,  0
badArgumentCount:
db "Requires exactly one argument!", 10, 0
numberUnderTwo:
db "The Number may not be under 2, because it is the lowest prime !.", 10, 0



Best regards Renegade
Ps: It would be cool to increase the speed, i will do that in future ! I will advance the algorithm. 
Pages: 1 [2] 3 4 ... 10