VOGONS


First post, by Exploit

User metadata
Rank Newbie
Rank
Newbie

I have a bunch of Object files for DOS.

They are called:
upcount.obj // counts upwards from 0 to 9 and prints it on the screen
dncount.obj // counts downwards from 9 to 9 and prints each number on the screen
wait.obj // It's delay loop
newline.obj // prints a CRLN
frame.obj // prints an nice frame using upper frame chars of Codepage 437.
https://en.wikipedia.org/wiki/Code_page_437#Character_set

and one main.obj file.

If i create two libraries with the same object files, but in a different order of the object files given to wlib:

wlib lib1.lib +dncount +newline +frame +upcount +wait
wlib lib2.lib +upcount +dncount +wait +newline +frame

And link together an executable with each library:

wlink name prog1 file main lib1.lib
wlink name prog2 file main lib2.lib

Then i get different reproducible runtime speeds for each file:

runtime prog1.exe
Runtime was 4.780220 seconds

runtime prog2.exe
Runtime was 2.472527 seconds

I tried several runs, but prog2 is always faster then prog1 with the time given above.
Even when the lib was created with the same object files.

Why is this so?
Why does creating the lib with a different order of the object file have such a large impact on the runtime speed?

And why doesn't wlib order them automatically in an optimized way?

Reply 1 of 5, by vstrakh

User metadata
Rank Member
Rank
Member

What's the platform you're running it on?
It could be anything - different alignment, or cache-friendly layout of the code. It would be good if you looked into the disassembly of the final executable to see the difference.
Linker does not know the external conditions, so has no information on how to lay it out "better".

Without more details I'd guess the difference is in the alignment of the hot loop in your 'wait' function. If the functions were not explicitly aligned to 2/4 bytes, then the final exe will have functions tightly packed, and the exact location of the busywait loop will depend on the order of functions, which will have different sizes, so it will affect the final location of 'wait' loop depending on their relative position.

Reply 2 of 5, by Exploit

User metadata
Rank Newbie
Rank
Newbie
vstrakh wrote on 2022-10-21, 17:16:

What's the platform you're running it on?

QEMU emulator with KVM.

It could be anything - different alignment, or cache-friendly layout of the code.

Thank you for the hint.

It would be good if you looked into the disassembly of the final executable to see the difference.
Linker does not know the external conditions, so has no information on how to lay it out "better".

The disassembly code of each object file/code is the same. Thus there is only the linker as variable option.

Without more details I'd guess the difference is in the alignment of the hot loop in your 'wait' function. If the functions were not explicitly aligned to 2/4 bytes, then the final exe will have functions tightly packed, and the exact location of the busywait loop will depend on the order of functions, which will have different sizes, so it will affect the final location of 'wait' loop depending on their relative position.

The wait function should be everywhere the same, only the position in the EXE might be different. How can i enforce an alignement with the linker?

Reply 3 of 5, by vstrakh

User metadata
Rank Member
Rank
Member
Exploit wrote on 2022-10-21, 18:12:

The disassembly code of each object file/code is the same. Thus there is only the linker as variable option.

Don't look into object files, look at the whole executable, after the linker did its job.

Exploit wrote on 2022-10-21, 18:12:

The wait function should be everywhere the same, only the position in the EXE might be different.

The content of the function is irrelevant, its absolute position is important.
Jumps to properly aligned addresses are faster than jumps to unaligned, and it's important that the loop jump lands on aligned address.
So look at the whole executable disassembly, compare the absolute addresses of the loop jump target.

Exploit wrote on 2022-10-21, 18:12:

How can i enforce an alignement with the linker?

You do that in the source file. If it's assembler - the usual directive is 'align' or '.align'. If it's other language - consult with your compiler manuals.

Reply 4 of 5, by Exploit

User metadata
Rank Newbie
Rank
Newbie
vstrakh wrote on 2022-10-21, 18:46:
Don't look into object files, look at the whole executable, after the linker did its job. […]
Show full quote
Exploit wrote on 2022-10-21, 18:12:

The disassembly code of each object file/code is the same. Thus there is only the linker as variable option.

Don't look into object files, look at the whole executable, after the linker did its job.

Exploit wrote on 2022-10-21, 18:12:

The wait function should be everywhere the same, only the position in the EXE might be different.

The content of the function is irrelevant, its absolute position is important.
Jumps to properly aligned addresses are faster than jumps to unaligned, and it's important that the loop jump lands on aligned address.
So look at the whole executable disassembly, compare the absolute addresses of the loop jump target.

Exploit wrote on 2022-10-21, 18:12:

How can i enforce an alignement with the linker?

You do that in the source file. If it's assembler - the usual directive is 'align' or '.align'. If it's other language - consult with your compiler manuals.

Thanks a lot. I will check that out but it will take some while.