1 / 49

Introduction to Libraries in Programming

Understand the concept of libraries in programming, including their types and how they can be used for code reuse. Learn about static and dynamic linking, advantages and disadvantages, and the steps to use libraries in assembly language.

charleyb
Download Presentation

Introduction to Libraries in Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Multi-modules programming mvanta@bitdefender.com

  2. 4. Libraries

  3. Introduction • Library = a separate collection (module) of code and data resources, meant to be reusedacrossmultiple programs or by multiple modules of the same program • The allowed/contained resources can be subroutines, classes and objects (OO languages), documentation, user manuals, audio and video items etc... • Each published resource must be uniquely identifiable • They usually have associated unique names but other methods can also be used (such as numerical identifiers) • For proper reuse, the behavior and interfaces have to be well documented! • User-mode applications are supervised by the OS and can only perform some critical operations through the system libraries • Hardware resources: keyboard, disk (files), network, audio/video etc... • Software resources: threads, memory and application management etc...

  4. Key concepts • Linkediting • Link-time static linking • Dinamic linking at load-time and run-time • Object file formats • Relocatable Object Module Format (OMF) • A MS-DOS dedicated file format (16 bits) with 32 bits compatibility • nasm.exe -fobj și alink.exe • Common Object File Format (COFF) • A more recent file format embraced by Windows, Unix and EFI • Used by Microsoft across the whole build toolchain • nasm.exe -fwin32and link.exe • Library types • Static libraries (LIB) • Import libraries (import LIB) • Dynamic libraries (DLL) • Relevant nasm directives: global, extern / import and export

  5. Keyconcepts • Load-time dynamic linking • The sole information needed by the linker is where the resources are located • OMF: their provenienceis specified via the NASM directive import • COFF: such information is described by an import LIB • The resources are not contained inside, it merely provides directions to a DLL • The resulting program won’t embed the resources, but instead, it will only reference their names and the library file (.dll) they’re part of • The OS (the program loader) is responsible for the actual linking • Advantages: • Reduced program size • Same resources are available to multiple programs without need for duplication • Disadvantages: • A DLL file is specifically neededas other .obj or .lib files can’t be dynamically linked • Complex and time consuming processing is performed right at program start-up • Potential version incompatibilities can’t be known beforehand and they’re only detected when trying to run the application

  6. Keyconcepts • Runtime dynamic linking • The needed resources are only loaded when explicitly requested and kept for only as long as they’re actually wanted • The requests originate on the application side and are handled by the OS • Dynamic linking against kernel32.dll is needed at load-time for a handful of essential system subroutines: • LoadLibrary: load a DLL at runtime • GetProcAddress: search for a resource by its name • FreeLibrary: unload and free the DLL resources • The linker has no direct involvement throughout the run-time linking process! • Advantages: • The program starts faster and may need less memory • Allows keeping active in memory only the code and data needed for the current activities • Behavior can be altered on-the-fly by loading different or updated (DLL) modules • Disadvantages: • Versioning issues are determined even later, at run-time, and data loss is likely without proper care

  7. Keyconcepts • Overview–module inclusion and linking options • How to decide between them? • Small ASM-only program? %include is an option, although, it’s not recommended… • Self-contained stand-alone program? Static linking is the only way for achieving the result! • For every other case dynamic linking is recommended • Load-time dynamic linking is easier to use and less error-prone • A mix of load-time + run-time dynamic linking should be used for faster application load time and/or for supporting plugin-able application modules or on-the-fly updates

  8. Key concepts • Overview – the link-editing workflow source 1 obj 1 Stack static library LIB source 2 compiler / assembler obj 2 librarian ... source N obj N static import EXEcode + data source 1 obj 1 application EXE uninitialized data Loader source 2 compiler / assembler obj 2 linker ... source N obj N DLL dynamic import at load-time source 1 obj 1 import library LIB ... source 2 compiler / assembler obj 2 linker ... dynamic, run-time import dynamic library DLL source N obj N

  9. Using libraries in ASM – the necessary steps • Find the name of the wanted subroutine in the library documentation • This applies in the same manner for other resource types too • Except for this very first step, which is generic and applies to any resource type, all of the steps that follow are not applicable to anything other than functions! • Extract from the function’s documentation the following info: • The calling convention • The name, type and meaning of each parameter • The associated type and meaning of the returned result • The file (orfiles) required for accessing the function, namely: • .DLL/.LIB: the dynamic (or static!) library file containing the function • .LIB: the import librarywhich is necessary alongside the DLL (for COFF only) • .H: although the header files are meant to be used by C programs, due to the rigorous nature of the types and constants definitions contained, it often proves useful even when writing ASM code, and especially so if the documentation doesn’t cover all the technical details an ASM program needs…

  10. Using libraries in ASM – the necessary steps • Let the assembler know this is a library function • For the OMF only, an import statement is needed to specify the DLL file: • Tag the function’s name as being external, having no local implementation • Perform the function call • The OMF format provides the imported symbols as function pointers, needing to be dereferenced! • For the COFF scenario, the imported symbols behave like the usual ASM function labels See Interfacing with high-level languages for more details and the required steps for subroutine calls Important: the function name being used throughout the NASM source code must account for the correct name mangling required (as seen in the multi-module program asm + C example) importfunction file.dll externfunct call [function]; like having a functiondd function_addressvar call function; similar to having a function: ... ASM function

  11. Using libraries in ASM – the necessary steps • Assembling the NASM source code • OMF: nasm.exe -fobj file.asm • COFF: nasm.exe -fwin32 file.asm If there are more files, this command must be issued for each one individually • Linking the object files • OMF: alink.exe file.obj -oPE -entry start -subsys console • Multiple files can be passed all at once, separated by whitespaces • COFF: link.exe file.obj library.lib -entry:start -subsystem:console • The .lib file corresponds to the import library identified at step 2.d) • Any number of import libraries can be specified, separated by space characters For building a library this step is different (see implementing user libraries) • Running the application (or using the resulting library) • Starting the program: file.exe • Debugging: ollydbg.exe file.exe • Library: repeat all steps for each new program that’s making use of the library

  12. System libraries(Win32) • Purpose: an abstraction layer over the OS and hardware complexity • All system libraries are dynamic (DLL files) • Offered as part of any standard Windows installation • kernel32.dll, user32.dll, ntdll.dll, shell32.dll etc... • Operations: • In/Out: console,windows, mouse andkeyboard, network • Process management: create,terminate, change priority • Memory management: allocate, free, share, change access rights • Files and folders: create, read, write, list, delete • Parallel processing: synchronization, threads management • ... Similar functionality is offered by other OSes as part of their own (different) system libraries

  13. System libraries (Win32)- properties • STDCALL is the usual calling convention for all functions • Numeric types: BYTE/WORD/DWORD/QWORD • Character strings: LP[C]STR, LP[C]WSTR, LP[C]TSTR • C = constant • W = wide string (UNICODE), otherwise ANSI/ASCII encoding is implied • T = both UNICODE and ASCII forms available (via two different implementations) • All strings are NULL terminated (C-like strings) • Conventions: • The GetLastError() function returns the reason for the last failed operation • HANDLE: black-box numerical type associated with some OS-managed resources • TheCloseHandle() subroutine can (usually) free the resources linked to (identified by) a HANDLE • NameAandNameW : the two different implementation of the same function Name, the formerbeing ANSI-friendlywhile the latter is wide/UNICODE (UTF-16) tailored

  14. System libraries (Win32) - File management • The files are seen as devices providing sequential-access to data • They have a current position associated, pointing to the next byte to process • They don’t necessarily reside on a disk drive and can model other devices too • The HANDLE returned when opening a file is needed for any actions • CloseHandle is used for freeing resources and saving any changes • Path specifier: a string that identifies a unique node in a files and folders tree • It defines the folder nodes that need to be traversed for arriving at a desired node • Absolute path: any path specifier starting from the very root node of the tree • The root name is, usually, a drive letter (such as C, D etc...) • Path specifier example: C:\Windows\System32\calc.exe • Relative path: a path starting at some other, already known, node of the tree • Example: System32\calc.exe • Path separators: • collon(:) betweenthe drive letter and the rest of the path • Backslah (\) for separating the folder names walked across the path (and between the last folder and a file name)

  15. System libraries (Win32) - File management • Relevant functions: • CreateFile: create (or open an existing) file • GetFileSizeEx: requests the number of bytes occupied by the given file • SetFilePointer: (re)position the file position at the specified byte index • ReadFile: read data from file to a memory buffer • WriteFile: save the content of the memory buffer to the file • CopyFile: create a copy of a file • MoveFile: move a file to a different folder/location • FindFirstFile/FindNextFile/FindClose:iterate all files matched by a (glob) name pattern • CreateDirectory: create a new folder • RemoveDirectory: delete an existing folder • GetCurrentDirectory: retrieve the working directory of the application • Working folder: all relative paths are, by default, considered as starting here (at this tree node) • Each program has its own working directory, set by the OS when the .exe is loaded • SetCurrentDirectory: change the current working directory to point to a different folder • Remarks • Powerful but complex (many parameters) => it’s important to read their documentation! • They’re all exported by kernel32.dll • Both ANSI and UNICODE versions are available for all the functions having strings as inputs • The C standard library functions are, in the end, wrappers over these functions

  16. System libraries- File management examples • Following the steps for calling CreateDirectoryA– 1 – • We retrieve the function’s name, if not already known • Inspecting the official docs (https://docs.microsoft.com/) for Windows Desktop applications,there’s a Windows API Reference where we can find function names grouped by common functionallity • Data access and storage → Local File Systems → Directory Management → Directory Management Reference → Directory Management Functions →CreateDirectory • Extracting subroutine information • The name, typeand parameter meanings (STDCALL implied)

  17. System libraries- File management examples • Following the steps for calling CreateDirectoryA– 2– • Info about the type and meaning of the returned value • The list of necessary (or related) files for using the function • DLL: the dynamic-link library containing the implementation • Library: import library (useful/necessary only for COFF builds) • Header: C header file describing the involved data types and symbolic constants

  18. System libraries- File management examples • Following the steps for calling CreateDirectoryA– 3– • Add the required NASM declarations • For OMF, the library name must be specified by using the importdirective • Declare the function extern as there’s no local implementation provided • OMF • COFF • Important: COFF enforces C++name mangling! • Perform the function call • For OMF, the function pointer needs to be dereferenced by the call instruction • COFF treats the function name directly as a label See Interfacing with high-level languages for a complete description of the call requirements importCreateDirectoryAkernel32.dll externCreateDirectoryA extern_CreateDirectoryA@8 call[CreateDirectoryA]; similar to a CreateDirectoryA dd address_of_code call_CreateDirectoryA@8; just like an asm CreateDirectoryA: ... function

  19. System libraries- File management examples • Following the steps for calling CreateDirectoryA– 4– • Assembling the NASM code • OMF: nasm.exe -fobj file.asm • COFF: nasm.exe -fwin32 file.asm Repeat the command individually for each file if there are more than one files • Linking the object file(s) • OMF: alink.exe file.obj -oPE -entry start –subsys console • (whitespace separated) multiple .obj file names can be sent at once • COFF: link.exe file.obj kernel32.lib -entry:start -subsystem:console • Kernel32.lib is the import library file from 2.d) • As many import libraries as needed can be specified (separated by whitespaces) See Implementing user libraries if building a library instead of an .exe file! • Running the program (or,using the library) • Run: file.exe • Debug: ollydbg.exe file.exe • Library: repeat the steps for a new program

  20. System libraries– File management examples • OMF: Creating a ”temp” sub-folder in the current working directory ; exemple1.asm importCreateDirectoryAkernel32.dll; the import directory is OMF-specific! importexit msvcrt.dll externCreateDirectoryA, exit segmentcodeuse32 globalstart start: pushdwordnume; first parameter – the name of the folder pushdword 0 ;lpSecurityAttributesis optional, it can be NULL call [CreateDirectoryA] ; an ASCII string is sent => use the ANSI function ; STDCALL => arguments already freed by the callee noteax; eax is a BOOL value that needs negation for translating pusheax; a TRUE result to a 0 argument for exit (meaning success) call [exit] segment data use32 numedb'temp', 0 • Necessary build commands • Assembling: nasm.exe -fobjexample1.asm • Linking: alink.exeexample1.obj -oPE -entry start -subsys console • Program execution: example1.exe

  21. System libraries– File management examples • COFF: opening a file, reading and displaying its beginning – 1– ; example2.asm ; we’re using kernel32.lib(an import lib found in both the windows SDK and the MS VC++) ; all kernel32.lib names are decorated for MS VC++ with the STDCALL calling convention extern_CreateFileA@28, _ReadFile@20, _CloseHandle@4, _printf, _exit ; 28=7*4, 20=5*4, 4=1*4… globalstart FILE_ATTRIBUTE_NORMALequ 128 ; These constants are found in the official OPEN_EXISTINGequ 3 ; Microsoft documentation of the used functions. GENERIC_READ equ 0x80000000 ; The constants and the subroutines are documented INVALID_HANDLE_VALUEequ -1 ; at https://msdn.microsoft.com segmentcodeuse32 start: push dword0 ; hTemplateFileis optional and can be 0 push dwordFILE_ATTRIBUTE_NORMAL; dwFlagsAndAttributes parameter push dwordOPEN_EXISTING; dwCreationDisposition push dword0 ; lpSecurityAttributes, optional 0 push dword0 ; dwShareMode, optional 0 push dwordGENERIC_READ ; dwDesiredAccess push dwordfile_name; lpFileName call_CreateFileA@28; open the file: HANDLE WINAPI CreateFile(...) cmpeax, INVALID_HANDLE_VALUE; did it return INVALID_HANDLE_VALUE? jz.error ; if yes, we won’t be able to read anything

  22. System libraries– File management examples • COFF: opening a file, reading and displaying its beginning – 2– mov[file_id], eax; save it’s id (HANDLE) as eax is a volatile reg. push dword0 ; lpOverlapped, optional 0 push dwordbytes_read; lpNumberOfBytesRead push dwordbuffer.size; nNumberOfBytesToRead push dwordbuffer.address; lpBuffer push eax; hFile call_ReadFile@20; read data from file: BOOL WINAPI ReadFile(...) testeax, eax; is eax= false = 0 ? je.error ; abort if it’s false moveax, [bytes_read] ; eax = the byte count for the data read mov byte [buffer.address+ eax], 0 ; add a NULL termainator at the end of the data push dwordbuffer.address; send by reference the data buffer to printf push dwordformat_string; %s call_printf; display the content (it’s NULL-terminated=>safe) add esp, 2*4 ; cdecl– we (the caller) have to free the stack! push dword[file_id] ; handle = the file’s identifier call _CloseHandle@4; closing the handle means closing the file sub eax, eax; prepare eax = exit code (= 0 to signal success) jmp.finish; jump to the exit point with eax = success

  23. System libraries– File management examples • COFF: opening a file, reading and displaying its beginning – 3– .error: moveax, 1 ; exit with eax=1 to signal we were unsuccessful .finish: push eax; exit code parameter value call_exit; exit the application segmentdatause32publicdata; link.exe makesthe segmentread-only if the segment’s ; type (data) is not specified together with its name! file_namedb"example2.asm", 0 buffer.sizeequ 256 buffer.addressresbbuffer.size bytes_readdd 0 file_iddd 0 format_stringdb"%s", 0 • Necessary commands: • Assembling: nasm.exe -fwin32example2.asm • Linking: link.exeexample2.obj kernel32.libmsvcrt.lib -entry:start -subsystem:console • /NODEFAULTLIB, although still valid, is not needed if at least one Visual C .lib is specified! • Running: example2.exe

  24. System libraries– Process management • Important functions: • CreateProcess: run an application; a running instance of a program is also known as a process • WinExec: a similar (but deprecated) function, kept only for compatibility reasons • ShellExecute (shell32.dll): performs the same operation a double-click on the file would! • ExitProcess: exit the program (like the C exit function, which wraps a call to ExitProcess itself) • TerminateProcess: finish the execution of another process • GetCommandLine: retrieve the program’s command line • Sleep: take a break and let the CPU execute other tasks for a given length of time • EnumProcesses: store the identifiers of all currently running processes into an array • GetCurrentProcessId: returns a numeric value used as a unique identifier of the program • GetProcessWorkingSetSize: returns the amount of memory used by a process • QueryProcessCycleTime: retrieve information about a the CPU overhead of a given process • Remarks • Complex, yet powerful=> reading their documentation is a must! • Except for ShellExecute, they’re all exported by kernel32.dll • They have both ANSI and UNICODE variants: the actual names are CreateProcessA, CreateProcessW...

  25. System libraries – Process management example • OMF: printing the program’s command line importprintf msvcrt.dll importExitProcess kernel32.dll importGetCommandLineA kernel32.dll externprintf, ExitProcess, GetCommandLineA globalstart segmentcodeuse32 start: ; GetCommandLine has no parameters call [GetCommandLineA] ; call the ANSI version ofLPTSTR WINAPI GetCommandLine(void); push eax; result = eax = address of the command line string push dwordformat_string; %s call [printf] add esp, 2*4 pushdword 0 ; exit code argument call [ExitProcess] ; done, exit the program segmentdatause32 format_stringdb"%s", 0

  26. System libraries – Memory management • Important functions: • VirtualAlloc: reserve and/or allocate an address range inside the program’s address space • VirtualAllocEx: similar to VirtualAlloc, but supports altering the memory seen by other processes too(→ shared memory) • VirtualFree(Ex): Free the memory reservation or allocation at a given address range • HeapAlloc, HeapReAlloc, HeapFree: dynamically re/allocateorfree memory on a heap • IsBadReadPtr, IsBadWritePtr, IsBadCodePtr: probe for read, write or execute access rights • HeapCreate, HeapDestroy: create or destroy new heaps! • CopyMemory, MoveMemory, FillMemory, ZeroMemory: copying and memory initializations • MapViewOfFile: maps the memory seen in an address range directly to the content of a file! • Remarks • They offer fine-grained control over the access rights and the precise memory layout (what is each address interval mapped to) seen by an application • Other third-party libraries or programming languages do not offer this low-level control • They’re all part of the kernel32.dll library • Using some of these functions requires advanced knowledge regarding the x86 CPU’s protected mode, especially an understanding of the virtual memory concepts, knowledge that is beyond the scope of this course. • The official documentation covers the very basic notions that are needed and also provides some example code, just enough for perfoming the calls.

  27. System libraries – Memory management example • Counting how many times each BYTE occurs in a file – 1 – importprintfmsvcrt.dll ; the OMF format is required due to using import! importExitProcesskernel32.dll importHeapAlloc kernel32.dll importHeapFree kernel32.dll importCreateFileA kernel32.dll importReadFile kernel32.dll importCloseHandle kernel32.dll importGetProcessHeap kernel32.dll importGetFileSizeEx kernel32.dll externprintf, ExitProcess, HeapAlloc, HeapFree, CreateFileA, ReadFile extern CloseHandle, GetProcessHeap, GetFileSizeEx globalstart FILE_ATTRIBUTE_NORMALequ128 ; Constant definitions from the Microsoft’s OPEN_EXISTINGequ 3 ; documentation GENERIC_READ equ 0x80000000 ; Check the online documentation at INVALID_HANDLE_VALUEequ -1 ; https://msdn.microsoft.com for addition details FILE_SHARE_READequ 1 FILE_SHARE_WRITE equ2 FILE_SHARE_DELETEequ4 ; build a bit-mask that would allow other processes full access to the file we’re inspecting: FILE_SHARE_ALLequFILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE

  28. System libraries – Memory management example • Counting how many times each BYTE occurs in a file– 2– segmentcodeuse32 start: ; opening the file by calling the ASNI version of CreateFile (CreateFileA) push dword0 ; hTemplateFile push dword FILE_ATTRIBUTE_NORMAL ; dwFlagsAndAttributes push dwordOPEN_EXISTING; dwCreationDisposition push dword0 ; lpSecurityAttributes push dwordFILE_SHARE_ALL ; dwShareMode: allow access, we don’t own it! push dwordGENERIC_READ; dwDesiredAccess push dwordfile_name; lpFileName: we’re opening kernel32.dll call [CreateFileA] ; HANDLE WINAPI CreateFile(...) cmpeax, INVALID_HANDLE_VALUE; is the returned handle = INVALID_HANDLE_VALUE? jz.error ; if true, we won’t be able to do any further operations mov[file_id], eax; store the value of the volatile register eax push dwordfile_size; pass the variable by it’s address (reference) push eax; the file handle (eax didn’t suffer any changes yet) call [GetFileSizeEx] ; find its size in bytes: BOOL WINAPI GetFileSizeEx(...) test eax, eax; eax = false = 0? jz.close ; if so, the operation has failed cmpdword[file_size+4], 0 ; check if the high 32 bits part is 0 jnz.close ; if not, abort, the file is too large / unsupported (>4GB)

  29. System libraries – Memory management example • Counting how many times each BYTE occurs in a file– 3– ; no arguments - get the default heap (a handle) for allocating memory call [GetProcessHeap] ; ask for a handle: HANDLE WINAPI GetProcessHeap(..); test eax, eax; did it return NULL? jz.close ; abort if NULL mov [heap_id], eax; store the handle for further heap operations push dword[file_size] ; dwBytes: how many bytes to allocate push 0 ; dwFlags: 0, no custom flags/options push dword[heap_id] ; hHeap: the heap's identifier call [HeapAlloc] ; allocate memory: LPVOID WINAPI HeapAlloc(...) test eax, eax ; did we get a NULL pointer as a result? jz.close ; abort if this is the case mov [mem_pointer], eax; remember the address of the newly allocated memory push dword0 ; lpOverlapped: optional, we can send a 0 push dwordbytes_read ; lpNumberOfBytesRead: by reference (set by the function) push dword[file_size] ; nNumberOfBytesToRead: by value push dword[mem_pointer] ; lpBuffer: bufferul(prinreferinta) push dword[file_id] ; hFile: fisierul din care citim call [ReadFile] ; BOOL WINAPI ReadFile(...) test eax, eax; eax = false = 0 ? je.free; then free the memory and exit

  30. System libraries – Memory management example • Counting how many times each BYTE occurs in a file– 4– movecx, [bytes_read] ; we'll repeat for each byte read jecxz.free; make sure we don't loop with ecx = 0 movesi, [mem_pointer] ; mem_pointer is a pointer variable, not just a label! .count_next: lodsb; load next byte from buffer (DF=0 as we didn't set it) movzxedi, al incdword[counters + edi*4] ; increment the corresponding DWORD loop.count_next; and continue for all the remaining bytes sub ebx, ebx; start at index = 0 (ebxkeeps its after external calls) movesi, counters ; esi points to the very first DWORD (counter[0]) .print_next: lodsd ; load the counter value to eax push eax; how many times the byte was encountered push ebx; the value of the byte (0..255) pushformat_string; "%d: %d", 10, 13 call [printf] ; printf("%d: %d\n", byte_value, counter[byte_value]) add esp, 3*4 ; free the 3 parameters from the stack add bl, 1 ; advance (we're avoiding INC as it leaves CF unchanged!) jnc.print_next; repeat until there CF is set (BL would be above 255) movdword[cod_iesire], 0 ; assign 0 (the success value) to exit_code ; exit_code is 1 unless we get to this point

  31. System libraries – Memory management example • Counting how many times each BYTE occurs in a file– 5 – .free: push dword[mem_pointer] ; pointer to the memory we're freeing push dword 0 ; no special options push dword[heap_id] ; heap identifier call [HeapFree] ; call BOOL WINAPI HeapFree(...) ignoringthe result .close: push dword[file_id] call [CloseHandle] ; CloseHandle will close the file .error: push dword[exit_code] ; 0 for success or 1 otherwise call [ExitProcess] segmentdatause32 public data file_name db'c:\windows\system32\kernel32.dll', 0; read the data from kernel32.dll! file_id dd0 ; identifier of the file used for reading the bytes heap_iddd 0 ; the identifier for the implicit heap of the process mem_pointerdd 0 ; a pointer to the dynamically allocated heap memory exit_code dd 1 ; 0 = success, 1 = error (preinitialized) file_size dq 0 ; a QWORD, a file size doesn't necessarily fit in 32 bits bytes_readdd0 ; how much data (bytes) were read counterstimes 256 dd 0 ; 256 DWORD entries, already 0-initialized format_stringdb"%d: %d", 10, 13, 0

  32. The C standard library • Purpose: provide a standard set of abstractions that hide the hardware and operating system complexity. • Platform-independent set of functions (there are different implementations available for different platforms) • Although the C library by itself is standard and platform-independent, ASM programs using it are not! • Operations: • Input/output: keyboard, console • Process management: run external commands,exit program • Memory management: heap re/allocate and free • File management: create, read, write anddelete files • Various common operations: conversions, sorting, pseudo-random numbers, string operations, mathematical functions • Easier to use but more limited than the system libraries • The CDECL calling convention is used by all functions • The msvcrt.dll dynamic library is part of the OS installation files • It implements an older version of the standard, used mainly by the OS • Many other implementations are available(C Runtime Libraries), including static

  33. The C standard library - properties • Numeric types: char/short/int/long/size_t • They are signed (except forsize_t) BYTE/WORD/DWORD integers • Character string: char* • in the C language, * marks a pointer to an instance of the preceding type • The voidtype • Proceduresthat return nothing (eax has no assigned meaning after the call) • void*is the type of a pointer referencing some raw, untyped memory region • All character strings are NULL terminated • Theerrno variablecontains a numeric code describing the last error reason (it is one of the library exports!) • Rigour and genericity were sacrificed for simplicity • The interface is problematic and many times inconsistent • Many of the exported functions are deemed unsafe and should be avoidedfor the better (yet nonstandard) alternatives provided as a substitute by various compilers or operating systems.

  34. The C standard library – file management • Also known as streams, they allow sequential input/output access to various devices abstracted as files • Main functions: • fopen: open a stream for read and/or write operations • The data will be either treated as text or binary (a sequence of bytes) • fclose: close a file opened with fopen and free any related resources • fread: read data from a stream already opened by fopen • fwrite: write data to a stream • ftell: retrieve the current position inside the stream • fseek: set the current stream position • feof: check for end-of-file (current stream position being right after the end of data) • fprintf: similar to printf but writes the output to a stream • fscanf: just like scanf but using a stream as input • .... • There are many more, with a lot of them being redundant and offered for convenience only • Remark: they all call the kernel32.dll system functions internally • → they’re inherently slower than the underlying system functions

  35. The C standard library – file management example • Counting the words in a text file – 1 – importfopen msvcrt.dll importfscanf msvcrt.dll importfclose msvcrt.dll importprintf msvcrt.dll importexit msvcrt.dll externfopen, fscanf, fclose, printf, exit globalstart segmentcodeuse32 start: push dwordaccess; "r": read access right push dwordfile.name ; "exemplu.asm" call [fopen] ; C fopen("example.asm", "r") add esp, 2*4 ; free the arguments (cdecl…) test eax, eax ; check if the returned pointer to a FILE object is null jz.error ; and exit in that case mov[file.pointer],eax; store the returned pointer for later use sub esi, esi; esi= state = 0 outside of a word, 1 inside a word movedi, esi; edi= 0 = current word count movebx, letters; lookup-table for word characters vs other characters

  36. The C standard library – file management example • Counting the words in a text file– 2 – .repeat: push dwordcharacter; reference to the variable to fill-in push dwordcharacter.format; "%c" push dword[file.pointer] ; the FILE pointer, sent by value call [fscanf] ; C fscanf(file.pointer, "%c", &character) add esp, 3*4 ; free parameter stack cmpeax, 1 ; did we read precisely one entry? jne.done ; exit the repeat block if not mov al, [character] ; prepare al = the character to check xlat; verify if it is a word character: al <- [ebx+al] movzxeax, al; zero-extend to whole eax cmpeax, esi; check if the character type has changed je.repeat; if there’s no change then process the next one incedi; otherwise increment the number of words movesi, eax; and remember the new state / character type jmp.repeat .done: push dword[file.pointer] ; the file pointer call [fclose] ; free any file-associated resources add esp, 1*4 ; free the parameter from stack

  37. The C standard library – file management example • Counting the words in a text file– 3 – push edi; edi = word counter push dwordmessage.success; "Total number of words: %d" call [printf] ; C printf("... %d", word_count) add esp, 2*4 ; free the arguments jmp.finish .error: push dwordmessage.error call [printf] ; C printf("Could not...") add esp, 1*4 .finish: push dword0 ; always return exit code 0 call [exit] ; as an error message is printed when necessary segmentdatause32 file.name db"example.asm", 0 ; the name of the input file file.pointerdd 0 ; fopen will save the FILE pointer here accessdb"r", 0 ; access rights: r=read caracterdb 0 ; current character code caracter.formatdb"%c", 0 ; character (%c) format string message.succes: db“Total number of words: %d", 0 message.error: db"Could not open the file", 0

  38. The C standard library – file management example • Counting the words in a text file– 4 – letters: ; lookup table for distinguishing character types times 'A' - ($-letters) db 0 ; nothing before the `A` letter (65 ASCII code) times 'Z' + 1 - ($-letters) db 1 ; everything up to and including `Z` times 'a' - ($-letters) db 0 ; nothing until `a` times 'z' + 1 - ($-letters) db 1 ; all up to `z` times 256 - ($-letters)db0 ; and nothing from z until the end

  39. Implementing user libraries • Implementation concerns • Supported by many languages, NASM being no exception • A quick review of the main library types: • Static (.LIB) = the external resources are copied inside the program using them • Dynamic(.DLL) = the program contains references only to the needed resources • Import libraries, althoughhaving the same .LIB extension as the static ones, only offer information about the DLL containing the code / data. • There are two ways of writing NASM libraries: • The export directive,available only when using the OMF object files • Both the -fobj nasm flagand alink.exefor the linking step are needed • It offers no support for static library creation! • Export via .DEF files (module-definitions file), in conjunction with the COFF format: • It entails the -fwin32assembler flag and the Microsoft’s link.exe linker • Static libraries (.LIB) can only be built in this manner! • In both cases, the exported symbols must be declaredglobal! • All the multi-module programming concepts apply to library writing too!A library can be built by linking together one or more object files, static libraries and can make use of dynamic libraries, all written in potentially different programming languages!

  40. Implementing user libraries • Implementation concerns • All dynamic libraries have a start subroutine, just like an usual program • Responsible for preparing the library for usage (memory allocations, initializations etc...) • The start routine must return a logically true value, otherwise it won’t load! • Described by the MSDN docs as BOOL WINAPI DllMain(3 arguments) • Static libraries don’t use a start routine • Static or dynamic library? How to decide? • Is the program composed of many executable files or libraries that need the same resources? Does some component need support for individual updates? Then, most likely, such resources are suited to be placed inside a dynamic library. • Is it a trivial program? Is a single, stand-alone file program needed? Use static libraries! • OMF or COFF? • Only NASM code?Don’t bother, the export directive is really handy  → OMF • Is it a library combining NASM with other languages? → COFF

  41. Implementing user libraries – ASM steps • For a dynamic library a start subroutine is needed, able to receive 3 DWORD arguments and returning a non-zero value • The labels preceding the exported resources must be declared global, including the start label (if it is a dynamically-linked library) • Only code and variables can be exported, i.e. macro names (%define or %macro) and EQU-defined constant are not supported! • The global directive, although necessary, is not enough for the export! It’s effect is only to allow access (for the linker) to the said resource without actually exporting it • Designate the names as public exports of the resulting library • For OMFthis is easily done through the export directive, used as follows: • In casethe COFF format is used, a new Module-Definitions File (.DEF) is needed. This file should specify a name for the library (with internal use only) and each resource contained/exported by the new library: globalfunction1, var2 ; one or more comma-separated identifiers exportfunction1 PublicName; resources can be published under different names! exportvar2 ; or, this way, exports can leave the name unchanged LIBRARY internal_name; ASM style comments are permitted EXPORTSfunction1 ; only a single name is allowed on each line! var2 ; and so on, one line for each exported name

  42. Implementing user libraries – ASM steps • The .def file fills-in the same role played by the export directive for OMF • These files can additionally contain other definition types (regarding the structure of the program / library), useful in other scenarios, besides writing ASM libraries, and their use is documented by Microsoft on their website • The module-definitions files are useful for various C/C++ programs too! • Assembling the NASM code • OMF: nasm.exe -fobjfile.asm → file.obj • COFF: nasm.exe -fwin32file.asm → file.obj If needed, the command should be repeated in a similar manner for any additional files • Linking the resulting library • OMF: alink.exe file.obj -oPE-dll -entry start→ file.dll • COFF, static library: link.exe /libfile.obj /NODEFAULTLIB → file.lib • COFF, dynamic library: link.exe /dll file.obj /entry:start /def:file.def→ file.dll • COFF, (opțional) import lib: lib.exe /def:file.def /machine:x86 → file.lib An arbitrary number of object files (and static libraries for COFF) can be linked together if their names are listed comma-separated in any of the above linker command-lines

  43. Implementing user libraries – Example • Exporting two functions from a dynamic library– 1 – • DoubleDivision, performing a QWORD to DWORD unsigned integer division • DoubleMultiplicationwhich will multiply two DWORD unsigned integers resulting a QWORD value • OMF format is assumed • Step 1: First things first, a start routine is needed • The three input arguments of the start subroutine are: • hInstDll: a HANDLEvalue used by the library to identify itself for internal management (it might call FreeLibrary to unload itself, for example) • fdwReason: start is called for signaling various events (library load/unload, new thread created etc…) by specifying a reason code • lpvReserved: unused and undefined • In our trivial example the three parameters are not used, their existence is only important at the cleanup stage where the stack storage need to be freed, due to using the STDCALL convention • Step2: start, DoubleDivision and DoubleMultiplication need to be flagged as global • Step3: by using the exportdirective the two functions are easily marked as library exports export DoubleDivision exportDoubleMultiplication globalstart, DoubleDivision, DoubleMultiplication segmentcodeuse32code start:; being named “start” is not a must, it only has to fit the ; BOOL WINAPI DllMain(hInstDll, fdwReason, lpvReserved) signature moveax, 1; return eax = 1 = TRUE to avoid the operation being treated as failed ret 3*4 ; free the 3 arguments and return the true value found in eax

  44. Implementing user libraries – Example • Exporting two functions from a dynamic library– 2 – ; int WINAPI DoubleDivision(intNumeratorSup, intNumeratorInf, int Denominator) DoubleDivision: .NumeratorHighequ4 + 1*4 ; EBP-relative offset of high numerator part .NumeratorLowequ4 + 2*4 ; the second argument (low part of the numerator) .Denominatorequ4 + 3*4 ; third parameter push ebp; prepare a stack frame for the function movebp, esp cmpdword[ebp + .Denominator], 0 ; is the denominator zero? jz.avoid_division; if yes, skip (division by zero isn’t possible) movedx, [ebp + .NumeratorHigh] ; EDX = high part moveax, [ebp + .NumeratorLow] ; EAX = the low DWORD part div dword[ebp + .Denominator] ; EAX<-EDX:EAX/Denominator (EDX<-remainder, ignored) .avoid_division: pop ebp ret3*4 ; nothing to restore, only volatile registers were used

  45. Implementing user libraries – Example • Exporting two functions from a dynamic library– 3– ; int WINAPI DoubleMultiplication(int Factor1, int Factor2, int *ResultHigh) DoubleMultiplication: .Factor1 equ4 + 1*4 ; first argument .Factor2 equ4 + 2*4 ; note the use of the local-label mechanism for EQU constant! .ResultHighequ4 + 3*4 ; the actual (full) name is DoubleMultiplication.ResultHigh push ebp; prepare a stack frame movebp, esp moveax, [ebp + .Factor1] ; EAX = first factor movedx, [ebp + .Factor2] ; EDX = second factor muledx; EDX:EAX = the 64 bit product result cmpdword [ebp + .ResultHigh], 0; is the pointer NULL (=0)? jz.done; if indeed NULL, avoid dereferencing it movecx, [ebp + .ResultHigh] ; ECX = pointer value (the address referenced by the pointer) mov [ecx], edx; save the high part of the result to the specified address .done: pop ebp; no other registers need to be restored ret 3*4 ; return and free the 4 stack locations used by the arguments

  46. Implementing user libraries – Example • Exporting two functions from a dynamic library– 4 – • Assuming the NASM file is saved as ”library.asm”, the necessary steps for building the library are: • Step4: assemble the asm source code: nasm -fobjlibrary.asm • Step5: link the object file: alink.exe library.obj -oPE -dll -entry start • The resulting dynamic library (library.dll) can be used as part of any program, no matter the programming language as long as that specific language (its Foreign-Function Interface) offers support for using dynamic libraries and can handle the call convention (STDCALL in this example)

  47. Implementing user libraries – Example • Exporting two functions from a dynamic library– 5– • Let’s also exemplify how the library might prove useful to a new ASM program: the following code will divide 0x0123456787654321 to 1*GIGA and then it will call printf to display the value (0x48D159E) importDoubleDivision library.dll importprintf msvcrt.dll importExitProcess kernel32.dll externDoubleDivision, printf, ExitProcess globalstart segmentcodeuse32 code start: push dword1024*1024*1024 ; denominator: (((1024=KILO)*1024)=MEGA)*1024)=GIGA push dword0x87654321 ; NumeratorLow: low DWORD part of (0x0123456787654321) push dword0x01234567 ; NumeratorHigh: high part of (0x0123456787654321) call[DoubleDivision] ; perform the division operation (0x0123456787654321 / GIGA) push eax; the value to print push dwordfmt; printf("0x0123456787654321 / GIGA = 0x%X", eax) call [printf] ; call printf add esp, 2*4 ; free the printf arguments (printf uses cdecl) push dword0; 0 is considered a success code for ExitProcess call [ExitProcess] ; done, finish execution fmt: db"0x0123456787654321 / GIGA = 0x%X", 0 ; %X will print a hexadecimal number

  48. Implementing user libraries – Example • Exporting two functions from a dynamic library– 6– • Let’s take a look at what the COFF version of the example would look like: • The export directive cannot be used and Step 3 asks for a .def file instead: ; the library.def file LIBRARY library EXPORTS DoubleDivision DoubleMultiplication • The only code change (due to the third step still) is the elimination of all export declarations: globalstart, DoubleDivision, DoubleMultiplication segmentcodeuse32code start: ; being named “start” is not a must, it only has to fit the ; BOOL WINAPI DllMain(hInstDll, fdwReason, lpvReserved) signature . . .. . . . . . . • The 4 and 5 steps would consist of issuing the following commands: • Step4 – assemble the file: nasm -fwin32library.asm • Step 5.c) – link editing: link.exe/dll library.obj/entry:start /def:library.def • Step5.d)– creating an import library, optional: lib.exe/def:library.def/machine:x86

More Related