Meaning of # zero_extendqisi2 - c

I was wondering what the actual meaning of # zero_extendqisi2 in gcc assembly output was and also the usage. I couldn't find what qisi stands for or anything along those lines.
For context, the line is ldrb r3, [fp, #-9] # zero_extendqisi2 and this is ARM on a Raspberry Pi Zero W, compiled with GCC. For example, when reloading an unsigned char with conversion to int, with optimization disabled, with GCC9.2 with no options. https://godbolt.org/z/7xnfqh. Older GCC all the way to the earliest on Godbolt (4.5) and presumably earlier print the same comment.

This is an RTL instruction name, included in the Standard Names list of the GCC internals manual under zero_extendmn2. Here m,n are the machine modes qi and si, which are respectively a byte and a 32-bit integer. So this is GCC's indication that it is generating an instruction which takes a byte (here loaded from memory) and zero-extends it into a 32-bit integer (here in the register r3). Which is exactly what the ARM ldrb instruction does.
I don't know what the 2 stands for, but it's apparently part of GCC's naming convention.
As Peter points out, it's a little odd that GCC would include such a comment in the assembly without -fverbose-asm. Indeed the comment is coded in as part of the template string in the machine description file, arm.md. It could have been a debugging aid that some GCC developer added and then forgot to take out.
(If you submit this for your assignment, please cite this post properly.)

Related

What happens in the assembly output when we add "cc" to clobber list

I read that if we specify "cc" in clobber list it indicates that an assembler code modifies flags register
Wrote a sample program to check the difference in between adding "cc" and not adding.
Comparing the assembly there is no change when we add "cc".
#include <stdio.h>
int main(void)
{
unsigned long sum;
asm("incq %0"
: "=r"(sum)//output operand
: "r" (sum) //input operand
);
printf("sum= %lu\n", sum);
return 0;
}
When should we use "cc", and what is the effect of it in the assembly output
For x86, absolutely nothing. For x86 and x86-64, a cc clobber is implicit in every asm() statement. This design decision makes some sense because most x86 instructions wrote FLAGS. And because it's easy to miss and could be hard to catch with testing. (Although there's no shortage of things that are easy to get wrong with GNU C inline asm. There's usually no need to use it.)
(It does make it impossible to tell the compiler when your asm statement doesn't modify flags, but the cost of that is probably low, usually just one more instruction to redo a compare or something, or to save a variable so it can be compared later.)
If you want to be pedantic, you can use a "cc" clobber in every asm statement that modifies FLAGS.
For non-x86, you must use a cc clobber in every asm statement that modifies flags / condition codes (on ISAs that have them). e.g. ARM. On ARM, setting flags is optional; instructions with an S suffix set flags. So adds r0, r1, r2 sets flags according to r0 = r1+r2, but add r0, r1, r2 leaves flags untouched.
If you left out a "cc" clobber (on non-x86), the compiler might emit asm that set flags before an asm statement and read them afterwards, as part of implementing some other non-asm statement. So it could be essentially the same as destroying a register: nonsensical behaviour that depends on the details of what the compiler was using the register or the flags for, and which varies with optimization level and/or compiler version.
This is why testing isn't sufficient to prove inline asm is safe. With one compiler version, you could easily get lucky and have the compiler generate code that happened not to keep anything in the status register / condition codes across an asm statement, but a different compiler version or different surrounding code in a function where this inlines could be vulnerable to a buggy asm statement.

DS5 Ultimate edition different behavior while accessing first float argument passed to asm call

I am using DS5 ultimate edition for assembly coding and execution on cortex-a53 32 bit.
From my C function i am calling asm function.
The usual norm is when from C function asm function is called and arguments passed, the first float argument is present in s0 register.
For eg., func_asm(float a, float * b);
First float argument 'a' goes to s0 register and argument 'b' is present in r0 register.
But, in my case i am getting the first float argument 'a' in r0 register and 'b' in r1 register.
I am using make file build with below options
--target=arm-arm-none-eabi -march=armv7-a -mcpu=cortex-a53 -mfpu=neon
Please suggest what option needs to be added to get the first float argument correctly in s0 register.
You will have to put the hard/soft float option for the ARM compiler (a Clang fork)
In GCC/Clang, they look like following:
-mfloat-abi=hard
-mfloat-abi=softfp
-mfloat-abi=soft
hard: it's what you are looking for. The compiler will generate machine codes that fully utilize the VFP
softfp: The most commonly used form. Even though the VFP is utilized, the parameter passing occurs via the integer registers
soft: No VFP utilization
Beware that the hard option you intend to use isn't that commonly used. And your binaries won't even link to other ones compiled with the softfp/soft option.
I strongly advise NOT use the hard option unless you know what you are doing.

Compiling PowerPC binary with gcc and restrict useable registers

I have a PowerPC device running a software and I'd like to modify this software by inserting some own code parts.
I can easily write my own assembler code, put it somewhere in an unused region in RAM, replace any instruction in the "official" code by b 0x80001234 where 0x80001234 is the RAM address where my own code extension is loaded.
However, when I compile a C code with powerpc-eabi-gcc, gcc assumes it compiles a complete program and not only "code parts" to be inserted into a running program.
This leads to a problem: The main program uses some of the CPUs registers to store data, and when I just copy my extension into it, it will mess with the previous contents.
For example, if the main program I want to insert code into uses register 5 and register 8 in that code block, the program will crash if my own code writes to r5 or r8. Then I need to convert the compiled binary back to assembler code, edit the appropriate registers to use registers other than r5 and r8 and then compile that ASM source again.
Waht I'm now searching for is an option to the ppc-gcc which tells it "never ever use the PPC registers r5 and r8 while creating the bytecode".
Is this possible or do I need to continue crawling through the ASM code on my own replacing all the "used" registers with other registers?
You should think of another approach to solve this problem.
There is a gcc extension to reserve a register as a global variable:
register int *foo asm ("r12");
Please note that if you use this extension, your program does no longer confirm to the ABI of the operating system you are working on. This means that you cannot call any library functions without risking program crashes, overwritten variables, or crashes.

Using ASM command in C

I have a small question about using ASM in c. I want to execute the instruction:
LDR PC,=0x123456
This gives me the error "unexpected token in operand".
asm("LDR PC,=0x123456");
This gives "invalid constraint".
asm("LDR PC," : "m" (0x123456));
What's the right way to do this?
You are using this:
asm("LDR PC,=0x123456");
This is not a standard ARM assembly instruction, but a pseudo-instruction provided as a compiler extension. This pseudo-instruction is converted to other assembly instructions when you compile it. It seems clang doesn't support this compiler extension (see this thread). You should do the conversion to assembly instructions yourself, see the ARM documentation for how the LDR pseudo-instruction is converted.
You can probably achieve the effect you want in plain C:
((void (*)(void))0x123456)();
or if you prefer more verbose:
typedef void FN(void);
((FN*)0x123456)();
I agree with #Étienne. I tried you code with mi Google toolchain. It's working fine.
I think you should read the manual how the compiler changes the directive to instructions (normally two mov instructions).

How to use C defines in ARM assembler

How can I use external defines such as LONG_MIN and LONG_MAX in ARM assembler code?
Let's say my_arm.h looks like this:
int my_arm(int foo);
Let's say I have a my_main.c as follows:
...
#include <limits.h>
#include "my_arm.h"
...
int main (int argc, char *argv[])
{
int foo=0;
...
printf("My arm assembler function returns (%d)\n", my_arm(foo));
...
}
And my_arm.s looks like this:
.text
.align 2
.global my_arm
.type my_arm, %function
my_arm:
...
ADDS r1, r1, r2
BVS overflow
...
overflow:
LDR r0, LONG_MAX # this is probably wrong, how to do it correctly?
BX lr # return with max value
The second to last line, I am not sure how to load correctly, I vaguely remember reading somewhere, that I had to define LONG_MAX in .global, but can't find the link to a working example anymore.
I am compiling with arm-linux-gnueabi-gcc version 4.3.2
==================
UPDATE: Appreciate the suggestions! Unfortunately, I am still having trouble with syntax.
First, I made a little header file mylimits.h (for now in same dir as .S)
#define MY_LONG_MIN 0x80000000
in my_arm.S i added the following:
...
.include "mylimits.h"
...
ldr r7, =MY_LONG_MIN # when it was working it was ldr r7, =0x80000000
...
Two problems with this approach.
First the biggest problem: the symbol MY_LONG_MIN is not recognized...so something is still not right
Second: syntax for .include does not let me include <limits.h>, I would have to add that in mylimits.h, seems a bit kludgy, but I suppose, that is ok :)
Any pointers?
I have access to ARM System Developer’s Guide Designing and Optimizing System Software[2004] and ARM Architecture
Reference Manual[2000], my target is XScale-IXP42x Family rev 2 (v5l) though.
Often the lowercase file extension .s implies that assembler should not be passed through the c preprocessor, whereas the uppercase extension .S implies that it should.
It's up to your compiler to follow this convention though (gcc ports normally do), so check its documentation.
(EDIT: note that this means you can use #include directives - but remember that most of the files you would include would not normally be valid assembler (unless they consist entirely of #defineitions), so you may have to write your own header that is)
edit 5 years later:
Note that the armcc v5 compiler follows this behaviour under linux... but not on windows.
If you are using gcc and its assembler, it is straightforward: name the file with final .S, then add at the beginning #include <limits.h> and use wherever you need the constant, e.g. ldr r0, SOMETHING; I did tests with x86 since it is what I have, but the same works since it is a gcc feature.
What I ended up doing is this:
in my_main.c
#include <limits.h>
...
int my_LONG_MAX=LONG_MAX;
then in my_arm.S
ldr r8, =my_LONG_MAX
ldr r10, [r8]
It looks convuluted and it is(plus the portability gains are questionable in this approach).
There must be a way to access LONG_MAX directly in assembly. Such a way I would gladly accept as the full answer.
I have seen simply feeding gcc the assembler source vs gas will allow you to do C like things in assembler. It is actually a bit scary when you come across situations where you must use gcc as a front end to gas to get something to work, but that is another story.
use --cpreproc for armasm option and add
#include "my_arm.h"
into my_arm.s.
it works for Keil ARM

Resources