flat assembler
Message board for the users of flat assembler.

Index > Tutorials and Examples > Code Construction questions for beginners

Author
Thread Post new topic Reply to topic
BilboLaggins



Joined: 02 Apr 2020
Posts: 2
BilboLaggins 29 Jan 2023, 17:36
Three questions using FAsm 1.73.29 with the attached source:

1. Why does the custom proc need to be before the _start:? To demonstrate the question, assemble and run to see the correct seven lines of output. Then move the proc to after the _start: by swapping the commented-status of lines 21 and 36. Assemble and run to see the wrong one line of output. What is happening?

The design goal is to put the proc and its string definitions into their own Include-file, then assembled into their own OBJ for inclusion in a LIB. How is all that supposed to work relative to .data and .code sections?

2. Why does a standard proc like printf need square brackets "call [printf]" when a custom proc does not "call BoolPrint"?

3. What setup is necessary to allow invoke-ing a custom proc?


Description:
Download
Filename: Demo1.ASM
Filesize: 5.19 KB
Downloaded: 351 Time(s)

Post 29 Jan 2023, 17:36
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1044
Location: Russia
macomics 29 Jan 2023, 19:26
BilboLaggins wrote:
What is happening?

1) Because the transition takes place strictly on the _start label, and immediately after this label on line 24 there is a subroutine, the execution of which begins. At the same time, the program does not even receive the correct set of parameters because it is not intended to be executed as a startup routine.

BilboLaggins wrote:
How is all that supposed to work relative to .data and .code sections?

2) Then you should not create a PE file. Create a COFF or MSCOFF.

BilboLaggins wrote:
Why does a standard proc like printf need square brackets "call [printf]" when a custom proc does not "call BoolPrint"?

3) The addresses of those procedures that are in your program are calculated by the assembler at the compilation stage. The addresses of printf type procedures are values calculated by another program (loader) and placed in an array according to the corresponding memory cells. The addresses of these cells must be specified in [] so that the recorded information is read from this variable and the call occurs at an indirect address.

BilboLaggins wrote:
3. What setup is necessary to allow invoke-ing a custom proc?
You need to call the CreateProcess function after filling in the required structures.
Post 29 Jan 2023, 19:26
View user's profile Send private message Reply with quote
Tomasz Grysztar



Joined: 16 Jun 2003
Posts: 8359
Location: Kraków, Poland
Tomasz Grysztar 29 Jan 2023, 20:06
macomics wrote:
BilboLaggins wrote:
3. What setup is necessary to allow invoke-ing a custom proc?
You need to call the CreateProcess function after filling in the required structures.
I'm under the impression that the question concerned use of the "invoke" macro to call own procedures.

If you look at the INCLUDE/MACRO/PROC32.INC, where the "invoke" is defined, you may notice that there is also an "stdcall" macro that does the same thing, except it call the procedure directly, not through a pointer:
Code:
macro stdcall proc,[arg]                ; directly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
    pushd arg
   common
    end if
    call proc }

macro invoke proc,[arg]                 ; indirectly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
     pushd arg
   common
    end if
    call [proc] }    
So to call local function like "BoolPrint" you can use "stdcall" macro:
Code:
stdcall BoolPrint, argument    
To be able to use "invoke", you'd need to store the address of this function into some pointer variable:
Code:
pBoolPrint dd BoolPrint    
and then:
Code:
invoke pBoolPrint, argument    
which is in fact the same as:
Code:
stdcall [pBoolPrint], argument    
Post 29 Jan 2023, 20:06
View user's profile Send private message Visit poster's website Reply with quote
BilboLaggins



Joined: 02 Apr 2020
Posts: 2
BilboLaggins 29 Jan 2023, 20:38
macomics wrote:
BilboLaggins wrote:
What is happening?
1) Because the transition takes place strictly on the _start label, and immediately after this label on line 24 there is a subroutine, the execution of which begins. At the same time, the program does not even receive the correct set of parameters because it is not intended to be executed as a startup routine.
Ah okay that should have been obvious because the wrong output exactly matches the subroutine. The program then just rets out without ever hitting Main nor ExitProcess.
1a) [program execution begins immediately after] the _start label, [regardless of what code is there].
macomics wrote:
BilboLaggins wrote:
How is all that supposed to work relative to .data and .code sections?
Then you should not create a PE file. Create a COFF or MSCOFF.
1b) [Create a COFF not an EXE].
COFF for OBJ=>LIB yes that makes sense for step two. Sorry the question didn't match the code for step one: in case of moving the subroutine and its data strings out to an include file, does it matter where the include statement goes, like in the .data section versus in .code section? OR, would two separate includes and files be better?
macomics wrote:
BilboLaggins wrote:
Why does a standard proc like printf need square brackets "call [printf]" when a custom proc does not "call BoolPrint"?
2) The addresses of those procedures that are in your program are calculated by the assembler at the compilation stage. The addresses of printf type procedures are values calculated by another program (loader) and placed in an array according to the corresponding memory cells. The addresses of these cells must be specified in [] so that the recorded information is read from this variable and the call occurs at an indirect address.
Cool in other words, the call address for custom procs is known at compile-time, so the assembler translates from the proc-name symbol to the call-address, and the linker doesn't need to touch it. In contrast, the call address for linked procs is not known until link-time. The way FAsm is implemented, it builds basically a jump-table for linked procs, which is populated at link-time and used at run-time. The proc-name symbol becomes a pointer into the jump-table, so the "call [Brackets]" sort of looks up the real call-address at call-time. Is that a reasonable way to understand it?

Thinking that even though printf at this level looks like a statically-linked proc say from a C library, programs which include 'Win32A.INC' make printf boil down to a WinAPI call, which are all dynamically-linked (it's how we can get a 2K EXE). Thus for Windows programs the real call-address is not known until program-load time, so the jump-table is totally necessary.

In case of a program with actual static linking, does FAsm still use a jump-table, or is it able to resolve the real call-address at link-time, thus not needing a jump-table and allowing "call NoBrackets" for library routines?
macomics wrote:
BilboLaggins wrote:
3. What setup is necessary to allow invoke-ing a custom proc?
You need to call the CreateProcess function after filling in the required structures.
Nice, that would be the WinAPI for launching/spawning other/child processes/programs. [this question is answered in another reply.] If push+call are explicit CPU instructions, and invoke is an assembler macro, then is stdcall an assembler intrinsic?

Thank you for taking the time to reply!
Post 29 Jan 2023, 20:38
View user's profile Send private message Reply with quote
macomics



Joined: 26 Jan 2021
Posts: 1044
Location: Russia
macomics 30 Jan 2023, 03:22
BilboLaggins wrote:
1a) [program execution begins immediately after] the _start label, [regardless of what code is there].
This can be observed when using step-by-step debugging using a debugger program (for example, OllyDbg, x64dbg)

BilboLaggins wrote:
Sorry the question didn't match the code for step one: in case of moving the subroutine and its data strings out to an include file, does it matter where the include statement goes, like in the .data section versus in .code section? OR, would two separate includes and files be better?
If you just want to create the included code (using the include directive), then you should divide into blocks that are connected to the desired section. At the same time, you will have different files.

When creating an OBJ file, there may be different sections in it and the linker collects them all together from all files. At the same time, you do not need various plug-in files.

BilboLaggins wrote:
Is that a reasonable way to understand it?
Only these are not fasm, but the requirements of the file format (PE). It is in the PE file that you need to create such structures that will be filled in by the loader when the file is loaded into memory (the program is running). But there is also a linker that can connect binary files (OBJ) to each other. Then the same principle is used, only the first (loader) performs linking upon loading (the base address of loading different modules), and the second (linker) performs a connection within the image of a single file loaded into memory.

BilboLaggins wrote:
In case of a program with actual static linking, does FAsm still use a jump-table, or is it able to resolve the real call-address at link-time, thus not needing a jump-table and allowing "call NoBrackets" for library routines?
When loading a program into memory, no static linking is used for execution. Dynamic only. Static linking can only be performed when assembling a PE EXE file from different OBJ.

Static linking when loading a file for execution is simply impossible because for different operating systems and on different computers there will be a different set of modules loaded into memory at the start of the program.

Not to mention the fact that the base loading addresses of the same modules can change from version to version.
Let's say in Windows XP the module kernel32.dll (I do not know how much it really weighs, this is just an example) It weighs 1 MB and is loaded at (2 GB - 1 MB = 0x7FE000000). But in Windows 7, the same module was supplemented with code, data and now occupies 1.5 MB (while its base load address changed and became (2 GB - 1.5 MB = 0x7FD800000)). In this case, the addresses of the functions from this module in the first case will be in the address range [0x7FE01000 - 0x7FFFFFFF], in the second - [0x7FD1000 - 0x7FFFFFFF].

All of the above is just an example. But he is not far from the truth and clearly (in numbers) should demonstrate the process of linking different modules when loading into memory.

BilboLaggins wrote:
macomics wrote:
You need to call the CreateProcess function after filling in the required structures.


Nice, that would be the WinAPI for launching/spawning other/child processes/programs. [this question is answered in another reply.] If push+call are explicit CPU instructions, and invoke is an assembler macro, then is stdcall an assembler intrinsic?

Thank you for taking the time to reply!
Fasm does not have these intrinsic directives. Both invoke and stdcall are macro instructions.

The author of fasm1 showed the full implementation of these macros in his answer
Tomasz Grysztar wrote:
Code:
macro stdcall proc,[arg]                ; directly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
    pushd arg
   common
    end if
    call proc }

macro invoke proc,[arg]                 ; indirectly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
     pushd arg
   common
    end if
    call [proc] }     
Their differences are only in the presence of [] in the call command

P. S. I didn't think about that when answering the last question.
Post 30 Jan 2023, 03:22
View user's profile Send private message Reply with quote
edfed



Joined: 20 Feb 2006
Posts: 4353
Location: Now
edfed 30 Jan 2023, 15:00
Tomasz Grysztar wrote:
Code:
macro stdcall proc,[arg]                ; directly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
    pushd arg
   common
    end if
    call proc }

macro invoke proc,[arg]                 ; indirectly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
     pushd arg
   common
    end if
    call [proc] }    



how can it becomes like:
Code:
macro stdcall proc,[arg]                ; directly call STDCALL procedure
 { common
    if ~ arg eq
   reverse
    pushd arg
   common
    end if
    call proc }

macro invoke proc,[arg]                 ; indirectly call STDCALL procedure
 { stdcall [proc],arg }    


this construct can help a lot to make heritage.
Post 30 Jan 2023, 15:00
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 20461
Location: In your JS exploiting you and your system
revolution 30 Jan 2023, 18:17
DRY vs WET

Those links are WET.. They lead to the same page. Razz
Post 30 Jan 2023, 18:17
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.