- Usage. Do not write in assembly unless you have a good reason to do so, e.g. a hobby, tool-chain related issues, etc.
- Modularization. Keep code units rather small. This does not necessarily mean that you need to split procedures into subprocedures but modern assemblers are good at "including" files so build your programs by "including" small units into bigger units. Do not go too far, i.e. avoid long dependency chains.
- Registers. As far as I know, this is one of the biggest problems. Be absolutely sure which registers are preserved and which are not. It may be convenient to have some kind of "dependency barriers" along the way. For example, "from this point on I know the exact state of the registers and any modifications before this point do not have any effect." It is a form of art to do this with minimum overhead.
- Calling convention. Related to the previous points. Have a strict calling convention for "public interfaces". Although debatable, I recommend having the "callee saves all but return values" approach. Internal procedures can be rather liberal and that is one of the advantages of assembly programming.
- Meta programming. Use macros or other helper tools if creating long and repetitive code sections. Usually much less error-prone.
- Macros, defines, etc. A contradictory topic. Useful if done right. Extremely bad if done wrong. It is easy to vefify the code if you know exactly what it does.
- Comments. Rules are simple: use comments almost everywhere.
Assembly programming advices and ideas
Assembly programming advices and ideas
A little rambling topic in between important topics. Let see whether it takes off or not. I have been programming in assembly for some time now and I would like to list some rather obvious advices. This is not a comprehensive list but just a few random thoughts.
- max
- Member
- Posts: 616
- Joined: Mon Mar 05, 2012 11:23 am
- Libera.chat IRC: maxdev
- Location: Germany
- Contact:
Re: Assembly programming advices and ideas
Aggree to all of these, except:
- Calling convention. Have a strict calling convention for "public interfaces". Callee saves only registers that it modifies, except the ones used for return.
Re: Assembly programming advices and ideas
Internal procedures could be like "static functions" in C. It is much more flexible to have loose rules for them.max wrote:I disagree on the internal procedures part; they should follow the same convention, otherwise they could trash stuff.
If those procedures, both A and B, are in the same module, it is possible that both of them use the same internal procedure.max wrote:if public procedure A and public procedure B both might use it, the problems begin.
-
- Member
- Posts: 501
- Joined: Wed Jun 17, 2015 9:40 am
- Libera.chat IRC: glauxosdever
- Location: Athens, Greece
Re: Assembly programming advices and ideas
Hi,
Programming in assembly can be entertaining and you might gain something from it, but it can also be sometimes very frustrating. I think this topic isn't really that rambling, but rather useful for everyone programming in assembly.
I agree modules should be small. This way they are more maintainable.
Now, about registers: As Antti said, always make sure which registers are preserved and which are restored. To make sure, push all used registers at the start of the call and restore them when done, so you can remain quiet that they were not altered by the call. The same goes with variables too.
I prefer not using macros, because they add executable code without noticing it. Use calls wherever possible, except you want to optimize your code for speed. Constants are fine.
Always document your code. At each call, document input and output values so you pass these that are needed for the call. Describe carefully what is the function of each register inside each call. Put local labels every 5-10 lines inside each call, that describe what's going on in the next 5-10 lines, even if there are no jumps to them. Comment every single line of code.
Try to write with least lines of code possible. Assembly is generally hard to read (optimized or not), so don't make it even harder by writing lengthy code.
I hope this was useful advise.
Regards,
glauxosdever
Programming in assembly can be entertaining and you might gain something from it, but it can also be sometimes very frustrating. I think this topic isn't really that rambling, but rather useful for everyone programming in assembly.
I agree modules should be small. This way they are more maintainable.
Now, about registers: As Antti said, always make sure which registers are preserved and which are restored. To make sure, push all used registers at the start of the call and restore them when done, so you can remain quiet that they were not altered by the call. The same goes with variables too.
I prefer not using macros, because they add executable code without noticing it. Use calls wherever possible, except you want to optimize your code for speed. Constants are fine.
Always document your code. At each call, document input and output values so you pass these that are needed for the call. Describe carefully what is the function of each register inside each call. Put local labels every 5-10 lines inside each call, that describe what's going on in the next 5-10 lines, even if there are no jumps to them. Comment every single line of code.
Try to write with least lines of code possible. Assembly is generally hard to read (optimized or not), so don't make it even harder by writing lengthy code.
I hope this was useful advise.
Regards,
glauxosdever
Re: Assembly programming advices and ideas
It is not always good. For example, sometimes unrolling a short loop can make code much more readable.glauxosdever wrote:Try to write with least lines of code possible.
-
- Member
- Posts: 501
- Joined: Wed Jun 17, 2015 9:40 am
- Libera.chat IRC: glauxosdever
- Location: Athens, Greece
Re: Assembly programming advices and ideas
Hi,
Antti: Generally, writing less code is most times better, because code that doesn't exist has no bugs and you can maintain it more easily. There are always cases where writing more lines can make code more readable, but these are less usual than the other cases.
You can save lines by avoiding unnecessary CMP instructions. For example a CMP ECX, 0 is pointless after a DEC ECX because DEC instruction will set the zero flag if ECX equals 0.
You can also use registers instead of main memory to store values. Moving a value from memory to memory can't be done in one single instruction, instead a register will be needed between. Writing to registers is faster compared to writing to memory, so for loops that are executed several thousands of times per second, it is really better to use registers for storage; the speedup will be noticeable.
Also, if you want to push general purpose registers all-in-one, you can use the PUSHA/PUSHAD instruction, and to pop them all-in-one, you can use the POPA/POPAD instruction.
There are also other size optimization tricks that I'm not aware now. They could make code not only more readable, but also faster.
Regards,
glauxosdever
Antti: Generally, writing less code is most times better, because code that doesn't exist has no bugs and you can maintain it more easily. There are always cases where writing more lines can make code more readable, but these are less usual than the other cases.
You can save lines by avoiding unnecessary CMP instructions. For example a CMP ECX, 0 is pointless after a DEC ECX because DEC instruction will set the zero flag if ECX equals 0.
You can also use registers instead of main memory to store values. Moving a value from memory to memory can't be done in one single instruction, instead a register will be needed between. Writing to registers is faster compared to writing to memory, so for loops that are executed several thousands of times per second, it is really better to use registers for storage; the speedup will be noticeable.
Also, if you want to push general purpose registers all-in-one, you can use the PUSHA/PUSHAD instruction, and to pop them all-in-one, you can use the POPA/POPAD instruction.
There are also other size optimization tricks that I'm not aware now. They could make code not only more readable, but also faster.
Regards,
glauxosdever
Re: Assembly programming advices and ideas
Although, in practice, the DEC ECX is probably unnecessary; more likely you would just use a LOOP.You can save lines by avoiding unnecessary CMP instructions. For example a CMP ECX, 0 is pointless after a DEC ECX because DEC instruction will set the zero flag if ECX equals 0.
I would say that it is probably better to PUSH/POP registers individually; you rarely need to save all of them. In any case, the PUSHA/POPA instructions are unavailable in 64-bit mode and I would imagine that those looking to the future will be looking at 64-bit code.Also, if you want to push general purpose registers all-in-one, you can use the PUSHA/PUSHAD instruction, and to pop them all-in-one, you can use the POPA/POPAD instruction.
Re: Assembly programming advices and ideas
There is one trick trick if, for some reason, you want to preserve registers.glauxosdever wrote:instead a register will be needed between
Code: Select all
push dword [SOURCE]
pop dword [DESTINATION]
- TightCoderEx
- Member
- Posts: 90
- Joined: Sun Jan 13, 2013 6:24 pm
- Location: Grande Prairie AB
Re: Assembly programming advices and ideas
USAGE:
My personal preference is, when I write this;I see this disassembly
So there is a one to one correlation between source and object. WYSIWYG in essence. As my project is focused strictly on X86 and BIOS, tools like FASM & NASM are sufficient and my project is not dependant file systems or shared libraries.
MODULARIZATION:
I don't concern myself too much with size, but keep subject matter contained. As an example, currently I'm working on a comprehensive algo to display text on an 80 x 25 (16 color) display that uses characters (1 - 31) for special functions and formatting in one file. Then there will be another for conversion routines Binary -> ASCIIZ and vise versa.
REGISTERS
As I've done quite a bit of Win32 programming, I've adopted M$ preserve everything except EAX, ECX & EDX. This is predicated entirely on specifics of routine, but it is a general rule of thumb I use. Because of this, I've also adopted CDECL calling convention. LEAVE or MOV ESP, EBP at epilogue is a convenient means by which to make sure stack doesn't get out of control.
I never use macros or any higher level constructs, but amply document my code although previous example doesn't show it.
My personal preference is, when I write this;
Code: Select all
@@: mov ah, [edi - 1]
mov al, ' '
push edi
rep stosw
mov cl, dl
inc ch
pop edi
pop esi
Code: Select all
00000040 8A67FF mov ah,[edi-0x1]
00000043 B020 mov al,0x20
00000045 57 push edi
00000046 F366AB rep stosw
00000049 88D1 mov cl,dl
0000004B FEC5 inc ch
0000004D 5F pop edi
0000004E 5E pop esi
MODULARIZATION:
I don't concern myself too much with size, but keep subject matter contained. As an example, currently I'm working on a comprehensive algo to display text on an 80 x 25 (16 color) display that uses characters (1 - 31) for special functions and formatting in one file. Then there will be another for conversion routines Binary -> ASCIIZ and vise versa.
REGISTERS
As I've done quite a bit of Win32 programming, I've adopted M$ preserve everything except EAX, ECX & EDX. This is predicated entirely on specifics of routine, but it is a general rule of thumb I use. Because of this, I've also adopted CDECL calling convention. LEAVE or MOV ESP, EBP at epilogue is a convenient means by which to make sure stack doesn't get out of control.
I never use macros or any higher level constructs, but amply document my code although previous example doesn't show it.
Re: Assembly programming advices and ideas
Although this is compact in size, I am not sure whether it is actually faster or not. The real problem comes when your procedures have return values. Usually there are not that much registers you need to push/pop, so single pushes and pops may be better. On x86-64 that is the only option.glauxosdever wrote:Also, if you want to push general purpose registers all-in-one, you can use the PUSHA/PUSHAD instruction, and to pop them all-in-one, you can use the POPA/POPAD instruction.