Warning # 13212: link to ebx in function requiring stack alignment

I am trying to compile the code below with ICC 2018:

__asm { mov ebx, xx ;xx address to registers } 

where xx is of type int16. This is the first instruction inside my function.

I get the following warning with the above assembler code: warning # 13212: link to ebx in a function requiring stack alignment

Surprisingly, when I replaced ebx with eax or esi, I saw a warning. I cannot understand why I see the problem only with ebx, as far as I know, both ebx and eax have the same architecture (32-bit registers).

Also, I did not see a warning when I compiled the same code with ICC 2013.

Can someone help me resolve this warning?

Thanks!

+5
source share
1 answer

The compiler on the select platform (ICC, because it mimics the behavior of MSVC) uses EBX to preserve the original value of the stack pointer if additional alignment is required. Therefore, you cannot overwrite it safely. The behavior of the program will become undefined. A compiler warning simply reports this.

To help with saving / restoring all registers affected by assembly blocks, an extended syntax with the so-called clobber lists is recommended. Your example uses the __asm{...} syntax in MSVC style. In the MSVC style syntax, the compiler detects which registers you touch and saves / restores them for you. ICC also supports GCC-like notation for extended asm with clobber lists: asm("...":::) . It also supports the simpler GCC asm("...") without part of the clobber list. See question for details (thanks to Peter Cordes for the link and explanation).

The documentation I found useful when I was learning to use clobber lists (I actually use it all the time because it is impossible to remember its rather unfriendly syntax):

Simple, built-in assembly units without mug lists can only be used safely in the following situations:

  • Block instructions do not change the registers defined in the ABI. Therefore, GPR, stack counter, flags should be untouched; if the function has floating point calculations, FPU / vector registers also do not work. Even writes to memory can lead to errors because the compiler relies on known values ​​to store in memory. On the contrary, you can issue the INT3 , HLT , WRMSR etc WRMSR , which either do not concern registers, or affect only system registers that the compiler does not use. However, most of these instructions are privileged and cannot be used in user applications. You can also read all available registers if there are no side effects of such readings.
  • The assembler block is the only statement in the function body. In this case, he must observe the calls on the chosen platform: how the arguments of the function are transferred, where the exit code should be placed, etc. The block will also need to cope with the compiler-generated blocks of prolog and epilogue code, which have their own assumptions about registers. Their code is not strictly stable, not portable, and not guaranteed at different optimization levels. With GCC on x86, I was not able to disable prolog / epilogue generation, so there is a risk of breaking compiler assumptions.
  • You save all the lost registers yourself and restore them later. This is relatively simple because you can see your own assembler code and can determine if it has been modified or not. However, make a mistake and the compiler will not be here for you to point this out. It is very good that ICC 2018 does give a warning, although it could just treat the asm block as a black box.
  • You "stole" the register from the compiler. GCC allows you to do this with the register asm operator (don't remember if the same trick works with other compilers). This way you can declare that the variable is bound to a specific case. Keep in mind that this technique reduces the number of registers available to the compiler for the register allocation phase, and this will degrade the quality of the generated code. Ask for too many registers and the compiler will be helpless and refuse to work. Likewise, you cannot request registers with a dedicated role that must be removed from the compiler, such as a stack pointer or program counter.

However, the extended asm syntax with clobber lists provides a nice alternative. It turns an asm section from a black box into a built-in internal β€œfunction” that declares its own inputs, outputs, and resources that it overwrites that are shared by an external function.

+1
source

Source: https://habr.com/ru/post/1275615/


All Articles