📄 libc.asm
字号:
;Copyright (C) 1999-2002 Konstantin Boldyshev <konst@linuxassembly.org>;Copyright (C) 1999 Cecchinel Stephan <inter.zone@free.fr>;;$Id: libc.asm,v 1.15 2002/06/11 08:38:39 konst Exp $;;hackers' libc;;Yes, this is the most advanced libc ever seen.;It uses advanced technologies which are possible only with assembly.;Two main features that make this libc outstanding:;1) calling convention can be configured AT RUNTIME (cdecl is default);2) THE smallest size;;It uses mixed code-data database approach for syscalls,;resulting in extremely small size.;;Well, there's still a lot of work to be done.;;0.01: 10-Sep-1999 initial alpha pre beta 0 non-release;0.02: 24-Dec-1999 first working version;0.03: 21-Feb-2000 fastcall support;0.04: 20-Jul-2000 fixed stupid bug/misprint, merged clib.asm & string.asm; printf();0.05: 16-Jan-2001 usual functions now work with both cdecl and fastcall,; added PIC support (and __GET_GOT macro),; added __ADJUST_CDECL3 macro,; syscall mechanism rewritten (size improved),; separated and optimized sprintf(),; printf() implemented via sprintf(),; lots of other various fixes (KB); finally ready for additions and active development.;0.06: 28-Jan-2001 added __start_main - it is called from stub in order; to prepare main() arguments (argc, argv, envp),; PIC fixes (KB);0.07: 25-Feb-2001 added __VERBOSE__, memcmp(), getenv() (KB);0.08: 20-Jan-2002 strlen() bugfix, various fixes (KB);0.09: 03-Mar-2002 __start_main fastcall fix (KB)%undef __ELF_MACROS__%include "system.inc"%define __PIC__ ;build PIC version;%define __VERBOSE__ ;treat stack with care;; macro used for function declaration;%macro _DECLARE_FUNCTION 1-*%rep %0 global %1:function%rotate 1%endrep%endmacro;; macro used for syscall declaration;;%1 syscall name;%2 number of parameters;;Ok, what is written below?;Yes - a really dirty trick, but it really saves size.;This is the thing I like assembly for,;and this why this libc is the most advanced :);;This macro generates the following code:;six bytes - call instruction;one byte - number of syscall parameters (<0 means always cdecl);one byte - syscall number (two bytes on BSD systems);;So, each syscall will take only 8 bytes (9 bytes on BSD systems);in executable image. We use call instruction to push return address,;and then find out syscall number and number of parameters using;this address in __system_call function. ret instructions is also;missing, because we will handle correct return in __system_call too.%macro _DECLARE_SYSCALL 2 global %1:function%1: call __system_call db %2 ;number of parameters%ifndef __BSD__ db SYS_%{1};syscall number%else dw SYS_%{1}%endif%endmacro;;PIC handling;%define __EXT_VAR(x) [ebx + (x) wrt ..got]%define __INT_VAR(x) ebx + (x) wrt ..gotoff%macro __GET_GOT 0 call __get_GOT%%get_GOT:%define gotpc %%get_GOT wrt ..gotpc add ebx,_GLOBAL_OFFSET_TABLE_ + $$ - gotpc%undef gotpc%endmacro;adjust cdecl call (1 - 3 parameters);;%1 stack frame to add;%2 - %4 registers%macro __ADJUST_CDECL3 2-4; _mov %2,eax;%if %0>2; _mov %3,edx;%if %0>3; _mov %4,ecx;%endif;%endif%ifdef __PIC__ push ebx __GET_GOT mov ebx,__EXT_VAR(__cc) cmp byte [ebx],0 pop ebx%else cmp byte [__cc],0%endif jnz %%fc mov %2,[esp + %1 + 4 ]%if %0>2 mov %3,[esp + %1 + 8 ]%if %0>3 mov %4,[esp + %1 + 12]%endif%endif%%fc:%endmacro;;for accessing registers after pusha;%define __ret esp+4*8%define __eax esp+4*7%define __ecx esp+4*6%define __edx esp+4*5%define __ebx esp+4*4%define __esp esp+4*3%define __ebp esp+4*2%define __esi esp+4*1%define __edi esp+4*0CODESEG%ifdef __PIC____get_GOT: mov ebx,[esp] ret%endifSTART:%ifdef __PIC__ __GET_GOT lea ecx,[__INT_VAR(__libc_banner)]%else mov ecx,__libc_banner%endif sys_write STDOUT,EMPTY,__LIBC_BANNER_LEN sys_exit 0__libc_banner db "a r e y o u s i c k ?", __n__LIBC_BANNER_LEN equ $ - __libc_bannerextern _GLOBAL_OFFSET_TABLE_;**************************************************;* INTERNAL FUNCTIONS *;**************************************************;;perform a system call (up to 6 arguments);__system_call: pusha mov eax,[__esp] ;load number of syscall args into eax mov eax,[eax] movzx eax,byte [eax] test al,al jz .ssn ;no args%ifdef __VERBOSE__ jns .sk1 ;usual call neg al ;always cdecl call jmps .cdecl%else js .cdecl%endif.sk1:%ifdef __PIC__ __GET_GOT mov ebx,__EXT_VAR(__cc) cmp byte [ebx],0%else cmp byte [__cc],0%endif jnz .fc%define _STACK_ADD 8 + 4*8%macro _JZ_SSN_ 0%ifdef __VERBOSE__ dec eax jz .ssn%endif%endmacro.cdecl: mov ebx,[esp + _STACK_ADD] ;1st arg _JZ_SSN_ mov ecx,[esp + _STACK_ADD + 4] ;2nd arg _JZ_SSN_ mov edx,[esp + _STACK_ADD + 8] ;3rd arg _JZ_SSN_ mov esi,[esp + _STACK_ADD + 12] ;4th arg _JZ_SSN_ mov edi,[esp + _STACK_ADD + 16] ;5th arg _JZ_SSN_ mov ebp,[esp + _STACK_ADD + 20] ;6th arg jmps .ssn.fc: mov ebx,[__eax] ;1st arg _JZ_SSN_ xchg ecx,edx ;2nd & 3rd arg _JZ_SSN_ _JZ_SSN_ mov esi,[esp + _STACK_ADD] ;4th arg _JZ_SSN_ mov edi,[esp + _STACK_ADD + 4] ;5th arg _JZ_SSN_ mov ebp,[esp + _STACK_ADD + 8] ;6th arg%undef _STACK_ADD.ssn: mov eax,[__esp] ;set syscall number mov eax,[eax]%ifndef __BSD__ movzx eax,byte [eax + 1] ;return address + 1%else movzx eax,word [eax + 1] ;return address + 1%endif sys_generic cmp eax,-4095 jb .leave; test eax,eax; jns .leave neg eax%ifdef __PIC__ __GET_GOT mov ebx,__EXT_VAR(errno) mov [ebx],eax%else mov [errno],eax%endif or eax,byte -1.leave: mov [__eax + 4],eax ;replace return address with eax popa pop eax ;now get it back ret ;and return to previous caller;;;_DECLARE_SYSCALL open, -3 ;<0 means always cdecl_DECLARE_SYSCALL close, 1_DECLARE_SYSCALL read, 3_DECLARE_SYSCALL write, 3_DECLARE_SYSCALL lseek, 3_DECLARE_SYSCALL chmod, 2_DECLARE_SYSCALL chown, 2_DECLARE_SYSCALL pipe, 1_DECLARE_SYSCALL link, 2_DECLARE_SYSCALL symlink,2_DECLARE_SYSCALL unlink, 1_DECLARE_SYSCALL mkdir, 1_DECLARE_SYSCALL rmdir, 1_DECLARE_SYSCALL exit, 1_DECLARE_SYSCALL fork, 0_DECLARE_SYSCALL execve, 3_DECLARE_SYSCALL uname, 1_DECLARE_SYSCALL ioctl, 3_DECLARE_SYSCALL alarm, 1_DECLARE_SYSCALL nanosleep, 2_DECLARE_SYSCALL kill, 2_DECLARE_SYSCALL signal, 2_DECLARE_SYSCALL wait4, 4;_DECLARE_SYSCALL stat, 2_DECLARE_SYSCALL fstat, 2_DECLARE_SYSCALL lstat, 2_DECLARE_SYSCALL getuid, 0_DECLARE_SYSCALL getgid, 0_DECLARE_FUNCTION _fastcall_DECLARE_FUNCTION memcpy, memset, memcmp_DECLARE_FUNCTION strlen_DECLARE_FUNCTION strtol_DECLARE_FUNCTION itoa_DECLARE_FUNCTION printf, sprintf_DECLARE_FUNCTION getenv_DECLARE_FUNCTION __start_main;;;ebp - main() address__start_main: pop ebp ;main() address pop eax ;argc lea ecx,[esp + eax * 4 + 4] ;**envp%ifdef __PIC__ __GET_GOT mov ebx,__EXT_VAR(__envp) mov [ebx],ecx%else mov [__envp],ecx%endif mov edx,esp ;**argv push ecx push edx push eax call ebp push eax call exit;**************************************************;* GLOBAL LIBRARY FUNCTIONS *;**************************************************;void fastcall(int regnum);;set fastcall/cdecl calling convention;note: always uses fasctall convention;;<EAX regnum_fastcall:%ifdef __PIC__ push ebx __GET_GOT mov ebx,__EXT_VAR(__cc) mov [ebx],eax pop ebx%else mov [__cc],eax%endif ret;void memset(void *s, int c, size_t n);;fill an array of memory;;<EDX *s;<AL c;<ECX nmemset: push edx push ecx push eax xchg eax,edx __ADJUST_CDECL3 4*3,edx,eax,ecx.real:%if __OPTIMIZE__=__O_SPEED__ cmp ecx,byte 20 ;if length is below 20 , better use byte fill jl .below20 mov ah,al ;expand al to eax like alalalal push ax shl eax,16 pop ax.lalign: test dl,3 ;align edx on a 4 multiple jz .align1 mov [edx],al inc edx dec ecx jnz .lalign jmps .memfin.align1: push ecx shr ecx,3 ;divide ecx by 8 pushf.boucle: mov [edx],eax ;then fill by 2 dword each times mov [edx+4],eax ;it is faster than stosd (on PII) add edx,byte 8 dec ecx jnz .boucle popf jnc .boucle2 mov [edx],eax add edx,byte 4.boucle2: pop ecx and ecx,byte 3 jz .memfin.below20: mov [edx+ecx-1],al dec ecx jnz .below20.memfin:%else ;__O_SIZE__ push edi cld mov edi,edx rep stosb pop edi%endif ;__OPTIMIZE__ pop eax pop ecx pop edx ret;void *memcpy(void *dest,const void *src, size_t n);;<EDI *dest;<ESI *src;<ECX nmemcpy:%if __OPTIMIZE__=__O_SPEED__%define _STACK_ADD 4*3 push ecx push edi push esi%else%define _STACK_ADD 4*8 pusha%endif mov edi,eax mov esi,edx __ADJUST_CDECL3 _STACK_ADD,edi,esi,ecx.real: cld rep movsb%if __OPTIMIZE__=__O_SPEED__ pop esi pop edi pop ecx%else popa%endif%undef _STACK_ADD ret;int memcmp(void *s1, void *s2, size_t n);;compare memory areas;;<ESI *s1;<EDI *s2;<ECX nmemcmp: push esi push edi push ecx __ADJUST_CDECL3 4*3,esi,edi,ecx.real: cld rep cmpsb jz .ret sbb eax,eax or eax,byte 1.ret: pop ecx pop edi pop esi ret;char *getenv(char *);;<ESI *sgetenv: pusha mov edi,eax __ADJUST_CDECL3 4*8,edi
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -