News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

GetCpuFrequency Tests

Started by dedndave, October 13, 2015, 08:34:58 PM

Previous topic - Next topic

TWell

If you use GetCurrentProcess(), it is calling process handle?

guga

Hi dave, take a look at this source

http://fluid-particles.googlecode.com/svn/trunk/CoreDetection/CpuTopology.cpp

You may find interesting the cpu classes :)

Btw....Also the project per se is quite amazing (Fluid particles system)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

Dave, do not use SetProcessAffinityMask !!!

I found a bug (at least on WinP) inside that API. The stack is being returned incorrectly. There is a major stack problem there. There is a lack of "leave"  or "mov esp ebp". This is causing the function to needs an adjustment on the stack after it is used. I made some tests on your function and saved the registers while using it. All i left was eax to it returns the proper Flags retrieved by GetCpuidSupport. The problem was after using the GetCpuFrequency it was saving at ebx the same value as in eax (ebx was being "poped" by eax), regardless i saved all registers with the chain of push/pop, during the entrance and exiting of the function. Take a look at the disassembled code from kernel32.dll as below:


; BOOL __stdcall SetProcessAffinityMask(HANDLE hProcess, DWORD_PTR dwProcessAffinityMask)
public _SetProcessAffinityMask@8
_SetProcessAffinityMask@8 proc near ; DATA XREF: .text:off_7C802654o

hProcess = dword ptr  8
dwProcessAffinityMask= dword ptr  0Ch

mov edi, edi
push ebp
mov ebp, esp
push 4
lea eax, [ebp+dwProcessAffinityMask]
push eax
push 21
push [ebp+hProcess]
call ds:__imp__NtSetInformationProcess@16 ; NtSetInformationProcess(x,x,x,x)
test eax, eax
jge short loc_7C862E48
push eax
call _BaseSetLastNTError@4 ; BaseSetLastNTError(x)
xor eax, eax
jmp short loc_7C862E4B
; ---------------------------------------------------------------------------

loc_7C862E48:
xor eax, eax
inc eax

loc_7C862E4B: ; MISSING A "LEAVE" OR "MOV ESP EBB" HERE !!!!
pop ebp
retn 8
_SetProcessAffinityMask@8 endp


I succeeded to fix that and rebuilt both APis used:GetProcessAffinityMask and SetProcessAffinityMask. I´ll post the corrected functions on another thread. I managed to fix retrieving the values from the TEB/PEB structures as the same way the original APis did, but, i fixed them, while on XP it is still broken ! (I believe that probably, it is also broken in others windows versions as well, but i didn´t analyzed them yet)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

nidud

#78
deleted

jj2007

Quote from: guga on December 26, 2015, 03:05:58 AMI found a bug (at least on WinP) inside that API. The stack is being returned incorrectly. There is a major stack problem there. There is a lack of "leave"  or "mov esp ebp". This is causing the function to needs an adjustment on the stack after it is used.

Can you post an executable that shows this behaviour, with an int 3 inserted shortly before?
My tests on Win XP and Win7-64 do not show any abnormal behaviour:

include \masm32\MasmBasic\MasmBasic.inc      ; download
  Init
  mov esi, 111111111
  mov edi, 222222222
  mov ebx, 333333333
  mov ecx, 444444444
  deb 4, "In", esi, edi, ebx, ebp, ecx, esp
  ClearLastError
  push ecx
  invoke SetProcessAffinityMask, rv(GetCurrentProcess), 1
  pop ecx
  deb 4, "SPAM", eax, $Err$()
  deb 4, "Out", esi, edi, ebx, ebp, ecx, esp
EndOfCode


In
esi             111111111
edi             222222222
ebx             333333333
ebp             1638292
ecx             444444444
esp             1638284

SPAM
eax             1
$Err$()         Operazione completata.


Out
esi             111111111
edi             222222222
ebx             333333333
ebp             1638292
ecx             444444444
esp             1638284

guga

Hi Guys...Many tks for the feedback.

Indeed that was not a fault of GetProcessAffinityMask/SetProcessAffinityMask.

The problem was in one of my macros. The counting of the stack was incorrect, leading the values to return 4 bytes ahead

many tks, and Merry Xmas, to you all :)
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com

guga

In any case, if someone wants a new version of those Apis (GetProcessAffinityMask and SetProcessAffinityMask) here they are:

GetProcessAffinityMask

[BASE_STATIC_SERVER_DATA.WindowsDirectory.LengthDis 0
BASE_STATIC_SERVER_DATA.WindowsDirectory.MaximumLengthDis 2
BASE_STATIC_SERVER_DATA.WindowsDirectory.BufferDis 4
BASE_STATIC_SERVER_DATA.WindowsSystemDirectory.LengthDis 8
BASE_STATIC_SERVER_DATA.WindowsSystemDirectory.MaximumLengthDis 10
BASE_STATIC_SERVER_DATA.WindowsSystemDirectory.BufferDis 12
BASE_STATIC_SERVER_DATA.NamedObjectDirectory.LengthDis 16
BASE_STATIC_SERVER_DATA.NamedObjectDirectory.MaximumLengthDis 18
BASE_STATIC_SERVER_DATA.NamedObjectDirectory.BufferDis 20
BASE_STATIC_SERVER_DATA.WindowsMajorVersionDis 24
BASE_STATIC_SERVER_DATA.WindowsMinorVersionDis 26
BASE_STATIC_SERVER_DATA.BuildNumberDis 28
BASE_STATIC_SERVER_DATA.CSD.wServicePackMajorDis 30
BASE_STATIC_SERVER_DATA.CSD.wServicePackMinorDis 32
BASE_STATIC_SERVER_DATA.CSD.szCSDVersionDis 34
BASE_STATIC_SERVER_DATA.Padding1Dis 286
BASE_STATIC_SERVER_DATA.SysInfo.ReservedDis 288
BASE_STATIC_SERVER_DATA.SysInfo.TimerResolutionDis 292
BASE_STATIC_SERVER_DATA.SysInfo.PageSizeDis 296
BASE_STATIC_SERVER_DATA.SysInfo.NumberOfPhysicalPagesDis 300
BASE_STATIC_SERVER_DATA.SysInfo.LowestPhysicalPageNumberDis 304
BASE_STATIC_SERVER_DATA.SysInfo.HighestPhysicalPageNumberDis 308
BASE_STATIC_SERVER_DATA.SysInfo.AllocationGranularityDis 312
BASE_STATIC_SERVER_DATA.SysInfo.MinimumUserModeAddressDis 316
BASE_STATIC_SERVER_DATA.SysInfo.MaximumUserModeAddressDis 320
BASE_STATIC_SERVER_DATA.SysInfo.ActiveProcessorsAffinityMaskDis 324
BASE_STATIC_SERVER_DATA.SysInfo.NumberOfProcessorsDis 328
BASE_STATIC_SERVER_DATA.SysInfo.Padding1Dis 329
BASE_STATIC_SERVER_DATA.Padding2Dis 332
BASE_STATIC_SERVER_DATA.TimeOfDay.BootTimeDis 336
BASE_STATIC_SERVER_DATA.TimeOfDay.CurrentTimeDis 344
BASE_STATIC_SERVER_DATA.TimeOfDay.TimeZoneBiasDis 352
BASE_STATIC_SERVER_DATA.TimeOfDay.TimeZoneIdDis 360
BASE_STATIC_SERVER_DATA.TimeOfDay.ReservedDis 364
BASE_STATIC_SERVER_DATA.IniFileMappingDis 368
BASE_STATIC_SERVER_DATA.NlsUserInfo.sAbbrevLangNameDis 372
BASE_STATIC_SERVER_DATA.NlsUserInfo.iCountryDis 532
BASE_STATIC_SERVER_DATA.NlsUserInfo.sCountryDis 692
BASE_STATIC_SERVER_DATA.NlsUserInfo.sListDis 852
BASE_STATIC_SERVER_DATA.NlsUserInfo.iMeasureDis 1012
BASE_STATIC_SERVER_DATA.NlsUserInfo.sDecimalDis 1172
BASE_STATIC_SERVER_DATA.NlsUserInfo.sThousandDis 1332
BASE_STATIC_SERVER_DATA.NlsUserInfo.sGroupingDis 1492
BASE_STATIC_SERVER_DATA.NlsUserInfo.iDigitsDis 1652
BASE_STATIC_SERVER_DATA.NlsUserInfo.iLZeroDis 1812
BASE_STATIC_SERVER_DATA.NlsUserInfo.iNegNumberDis 1972
BASE_STATIC_SERVER_DATA.NlsUserInfo.sCurrencyDis 2132
BASE_STATIC_SERVER_DATA.NlsUserInfo.sMonDecSepDis 2292
BASE_STATIC_SERVER_DATA.NlsUserInfo.sMonThouSepDis 2452
BASE_STATIC_SERVER_DATA.NlsUserInfo.sMonGroupingDis 2612
BASE_STATIC_SERVER_DATA.NlsUserInfo.iCurrDigitsDis 2772
BASE_STATIC_SERVER_DATA.NlsUserInfo.iCurrencyDis 2932
BASE_STATIC_SERVER_DATA.NlsUserInfo.iNegCurrDis 3092
BASE_STATIC_SERVER_DATA.NlsUserInfo.sPosSignDis 3252
BASE_STATIC_SERVER_DATA.NlsUserInfo.sNegSignDis 3412
BASE_STATIC_SERVER_DATA.NlsUserInfo.sTimeFormatDis 3572
BASE_STATIC_SERVER_DATA.NlsUserInfo.sTimeDis 3732
BASE_STATIC_SERVER_DATA.NlsUserInfo.iTimeDis 3892
BASE_STATIC_SERVER_DATA.NlsUserInfo.iTLZeroDis 4052
BASE_STATIC_SERVER_DATA.NlsUserInfo.iTimeMarkPosnDis 4212
BASE_STATIC_SERVER_DATA.NlsUserInfo.s1159Dis 4372
BASE_STATIC_SERVER_DATA.NlsUserInfo.s2359Dis 4532
BASE_STATIC_SERVER_DATA.NlsUserInfo.sShortDateDis 4692
BASE_STATIC_SERVER_DATA.NlsUserInfo.sDateDis 4852
BASE_STATIC_SERVER_DATA.NlsUserInfo.iDateDis 5012
BASE_STATIC_SERVER_DATA.NlsUserInfo.sLongDateDis 5172
BASE_STATIC_SERVER_DATA.NlsUserInfo.iCalTypeDis 5332
BASE_STATIC_SERVER_DATA.NlsUserInfo.iFirstDayDis 5492
BASE_STATIC_SERVER_DATA.NlsUserInfo.iFirstWeekDis 5652
BASE_STATIC_SERVER_DATA.NlsUserInfo.sLocaleDis 5812
BASE_STATIC_SERVER_DATA.NlsUserInfo.UserLocaleIdDis 5972
BASE_STATIC_SERVER_DATA.NlsUserInfo.fCacheValidDis 5976
BASE_STATIC_SERVER_DATA.DefaultSeparateVDMDis 5980
BASE_STATIC_SERVER_DATA.Wx86EnabledDis 5981
BASE_STATIC_SERVER_DATA.Padding3Dis 5982]

[Size_Of_BASE_STATIC_SERVER_DATA 5984]


[PROCESS_BASIC_INFORMATION.ExitStatusDis 0
PROCESS_BASIC_INFORMATION.PebBaseAddressDis 4
PROCESS_BASIC_INFORMATION.AffinityMaskDis 8
PROCESS_BASIC_INFORMATION.BasePriorityDis 12
PROCESS_BASIC_INFORMATION.UniqueProcessIdDis 16
PROCESS_BASIC_INFORMATION.InheritedFromUniqueProcessIdDis 20]

[Size_of_PROCESS_BASIC_INFORMATION 24]

[BaseStaticServerData: D$ 0]

Proc GetProcessAffinityMask:
    Arguments @hProcess, @lpProcessAffinityMask, @lpSystemAffinityMask
    Structure @PROCESS_BASIC_INFORMATION 24, @PROCESS_BASIC_INFORMATION.ExitStatusDis 0,
              @PROCESS_BASIC_INFORMATION.PebBaseAddressDis 4, @PROCESS_BASIC_INFORMATION.AffinityMaskDis 8,
              @PROCESS_BASIC_INFORMATION.BasePriorityDis 12, @PROCESS_BASIC_INFORMATION.UniqueProcessIdDis 16,
              @PROCESS_BASIC_INFORMATION.InheritedFromUniqueProcessIdDis 20
    Uses ecx, edx

    call 'Ntdll.NtQueryInformationProcess' D@hProcess, &PROCESS_BASICINFORMATION,
                                           D@PROCESS_BASIC_INFORMATION, Size_of_PROCESS_BASIC_INFORMATION, 0
    If eax <> &STATUS_SUCCESS
        call BaseSetLastNTError eax
        xor eax eax
    Else
       
        ; Copy the affinity mask, and get the system one from our shared data
        mov ecx D@lpProcessAffinityMask
        mov eax D@PROCESS_BASIC_INFORMATION.AffinityMaskDis | mov D$ecx eax

        call 'ntdll.RtlAcquirePebLock' ; <------- Always lock the PEb before using it.
        call GetBaseStaticServerFromTEB BaseStaticServerData
        mov eax D$BaseStaticServerData
        mov eax D$eax+BASE_STATIC_SERVER_DATA.SysInfo.NumberOfProcessorsDis
        mov ecx D@lpSystemAffinityMask | mov D$ecx eax
        call 'ntdll.RtlReleasePebLock'; <---- And, of course, don´t forget to unlock it.
        mov eax &TRUE
    End_If

EndP


SetProcessAffinityMask

Proc SetProcessAffinityMask:
    Arguments @hProcess, @dwProcessAffinityMask
    Uses ecx, edx

    ; Directly set the affinity mask
    lea eax D@dwProcessAffinityMask
    call 'Ntdll.NtSetInformationProcess' D@hProcess, &PROCESS_AFFINITYMASK, eax, 4

    If eax <> &STATUS_SUCCESS
        call BaseSetLastNTError eax
        xor eax eax
    Else
        mov eax &TRUE
    End_If

EndP


And the additional functions

BaseSetLastNTError

Proc BaseSetLastNTError:
    Arguments @ErrorCode
    Uses esi, ecx, edx, ebx

    call 'ntdll.RtlNtStatusToDosError' D@ErrorCode | mov esi eax
    call 'kernel32.SetLastError' eax
    mov eax esi

EndP


GetBaseStaticServerFromTEB


;;
         GetBaseStaticServerFromTEB

            This function retrieves the pointer to a BASE_STATIC_SERVER_DATA structure that contains information about your system.

         Arguments:
           pOutput (out): Pointer to a Variable that will holds the data to the structure BASE_STATIC_SERVER_DATA

        Returned Values:
               This function will return a pointer to BASE_STATIC_SERVER_DATA structure. Also, it will store it on the proper variable at pOutput

       Example of usage:

          [BaseStaticServerData: D$ 0]
                    call 'ntdll.RtlAcquirePebLock' ; <------- Always lock the PEb before using it.
                    call GetBaseStaticServerFromTEB BaseStaticServerData
                    add eax BASE_STATIC_SERVER_DATA.NamedObjectDirectory.LengthDis
                     (...)
                    call 'ntdll.RtlReleasePebLock' <---- And, of course, don´t forget to unlock it.

       See Also: BASE_STATIC_SERVER_DATA structure

        Remarks: Always lock and unlock the PEb when retrieving the information from TEB/PEB data.
                        To lock you must use a call to  'ntdll.RtlAcquirePebLock' and to unlock you must use the function ntdll.RtlReleasePebLock
                         See the example above.

      Author:
         Gustavo Trigueiros (aka: Beyond2000! or Guga)
         jul/2014
;;


[TEB.Tib.ExceptionListDis 0
TEB.Tib.StackBaseDis 4
TEB.Tib.StackLimitDis 8
TEB.Tib.SubSystemTibDis 12
TEB.Tib.FiberDataDis 16
TEB.VersionDis 16
TEB.Tib.ArbitraryUserPointerDis 20
TEB.Tib.SelfDis 24
TEB.EnvironmentPointerDis 28
TEB.ClientId.UniqueProcessDis 32
TEB.ClientId.UniqueThreadDis 36
TEB.ActiveRpcDDis 40
TEB.ThreadLocalStoragePointerDis 44
TEB.PebDis 48
TEB.LastErrorValueDis 52
TEB.CountOfOwnedCriticalSectionsDis 56
TEB.CsrClientThreadDis 60
TEB.Win32ThreadInfoDis 64
TEB.Win32ClientInfoDis 68
TEB.WOW32ReservedDis 192
TEB.CurrentLocaleDis 196
TEB.FpSoftwareStatusRegisterDis 200
TEB.SystemReserved1Dis 204
TEB.Spare1Dis 420
TEB.ExceptionCodeDis 424
TEB.SpareBs1Dis 428
TEB.SystemReserved2Dis 468
TEB.GdiTebBatch.OffsetDis 508
TEB.GdiTebBatch.HDCDis 512
TEB.GdiTebBatch.BufferDis 516
TEB.gdiRgnDis 1756
TEB.gdiPenDis 1760
TEB.gdiBrushDis 1764
TEB.RealClientId.UniqueProcessDis 1768
TEB.RealClientId.UniqueThreadDis 1772
TEB.GdiCachedProcessDDis 1776
TEB.GdiClientPIDDis 1780
TEB.GdiClientTIDDis 1784
TEB.GdiThreadLocaleInfoDis 1788
TEB.UserReservedDis 1792
TEB.glDispachTableDis 1812
TEB.glReserved1Dis 2932
TEB.glReserved2Dis 3036
TEB.glSectionInfoDis 3040
TEB.glSectionDis 3044
TEB.glTableDis 3048
TEB.glCurrentRCDis 3052
TEB.glContextDis 3056
TEB.LastStatusValueDis 3060
TEB.StaticUnicodeString.LengthDis 3064
TEB.StaticUnicodeString.MaximumLengthDis 3066
TEB.StaticUnicodeString.BufferDis 3068
TEB.StaticUnicodeBufferDis 3072
TEB.PADDINGDis 3594
TEB.DeallocationStackDis 3596
TEB.TlsSlotsDis 3600
TEB.TlsLinks.FlinkDis 3856
TEB.TlsLinks.BlinkDis 3860
TEB.VdmDis 3864
TEB.ReservedForNtRpcDis 3868
TEB.DbgSsReservedDis 3872
TEB.HardErrorDisabledDis 3880
TEB.InstrumentationDis 3884
TEB.WinSockDataDis 3948
TEB.GdiBatchCountDis 3952
TEB.Spare2Dis 3956
TEB.Spare3Dis 3960
TEB.Spare4Dis 3964
TEB.ReservedForOleDis 3968
TEB.WaitingOnLoaderLockDis 3972
TEB.Reserved5Dis 3976
TEB.TlsExpansionSlotsDis 3988]

[PEB.InheritedAddressSpaceDis 0
PEB.ReadImageFileExecOptionsDis 1
PEB.BeingDebuggedDis 2
PEB.SpareBoolDis 3
PEB.MutantDis 4
PEB.ImageBaseAddressDis 8
PEB.LdrDataDis 12
PEB.ProcessParametersDis 16
PEB.SubSystemDataDis 20
PEB.ProcessHeapDis 24
PEB.FastPebLockDis 28
PEB.FastPebLockRoutineDis 32
PEB.FastPebUnlockRoutineDis 36
PEB.EnvironmentUpdateCountDis 40
PEB.KernelCallbackTableDis 44
PEB.EventLogSectionDis 48
PEB.EventLogDis 52
PEB.FreeListDis 56
PEB.TlsExpansionCounterDis 60
PEB.TlsBitmapDis 64
PEB.TlsBitmapBitsDis 68
PEB.ReadOnlySharedMemoryBaseDis 76
PEB.ReadOnlySharedMemoryHeapDis 80
PEB.ReadOnlyStaticServerDataDis 84
PEB.AnsiCodePageDataDis 88
PEB.OemCodePageDataDis 92
PEB.UnicodeCaseTableDataDis 96
PEB.NumberOfProcessorsDis 100
PEB.NtGlobalFlagDis 104
PEB.Spare2Dis 108
PEB.CriticalSectionTimeoutDis 112
PEB.HeapSegmentReserveDis 120
PEB.HeapSegmentCommitDis 124
PEB.HeapDeCommitTotalFreeThresholdDis 128
PEB.HeapDeCommitFreeBlockThresholdDis 132
PEB.NumberOfHeapsDis 136
PEB.MaximumNumberOfHeapsDis 140
PEB.ProcessHeapsDis 144
PEB.GdiSharedHandleTableDis 148
PEB.ProcessStarterHelperDis 152
PEB.GdiDCAttributeListDis 156
PEB.LoaderLockDis 160
PEB.OSMajorVersionDis 164
PEB.OSMinorVersionDis 168
PEB.OSBuildNumberDis 172
PEB.OSPlatformIdDis 176
PEB.ImageSubSystemDis 180
PEB.ImageSubSystemMajorVersionDis 184
PEB.ImageSubSystemMinorVersionDis 188
PEB.ImageProcessAffinityMaskDis 192
PEB.GdiDBufferDis 196
PEB.PostProcessInitRoutineDis 332
PEB.TlsExpansionBitmapDis 336
PEB.TlsExpansionBitmapBitsDis 340
PEB.SessionIdDis 468]

[TEXT_INFO.ReservedDis 0
TEXT_INFO.SystemStringsDis 4]

[Size_Of_TEXT_INFO 8]

Proc GetBaseStaticServerFromTEB:
    Arguments @pOutput
    Uses edi

    mov edi D@pOutput
    mov eax D$fs:TEB.Tib.SelfDis ; retrieve TEB structure for the current process
    mov eax D$eax+TEB.PebDis ; pointer to a PEB structure
    mov eax D$eax+PEB.ReadOnlyStaticServerDataDis ; retrieve the ReadOnlyStaticServerData (a TEXT_INFO structure)
    mov eax D$eax+TEXT_INFO.SystemStringsDis ; pointer to a BASE_STATIC_SERVER_DATA structure and not a SYSTEM_STRINGS structure (eah member points to a UNICODE_STRING String)
    mov D$edi eax

EndP


Equates :
PROCESS_BASICINFORMATION = 0
PROCESS_AFFINITYMASK = 21
STATUS_SUCCESS = 0

or, another version of GetProcessAffinityMask
Alternative version

Proc GetProcessAffinityMask:
    Arguments @hProcess, @lpProcessAffinityMask, @lpSystemAffinityMask
    Structure @PROCESS_BASIC_INFORMATION 24, @PROCESS_BASIC_INFORMATION.ExitStatusDis 0,
              @PROCESS_BASIC_INFORMATION.PebBaseAddressDis 4, @PROCESS_BASIC_INFORMATION.AffinityMaskDis 8,
              @PROCESS_BASIC_INFORMATION.BasePriorityDis 12, @PROCESS_BASIC_INFORMATION.UniqueProcessIdDis 16,
              @PROCESS_BASIC_INFORMATION.InheritedFromUniqueProcessIdDis 20
    Uses ecx, edx

    call 'Ntdll.NtQueryInformationProcess' D@hProcess, &PROCESS_BASICINFORMATION,
                                           D@PROCESS_BASIC_INFORMATION, Size_of_PROCESS_BASIC_INFORMATION, 0
    If eax <> &STATUS_SUCCESS
        call BaseSetLastNTError eax
        xor eax eax
    Else
       
        ; Copy the affinity mask, and get the system one from our shared data
        mov ecx D@lpProcessAffinityMask
        mov eax D@PROCESS_BASIC_INFORMATION.AffinityMaskDis | mov D$ecx eax

        mov ecx D@lpSystemAffinityMask
        mov eax D@PROCESS_BASIC_INFORMATION.PebBaseAddressDis | mov eax D$eax+PEB.ReadOnlyStaticServerDataDis
        mov eax D$eax+TEXT_INFO.SystemStringsDis | mov eax D$eax+BASE_STATIC_SERVER_DATA.SysInfo.NumberOfProcessorsDis
        mov D$ecx eax
        mov eax &TRUE
    End_If

EndP
Coding in Assembly requires a mix of:
80% of brain, passion, intuition, creativity
10% of programming skills
10% of alcoholic levels in your blood.

My Code Sites:
http://rosasm.freeforums.org
http://winasm.tripod.com