Author Topic: nasm + lld-link  (Read 7061 times)

Offline NASM

  • Jr. Member
  • *
  • Posts: 3
nasm + lld-link
« on: September 12, 2018, 11:20:36 AM »
Help me pls import function


Code: [Select]
BITS 64

SECTION .bss

  hSocket:  resq 1

SECTION .data

port: equ 777

struc WSADATA
  .wVersion:  resw 1
  .wHighVersion:  resw 1
  .szDescription:  resb 256
  .szSystemStatus:  resb 256
  .iMaxSockets:  resd 1
  .iMaxUdpDg:  resd 1
  .lpVendorInfo:  resq 1
endstruc

struc sockaddr_in
  .sin_family:  resd 1
  .sin_port:  resd 1
  .sin_addr:  resq 1
  .sin_zero:  resb 8
  .size:
endstruc

SECTION .text

global start

extern WSAStartup
extern WSACleanup
extern socket
extern Sleep

extern ExitProcess
import ExitProcess kernel32.dll

extern accept
extern listen
extern bind

start:

  mov rdx , [WSADATA]
  mov rcx , 0x202
  call WSAStartup
 
  mov r8 , 0
  mov rdx , 1
  mov rcx , 2
  call socket
 
  mov [hSocket] , rax
  mov dword [sockaddr_in.sin_family] , 1
  mov qword [sockaddr_in.sin_addr] , 0
  mov ax , port
  xchg ah , al
  mov [sockaddr_in.sin_port] , ax
  mov r8 , sockaddr_in.size
  mov rdx , [sockaddr_in]
  mov rcx , hSocket
  call bind
 
  mov rdx , 13
  mov rcx , hSocket
  call listen
 
  mov r8 , 0
  mov rdx , [sockaddr_in]
  mov rcx , hSocket
  call accept
 
  mov rcx , 60000
  call Sleep
 
  call WSACleanup
 
  mov rcx,0
  call ExitProcess

C:\msys64\home\Alexey>nasm cmd.asm -f win64 -o cmd.obj
cmd.asm:39: error: parser: instruction expected


https://wasm.in/threads/lld-bsd-exe.32375/#post-402921

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: nasm + lld-link
« Reply #1 on: September 18, 2018, 06:20:42 PM »
There is no "import" directive in NASM... All symbols resolution is made in linking phase...

Offline NASM

  • Jr. Member
  • *
  • Posts: 3
Re: nasm + lld-link
« Reply #2 on: November 08, 2018, 06:25:22 PM »
LLD BSD EXE
Wont write clear browser wif support MSHTML.DLL

WASM.IN FORUM

Offline NASM

  • Jr. Member
  • *
  • Posts: 3
Re: nasm + lld-link
« Reply #3 on: January 19, 2019, 05:45:53 AM »
I still do not understand how to import functions?




pexports C:\Windows\System32\user32.dll > user32.def
dlltool -d user32.def -l user32.lib
« Last Edit: January 19, 2019, 05:49:56 AM by NASM »

Offline debs3759

  • Global Moderator
  • Full Member
  • *****
  • Posts: 221
  • Country: gb
    • GPUZoo
Re: nasm + lld-link
« Reply #4 on: January 19, 2019, 07:10:33 PM »
Import is not a processor directive, it is a macro that generates a series of commands, and it is not part of nasm. If you really need to use it, you will need MASM.
My graphics card database: www.gpuzoo.com

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: nasm + lld-link
« Reply #5 on: January 30, 2019, 07:37:45 PM »
Win32 or Win64 API functions are aliases to the real names, that always end with A or W. The real function name of WSAStartup is WSAStartupA or WSAStartupW.

And you must statically link the DLL surrogate library or load it dinamycally with LoadLibraryA (or LoadLibraryW)...

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: nasm + lld-link
« Reply #6 on: February 01, 2019, 11:06:30 AM »
Here's an example (Win32):

Code: [Select]
; winapp.asm
; NASM code to simple Hello Windows!
  bits 32

%include "win32.inc"

  section .data

winapp_class: db  "MyWinAppClass",0
winapp_title: db  "My Windows App",0
msg_caption:  db  "Error",0
msg_text:     db  "Error creating main window.",0

wc:   istruc WNDCLASS
        at WNDCLASS.style,          dd  (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS)
        at WNDCLASS.hbrBackground,  dd  (COLOR_WINDOW+1)
      iend

msg:  istruc MSG
      iend

  section .bss

hWnd: resd  1

  section .text

; Imported from kernel32.exe & user32.exe
extern __imp__LoadIconA@8
extern __imp__LoadCursorA@8
extern __imp__RegisterClassA@4
extern __imp__CreateWindowExA@48
extern __imp__MessageBoxA@16
extern __imp__UpdateWindow@4
extern __imp__ShowWindow@8
extern __imp__GetMessageA@16
extern __imp__TranslateMessage@4
extern __imp__DispatchMessageA@4
extern __imp__DefWindowProcA@16
extern __imp__PostQuitMessage@4

  global _WindowMessagesHandler@16

struc WndMsgHandlerStk
.oldebp:  resd  1
.retaddr: resd  1
.hWnd:    resd  1
.uMsg:    resd  1
.wParam:  resd  1
.lParam:  resd  1
.size:
endstruc

WNDMSGHANDLERSTKSIZE equ WndMsgHandlerStk.size - WndMsgHandlerStk.hWnd

  align 16
_WindowMessagesHandler@16:
  push  ebp
  mov  ebp,esp

  cmp   dword [ebp + WndMsgHandlerStk.uMsg],WM_DESTROY
  jz    Handle_Destroy

  push  dword [ebp + WndMsgHandlerStk.lParam]
  push  dword [ebp + WndMsgHandlerStk.wParam]
  push  dword [ebp + WndMsgHandlerStk.uMsg]
  push  dword [ebp + WndMsgHandlerStk.hWnd]
  call  dword [__imp__DefWindowProcA@16]
  jmp   HandlerExit

Handle_Destroy:
  push  dword 0
  call  dword [__imp__PostQuitMessage@4]
  xor   eax,eax

HandlerExit:
  pop  ebp
  ret   WNDMSGHANDLERSTKSIZE

  global _WinMain@16

struc WinMainStk
.oldebp:  resd 1
.retaddr:       resd  1
.hInstance:     resd  1
.hPrevInstance: resd  1
.lpszCmdLine:   resd  1
.nCmdShow:      resd  1
.size:
endstruc

WINMAINSTKSIZE equ WinMainStk.size - WinMainStk.hInstance

  align 16
_WinMain@16:
  push ebp
  mov  ebp,esp
  ;-----------------
  ; Registra a classe de janela.
  ;-----------------
  mov   eax,[ebp+WinMainStk.hInstance]
  mov   [wc+WNDCLASS.hInstance],eax

  push  dword IDI_APPLICATION
  push  dword 0
  call  dword [__imp__LoadIconA@8]
  mov   [wc+WNDCLASS.hIcon],eax

  push  dword IDC_ARROW
  push  0
  call  dword [__imp__LoadCursorA@8]
  mov   [wc+WNDCLASS.hCursor],eax

  mov   eax,_WindowMessagesHandler@16
  mov   [wc+WNDCLASS.lpWndProc],eax

  mov   eax,winapp_class
  mov   [wc+WNDCLASS.lpszClassName],eax

  push  wc
  call  dword [__imp__RegisterClassA@4]

  ;-----------------
  ; Cria a nova janela.
  ;-----------------
  push  dword 0
  push  dword [ebp+WinMainStk.hInstance]
  push  dword 0
  push  dword 0
  push  dword 480
  push  dword 640
  push  dword CW_USEDEFAULT
  push  dword CW_USEDEFAULT
  push  dword WS_OVERLAPPEDWINDOW
  push  winapp_title
  push  winapp_class
  push  dword 0
  call  dword [__imp__CreateWindowExA@48]
  test  eax,eax
  jnz   created_ok

  ;----
  ; Em caso de erro com CreateWindowEx...
  ;----
  push  dword (MB_OK | MB_ICONERROR)
  push  msg_caption
  push  msg_text
  push  dword 0
  call  dword [__imp__MessageBoxA@16]
  xor   eax,eax
  jmp   WinMainExit

  ;----
  ; Tudo ocorreu bem com CreateWindowEx...
  ;----
created_ok:
  mov   [hWnd],eax    ; Salva o handle.

  ;---- Update and Show...
  push  eax
  call  dword [__imp__UpdateWindow@4]
  push  dword [ebp+WinMainStk.nCmdShow]
  push  dword [hWnd]
  call  dword [__imp__ShowWindow@8]

MessageLoop:
  push  dword 0
  push  dword 0
  push  msg
  push  dword [hWnd]
  call  dword [__imp__GetMessageA@16]
  test  eax,eax
  jz    ExitLoop

  push  msg
  call  dword [__imp__TranslateMessage@4]

  push  msg
  call  dword [__imp__DispatchMessageA@4]
  jmp   MessageLoop

ExitLoop:
  mov   eax,[msg+MSG.wParam]

WinMainExit:
  pop  ebp
  ret   WINMAINSTKSIZE

The include file:
Code: [Select]
; win32.inc
%define CS_VREDRAW 1
%define CS_HREDRAW 2
%define CS_DBLCLKS 8

%define COLOR_WINDOW  5

%define WM_DESTROY  2

%define IDI_APPLICATION 32512
%define IDC_ARROW       32512

%define CW_USEDEFAULT   0x80000000

%define WS_OVERLAPPED   0x000000
%define WS_CAPTION      0xc00000
%define WS_SYSMENU      0x080000
%define WS_THICKFRAME   0x040000
%define WS_MINIMIZEBOX  0x020000
%define WS_MAXIMIZEBOX  0x010000
%define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)

%define MB_OK 0
%define MB_ICONERROR 0x10

struc WNDCLASS
  .style:         resd  1
  .lpWndProc:     resd  1
  .cbClsExtra:    resd  1
  .cbWndExtra:    resd  1
  .hInstance:     resd  1
  .hIcon:         resd  1
  .hCursor:       resd  1
  .hbrBackground: resd  1
  .lpszMenuName:  resd  1
  .lpszClassName: resd  1
endstruc

struc MSG
  .hWnd:    resd  1
  .message: resd  1
  .wParam:  resd  1
  .lParam:  resd  1
  .time:    resd  1
  .pt:      resd  2
endstruc

The makefile:

Code: [Select]
; Makefile
CC=i686-w64-mingw32-gcc

.PHONY: all clean

all: winapp.exe

winapp.exe: winapp.o
$(CC) -O3 -s -o $@ $^

winapp.o: winapp.asm win32.inc
nasm -f win32 -o $@ $<

clean:
-rm *.o

Compiled with 'make', using mingw32 (linux).

libkernel32.a, libuser32.al and libgdi32.al are linked by default, but winsock2.dll must be linked adding-lws2_32.

The static surrogate libraries to DLLs are in /usr/i686-w64-minw32/. Take a look at them with objdump -x <libfile>.

« Last Edit: February 01, 2019, 12:01:19 PM by fredericopissarra »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: nasm + lld-link
« Reply #7 on: February 01, 2019, 11:48:54 AM »
Of course, for Win64 the calling convention is different and the functions naming are different (there is no @N at the end and the prefix is '__imp_' - with a single '_'). And all Win API function calls are always indirect...
« Last Edit: February 01, 2019, 01:14:08 PM by fredericopissarra »

Offline fredericopissarra

  • Full Member
  • **
  • Posts: 368
  • Country: br
Re: nasm + lld-link
« Reply #8 on: February 01, 2019, 01:53:49 PM »
Ok... the same example for Win64 using mingw64:
Sorry, there are some comments in portuguese (pt_BR)...

Code: [Select]
; winapp.asm
; NASM code for win64
  bits 64
  default rel

%include "win64.inc"

  section .data

winapp_class: db  `MyWinAppClass\0`
winapp_title: db  `My Windows App\0`
msg_caption:  db  `Error\0`
msg_text:     db  `Error creating main window.\0`

wc:   istruc WNDCLASS
        at WNDCLASS.style,          dd  (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS)
        at WNDCLASS.hbrBackground,  dd  (COLOR_WINDOW+1)
      iend

msg:  istruc MSG
      iend

  section .bss

hWnd:     resd  1
nCmdShow: resd  1

  section .text

; Imported from kernel32.exe & user32.exe
extern __imp_LoadIconA
extern __imp_LoadCursorA
extern __imp_RegisterClassA
extern __imp_CreateWindowExA
extern __imp_MessageBoxA
extern __imp_UpdateWindow
extern __imp_ShowWindow
extern __imp_GetMessageA
extern __imp_TranslateMessage
extern __imp_DispatchMessageA
extern __imp_DefWindowProcA
extern __imp_PostQuitMessage

;===============================
; Win64 calling convention:
;   RCX, RDX, R8 and R9 are used for the first 4 arguments,
;   any others goes to stack
;===============================

  align 16
  global _WindowMessagesHandler
; Entry: ECX = hWnd,
;        EDX = uMsg
;        R8D = wParam
;        R9D = lParam (yep... dword).
_WindowMessagesHandler:
  cmp   edx,WM_DESTROY
  jz    Handle_Destroy

  ; All registers are already in place!
  call  qword [__imp_DefWindowProcA]
  ret

Handle_Destroy:
  xor   ecx,ecx
  call  qword [__imp_PostQuitMessage]
  xor   eax,eax

HandlerExit:
  ret


  align 16
  global WinMain
; Entry: ECX = hInstance,
;        EDX = hPrevInstance
;        R8  = lpszCmdLine
;        R9D = nCmdShow
WinMain:
  ;-----------------
  ; Registra a classe de janela.
  ;-----------------
  mov   [wc+WNDCLASS.hInstance],ecx
  mov   [nCmdShow],r9d  ; salva nCmdShow

  xor   ecx,ecx
  mov   edx,IDI_APPLICATION
  call  qword [__imp_LoadIconA]
  mov   [wc+WNDCLASS.hIcon],eax

  xor   ecx,ecx
  mov   edx,IDC_ARROW
  call  qword [__imp_LoadCursorA]
  mov   [wc+WNDCLASS.hCursor],eax

  lea   rax,[_WindowMessagesHandler]
  mov   [wc+WNDCLASS.lpWndProc],rax

  lea   rax,[winapp_class]
  mov   [wc+WNDCLASS.lpszClassName],rax

  lea   rcx,[wc]
  call  qword [__imp_RegisterClassA]

  ;-----------------
  ; Cria a nova janela.
  ;-----------------
  xor   ecx,ecx
  lea   rdx,[winapp_class]
  lea   r8,[winapp_title]
  mov   r9d,WS_OVERLAPPEDWINDOW
  ; Todos os outros parĂ¢metros na pilha (C style)
  push  0
  mov   eax,[wc+WNDCLASS.hInstance]
  push  rax
  push  0
  push  0
  push  480
  push  640
  push  CW_USEDEFAULT   ; nasm warning: Ignore it!
  push  CW_USEDEFAULT   ; nasm warning: Ignore it!
  call  qword [__imp_CreateWindowExA]
  test  eax,eax
  jnz   created_ok

  ;----
  ; Em caso de erro com __imp_CreateWindowEx...
  ;----
  xor   ecx,ecx
  lea   rdx,[msg_text]
  lea   r8,[msg_caption]
  mov   r9d,(MB_OK | MB_ICONERROR)
  call  qword [__imp_MessageBoxA]
  xor   eax,eax
  jmp   WinMainExit

  ;----
  ; Tudo ocorreu bem com __imp_CreateWindowEx...
  ;----
created_ok:
  mov   [hWnd],eax    ; Salva o handle.

  ;---- __imp_Update and Show...
  mov   ecx,eax
  call  qword [__imp_UpdateWindow]

  mov   ecx,[hWnd]
  mov   edx,[nCmdShow]
  call  qword [__imp_ShowWindow]

MessageLoop:
  mov   ecx,[hWnd]
  lea   rdx,[msg]
  xor   r8d,r8d
  xor   r9d,r9d
  call  qword [__imp_GetMessageA]
  test  eax,eax
  jz    ExitLoop

  lea   rcx,[msg]
  call  qword [__imp_TranslateMessage]

  lea   rcx,[msg]
  call  qword [__imp_DispatchMessageA]
  jmp   MessageLoop

ExitLoop:
  mov   eax,[msg+MSG.wParam]

WinMainExit:
  ret

Notice that our functions don't deal with the stack (they have 4 arguments, allocated on RCX, RDX, R8 and R9 only)... This allow us to use a simple RET... Only pointers must be 8 bytes long. Handles are still DWORDs (Win64 uses IL32P64 standard)... When we have to put arguments on stack (before calling CreateWindowExA), this must be done in C style (last argument first), but the 4 first arguments must (if integers) must be passed on RCX,RDX,R8 and R9 registers.

All Win64 API calls are still indirect...

Code: [Select]
; win64.inc
%define CS_VREDRAW 1
%define CS_HREDRAW 2
%define CS_DBLCLKS 8

%define COLOR_WINDOW  5

%define WM_DESTROY  2

%define IDI_APPLICATION 32512
%define IDC_ARROW       32512

%define CW_USEDEFAULT   0x80000000

%define WS_OVERLAPPED   0x000000
%define WS_CAPTION      0xc00000
%define WS_SYSMENU      0x080000
%define WS_THICKFRAME   0x040000
%define WS_MINIMIZEBOX  0x020000
%define WS_MAXIMIZEBOX  0x010000
%define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)

%define MB_OK 0
%define MB_ICONERROR 0x10

struc WNDCLASS
  .style:         resd  1
  .lpWndProc:     resq  1   ; ptrs are 8 bytes long.
  .cbClsExtra:    resd  1
  .cbWndExtra:    resd  1
  .hInstance:     resd  1
  .hIcon:         resd  1
  .hCursor:       resd  1
  .hbrBackground: resd  1
  .lpszMenuName:  resq  1   ; ptrs are 8 bytes long.
  .lpszClassName: resq  1   ; ptrs are 8 bytes long.
endstruc

struc MSG
  .hWnd:    resd  1
  .message: resd  1
  .wParam:  resd  1
  .lParam:  resd  1
  .time:    resd  1
  .pt:      resd  2
endstruc

Code: [Select]
# Makefile
CC=x86_64-w64-mingw32-gcc

.PHONY: all clean

all: winapp.exe

winapp.exe: winapp.o
$(CC) -O3 -s -o $@ $^

# -f win64 is necessary!
winapp.o: winapp.asm win64.inc
nasm -f win64 -o $@ $<

clean:
-rm *.o

When using winsock2 you have to declare __imp_WSAStartup (no A or W, 'cause there are no string arguments) as external, use RCX and RDX as arguments and call it indirectly... You have also to link libwsock32 adding -lwsock32 to the linker.