News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

How to calculate the size of a PROC?

Started by frktons, September 13, 2010, 12:12:56 AM

Previous topic - Next topic

frktons

I've just finished the preliminary test with the ASCII program, and it is
quite difficult to say how bigger the executable has become after adding
some PROCs.

I added some 300 instructions more or less, but the executable size is still 3.584 bytes
like the executable without these PROCs.

So there is surely a better way to tell how many bytes a PROC or a group of
PROCs take.

I attach the two versions of the program, before and after adding the new code.
Could somebody tell me how bigger the new prog [ascii_3.asm] is?

Thanks

Frank
Mind is like a parachute. You know what to do in order to use it :-)

clive

Looking at the EXE is a poor approach as it often reflects the paging/alignment of the file.

Use the -Fl option to generate a LST listing file. Examine the listing as it contains details of segments and procedures.

Microsoft (R) Macro Assembler Version 6.15.8803            05/01/10 16:01:09
proc.asm                             Page 1 - 1


                .386
                .model flat,stdcall

00000000            .code

00000000            TestFunction proc
00000000  55              push ebp
00000001  8B EC          mov ebp, esp

00000003  8B E5          mov esp, ebp
00000005  5D              pop ebp
00000006  C3              ret 0
00000007            TestFunction endp
                end
Microsoft (R) Macro Assembler Version 6.15.8803            05/01/10 16:01:09
proc.asm                             Symbols 2 - 1




Segments and Groups:

                N a m e                 Size     Length   Align   Combine Class

FLAT . . . . . . . . . . . . . .    GROUP
_DATA  . . . . . . . . . . . . .    32 Bit     00000000 DWord      Public  'DATA'
_TEXT  . . . . . . . . . . . . .    32 Bit     00000007 DWord      Public  'CODE'


Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

TestFunction . . . . . . . . . .    P Near     00000000 _TEXT    Length= 00000007 Public STDCALL


Symbols:

                N a m e                 Type     Value    Attr

@CodeSize  . . . . . . . . . . .    Number     00000000h
@DataSize  . . . . . . . . . . .    Number     00000000h
@Interface . . . . . . . . . . .    Number     00000003h
@Model . . . . . . . . . . . . .    Number     00000007h
@code  . . . . . . . . . . . . .    Text        _TEXT
@data  . . . . . . . . . . . . .    Text        FLAT
@fardata?  . . . . . . . . . . .    Text        FLAT
@fardata . . . . . . . . . . . .    Text        FLAT
@stack . . . . . . . . . . . . .    Text        FLAT

       0 Warnings
       0 Errors


Get the linker to generate a MAP file by using the  /MAP option, or -link /MAP on the MASM command line. The MAP file will get details of the actual section sizes.

Debug information also contains useful data, certain CODEVIEW and FPO records contain data about procedure size.

ASCII.LST
Segments and Groups:

                N a m e                 Size     Length   Align   Combine Class

FLAT . . . . . . . . . . . . . .    GROUP
_BSS . . . . . . . . . . . . . .    32 Bit     00001F80 Para      Public  'BSS'
_DATA  . . . . . . . . . . . . .    32 Bit     00000063 Para      Public  'DATA'
_TEXT  . . . . . . . . . . . . .    32 Bit     000001BF Para      Public  'CODE'


ASCII_3.LST
Segments and Groups:

                N a m e                 Size     Length   Align   Combine Class

FLAT . . . . . . . . . . . . . .    GROUP
_BSS . . . . . . . . . . . . . .    32 Bit     00001F80 Para      Public  'BSS'
_DATA  . . . . . . . . . . . . .    32 Bit     00000065 Para      Public  'DATA'
_TEXT  . . . . . . . . . . . . .    32 Bit     0000032D Para      Public  'CODE'


There is a lot of chaff from all the stuff you've imported in the "Procedures,  parameters and locals:", it will take a minute or two to winnow that down to something more useful.
It could be a random act of randomness. Those happen a lot as well.

frktons

Thanks Clive, I've a lot to learn about those stuff yet.

Well, I was thinking about a simpler but perhaps unsuitable way of
counting the bytes, something like the use of the Current Address [$]
operator.

It is simpler, but I don't know if it is usable for the task:


a PROC
....
a ENDP

b PROC
....
b ENDP

c PROC

SizeProcs = ($ - a)
mov eax, SizeProcs
print "The size of a-b procs is about: "
print eax
inkey

c ENDP


The current address operator works fine with .DATA SECTION
but I don't know if it can be used for the .CODE SECTION as well.  ::)

Mind is like a parachute. You know what to do in order to use it :-)

clive

That would be workable, I'd look at the data in the object file myself.

Here is the data from the .LST files with the extraneous stuff removed.

ASCII

Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

AnyKey . . . . . . . . . . . . .    P Near     00000194 _TEXT    Length= 0000002B Public STDCALL
  again  . . . . . . . . . . . .    L Near     00000194 _TEXT
ConsoleSize  . . . . . . . . . .    P Near     00000030 _TEXT    Length= 00000033 Public STDCALL
DisplayFmt . . . . . . . . . . .    P Near     0000016E _TEXT    Length= 00000026 Public STDCALL
  szFmtName  . . . . . . . . . .    DWord     bp + 00000008
GetConsole . . . . . . . . . . .    P Near     00000063 _TEXT    Length= 00000054 Public STDCALL
  szFmtName  . . . . . . . . . .    DWord     bp + 00000008
HideTheCursor  . . . . . . . . .    P Near     000000E2 _TEXT    Length= 0000002B Public STDCALL
InitProc . . . . . . . . . . . .    P Near     0000010D _TEXT    Length= 00000061 Public STDCALL
Main . . . . . . . . . . . . . .    P Near     00000000 _TEXT    Length= 00000030 Public STDCALL
  finish . . . . . . . . . . . .    L Near     00000028 _TEXT
ShowTheCursor  . . . . . . . . .    P Near     000000B7 _TEXT    Length= 0000002B Public STDCALL


ASCII_3

Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

AnyKey . . . . . . . . . . . . .    P Near     00000302 _TEXT    Length= 0000002B Public STDCALL
  again  . . . . . . . . . . . .    L Near     00000302 _TEXT
BoxLine  . . . . . . . . . . . .    P Near     000000F3 _TEXT    Length= 00000017 Public STDCALL
  FillBoxLine  . . . . . . . . .    L Near     00000102 _TEXT
BuildBox . . . . . . . . . . . .    P Near     00000080 _TEXT    Length= 00000073 Public STDCALL
  Row1 . . . . . . . . . . . . .    DWord     bp + 00000008
  Row2 . . . . . . . . . . . . .    DWord     bp + 0000000C
  FillBorder . . . . . . . . . .    L Near     000000C1 _TEXT
BuildConsole . . . . . . . . . .    P Near     0000005E _TEXT    Length= 00000022 Public STDCALL
ConsoleSize  . . . . . . . . . .    P Near     0000002B _TEXT    Length= 00000033 Public STDCALL
DisplayFmt . . . . . . . . . . .    P Near     000002DC _TEXT    Length= 00000026 Public STDCALL
  szFmtName  . . . . . . . . . .    DWord     bp + 00000008
DisplaySequence  . . . . . . . .    P Near     0000010A _TEXT    Length= 000000DF Public STDCALL
  PrintCol . . . . . . . . . . .    L Near     0000012B _TEXT
  CarryOn  . . . . . . . . . . .    L Near     0000013F _TEXT
  IncTen . . . . . . . . . . . .    L Near     00000197 _TEXT
  HundredCheck . . . . . . . . .    L Near     000001AD _TEXT
  IncHundred . . . . . . . . . .    L Near     000001BF _TEXT
  NextCol  . . . . . . . . . . .    L Near     000001C5 _TEXT
  NextRow  . . . . . . . . . . .    L Near     000001D7 _TEXT
  EndCycle . . . . . . . . . . .    L Near     000001E8 _TEXT
HideTheCursor  . . . . . . . . .    P Near     00000250 _TEXT    Length= 0000002B Public STDCALL
InitProc . . . . . . . . . . . .    P Near     0000027B _TEXT    Length= 00000061 Public STDCALL
Main . . . . . . . . . . . . . .    P Near     00000000 _TEXT    Length= 0000002B Public STDCALL
  finish . . . . . . . . . . . .    L Near     00000023 _TEXT
SetBufferColor . . . . . . . . .    P Near     00000211 _TEXT    Length= 00000014 Public STDCALL
ShowTheCursor  . . . . . . . . .    P Near     00000225 _TEXT    Length= 0000002B Public STDCALL
WriteScreenTitle . . . . . . . .    P Near     000001E9 _TEXT    Length= 00000028 Public STDCALL
  WriteTitle . . . . . . . . . .    L Near     00000201 _TEXT
It could be a random act of randomness. Those happen a lot as well.

frktons

Quote from: clive on September 13, 2010, 01:01:32 AM
That would be workable, I'd look at the data in the object file myself.

Here is the data from the .LST files with the extraneous stuff removed.

ASCII

Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

AnyKey . . . . . . . . . . . . .    P Near     00000194 _TEXT    Length= 0000002B Public STDCALL
  again  . . . . . . . . . . . .    L Near     00000194 _TEXT
ConsoleSize  . . . . . . . . . .    P Near     00000030 _TEXT    Length= 00000033 Public STDCALL
DisplayFmt . . . . . . . . . . .    P Near     0000016E _TEXT    Length= 00000026 Public STDCALL
  szFmtName  . . . . . . . . . .    DWord     bp + 00000008
GetConsole . . . . . . . . . . .    P Near     00000063 _TEXT    Length= 00000054 Public STDCALL
  szFmtName  . . . . . . . . . .    DWord     bp + 00000008
HideTheCursor  . . . . . . . . .    P Near     000000E2 _TEXT    Length= 0000002B Public STDCALL
InitProc . . . . . . . . . . . .    P Near     0000010D _TEXT    Length= 00000061 Public STDCALL
Main . . . . . . . . . . . . . .    P Near     00000000 _TEXT    Length= 00000030 Public STDCALL
  finish . . . . . . . . . . . .    L Near     00000028 _TEXT
ShowTheCursor  . . . . . . . . .    P Near     000000B7 _TEXT    Length= 0000002B Public STDCALL


ASCII_3

Procedures,  parameters and locals:

                N a m e                 Type     Value    Attr

AnyKey . . . . . . . . . . . . .    P Near     00000302 _TEXT    Length= 0000002B Public STDCALL
  again  . . . . . . . . . . . .    L Near     00000302 _TEXT
BoxLine  . . . . . . . . . . . .    P Near     000000F3 _TEXT    Length= 00000017 Public STDCALL
  FillBoxLine  . . . . . . . . .    L Near     00000102 _TEXT
BuildBox . . . . . . . . . . . .    P Near     00000080 _TEXT    Length= 00000073 Public STDCALL
  Row1 . . . . . . . . . . . . .    DWord     bp + 00000008
  Row2 . . . . . . . . . . . . .    DWord     bp + 0000000C
  FillBorder . . . . . . . . . .    L Near     000000C1 _TEXT
BuildConsole . . . . . . . . . .    P Near     0000005E _TEXT    Length= 00000022 Public STDCALL
ConsoleSize  . . . . . . . . . .    P Near     0000002B _TEXT    Length= 00000033 Public STDCALL
DisplayFmt . . . . . . . . . . .    P Near     000002DC _TEXT    Length= 00000026 Public STDCALL
  szFmtName  . . . . . . . . . .    DWord     bp + 00000008
DisplaySequence  . . . . . . . .    P Near     0000010A _TEXT    Length= 000000DF Public STDCALL
  PrintCol . . . . . . . . . . .    L Near     0000012B _TEXT
  CarryOn  . . . . . . . . . . .    L Near     0000013F _TEXT
  IncTen . . . . . . . . . . . .    L Near     00000197 _TEXT
  HundredCheck . . . . . . . . .    L Near     000001AD _TEXT
  IncHundred . . . . . . . . . .    L Near     000001BF _TEXT
  NextCol  . . . . . . . . . . .    L Near     000001C5 _TEXT
  NextRow  . . . . . . . . . . .    L Near     000001D7 _TEXT
  EndCycle . . . . . . . . . . .    L Near     000001E8 _TEXT
HideTheCursor  . . . . . . . . .    P Near     00000250 _TEXT    Length= 0000002B Public STDCALL
InitProc . . . . . . . . . . . .    P Near     0000027B _TEXT    Length= 00000061 Public STDCALL
Main . . . . . . . . . . . . . .    P Near     00000000 _TEXT    Length= 0000002B Public STDCALL
  finish . . . . . . . . . . . .    L Near     00000023 _TEXT
SetBufferColor . . . . . . . . .    P Near     00000211 _TEXT    Length= 00000014 Public STDCALL
ShowTheCursor  . . . . . . . . .    P Near     00000225 _TEXT    Length= 0000002B Public STDCALL
WriteScreenTitle . . . . . . . .    P Near     000001E9 _TEXT    Length= 00000028 Public STDCALL
  WriteTitle . . . . . . . . . .    L Near     00000201 _TEXT


Thanks clive.

The New PROCs are:

1) BoxLine     Length= 00000017
2) BuildBox . .Length= 00000073
3) BuildConsole . .  Length= 00000022
4) DisplaySequence  Length= 000000DF
5) SetBufferColor . . Length= 00000014
6) WriteScreenTitle . Length= 00000028

Minus the removed ones:

1) GetConsole . . Length= 00000054

Time to add and subtract.  :lol

Edit: 371 bytes. Not bad, considering we started with a 8.000 bytes file.  :P
And the program is not optimized for size yet.
Mind is like a parachute. You know what to do in order to use it :-)

hutch--

Frank,

This is the normal methods used in code. Clive has a good point in that you need to be careful where you put the trailing label as it can pick up extra bytes of alignment padding. NOTE that the two labels are global scope labels with the trailing "::" at the end.


IF 0  ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                      Build this template with "CONSOLE ASSEMBLE AND LINK"
ENDIF ; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include \masm32\include\masm32rt.inc

    .data
      item dd glbl1 - glbl0

    .code

start:
   
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    print str$(item),13,10      ; static result, calculated at assembly time

    mov eax, OFFSET glbl1
    sub eax, OFFSET glbl0
    print str$(eax),13,10       ; dynamic result, calculated at runtime

    call main

    inkey
    exit

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    align 16

    glbl0::

main proc

    print "Get Procedure Length",13,10

    nop     ; add an extra byte

    ret

main endp

    glbl1::

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

end start
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

frktons

Thanks Steve, these are quite handy methods indeed.  :U

The ClearScreen doesn't clear the attribute, so when I use the cls
macro, the attributes remain on the screen.

Somebody suggested a little change to the ClearScreen PROC inside the
MASM32 lib:
http://www.masm32.com/board/index.php?topic=4878.0
and it clears like DOS CLS, also the attributes.

It could be handy to make this change as the author suggested.

Something I've noticed is that the size of the prog grows 512 bytes at a time,
even if not all of them are used.

Frank
Mind is like a parachute. You know what to do in order to use it :-)

hutch--

Frank,

Its easy enough for anyone interested to code up a screen clear algo that has additional attributes but the demand for fancy formating at a console level is now so low that I would not lose much sleep over it. The other factor is once an algo has been around for a while and has ben used by enough people its unwise to change it without breaking someones code.

RE the size increase, its normal depending on the file alignment set with the linker, 512 byte is common and your exe steps up in 512 byte increments.
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

jj2007

Here is a gift from the MasmBasic library. Usage:

QuoteZeProc_s:
ZeProc proc whatever
  ret
ZeProc endp
ZeProc_endp:
include \masm32\include\masm32rt.inc

MyTest PROTO: DWORD, :DWORD

CodeSize MACRO algo
  pushad
  mov eax, offset &algo&_endp
  sub eax, offset &algo&_s
  print str$(eax), 9, " bytes for &algo&", 13, 10
  popad
ENDM

.code
start:
CodeSize MyTest
inkey "Cute..."
exit

MyTest_s:
MyTest proc arg1:DWORD, arg2:DWORD
  MsgBox 0, arg1, arg2, MB_OK
  ret
MyTest endp
MyTest_endp:

end start

frktons

Quote from: jj2007 on September 13, 2010, 07:46:41 AM
Here is a gift from the MasmBasic library. Usage:

QuoteZeProc_s:
ZeProc proc whatever
  ret
ZeProc endp
ZeProc_endp:
include \masm32\include\masm32rt.inc

MyTest PROTO: DWORD, :DWORD

CodeSize MACRO algo
  pushad
  mov eax, offset &algo&_endp
  sub eax, offset &algo&_s
  print str$(eax), 9, " bytes for &algo&", 13, 10
  popad
ENDM

.code
start:
CodeSize MyTest
inkey "Cute..."
exit

MyTest_s:
MyTest proc arg1:DWORD, arg2:DWORD
  MsgBox 0, arg1, arg2, MB_OK
  ret
MyTest endp
MyTest_endp:

end start


Thanks Jochen,

I'll give it a try.  :U
Mind is like a parachute. You know what to do in order to use it :-)

MichaelW

Instead of the redundant label at the start of the procedure, why not just use the procedure name?

sub  eax,  algo

eschew obfuscation

frktons

Quote from: MichaelW on September 13, 2010, 06:45:28 PM
Instead of the redundant label at the start of the procedure, why not just use the procedure name?

sub  eax,  algo

This is the way I'm going too. I don't know why Jochen prefer to use
another label.  ::)

For my personal taste I'd prefer to use the MACRO this way:

include \masm32\include\masm32rt.inc

MyTest PROTO: DWORD, :DWORD

CodeSize MACRO algo
  pushad
  mov eax, offset &algo&_endp
  sub eax, offset &algo&
  print str$(eax), 9, " bytes for &algo&", 13, 10
  popad
ENDM

.code
start:
CodeSize MyTest
inkey "Cute..."
exit


MyTest proc arg1:DWORD, arg2:DWORD
  MsgBox 0, arg1, arg2, MB_OK
  ret
MyTest_endp:: 
MyTest endp


But it is just a question of personal preference. I think it works well
both way.  :U
Mind is like a parachute. You know what to do in order to use it :-)

brethren


clive

Probably because there are many ways to skin the cat. And perhaps it would allow you to account for faux alignment added to a procedure to achieve internal loop alignment where looking at the entry address will not.

In the general case I'd want to automate the tracking of procedure size based on assembler/compiler metrics that they already generate, then again if you only want stats on a few routines for printing/comparison any easy/simple solution with suffice.

Does the size of the executable in bytes +/- a few KB matter on a machine with 2 GB and allocated in quanta of 4 KB pages, I am fairly doubtful.

If you are trying to squeeze some code into a 64 KB or 128 KB ROM the code/data/bss footprints do become more pertinent. In which case the tools are generally smarter to track this kind of thing, and provide HTML reports.

When Microsoft optimizes executable images, they look to reduce the working set (WS, collection of pages most commonly used together), and analyze the call frequency and proximity of subroutines being used together, vs those parts of the code which are barely/rarely visited.
It could be a random act of randomness. Those happen a lot as well.

frktons

I'm trying to squeeze an 8K external file into 250 bytes of code more or less, like a
compressor from DATA to CODE, so all this ADO is about that thing  :P

The MACRO and methods proposed are quite suitable for the task, and
at the same time, looking at the LST/MAP files is something that I need to
learn anyway in order to understand something more about assembling and
linking process as well.  :U



Mind is like a parachute. You know what to do in order to use it :-)