"Error: operand out of range" when using PPC assembler - gcc

I have bulit gcc cross compiler/assembler/linker with 'powerpc-eabi' as TARGET in windows using cygwin. When assembling, I am getting the following error ....
code/sfiles/init_evh.s: Assembler messages:
code/sfiles/init_evh.s:381: Error: operand out of range (0x0000fffd is not between 0xffff8000 and 0x00007fff)
But, in that line number, the following instruction is there:
addi r2,0,0xFFFD
I am using the follwing command for assembly:
c:/cygwin/home/cdot/powerpc/bin/powerpc-eabi-as -mbig-endian -m603 -mregnames --
defsym _NDI_=1 --defsym _DBGR_ON_=1 --defsym DEBUG=1 --defsym _PARAM_DEBUG_=1 --
defsym _NIU_=1 -gdwarf-2 -I code/hfiles -o build/niu_ndi_dbgr_init_evh.o code/sf
iles/init_evh.s 2>build/niu_ndi_dbgr_init_evh.err
I would like to know why the above error appear.
Please help in this direction.

The compiler/assembler is correct in emitting an error message here. The use of a constant 0xfffd is not possible with immediate-type instructions in PPC assembly.
PowerPC immediate instructions (such as the addi you're attempting to do) have a generic instruction format 6/5/6/16 bits each for opcode/source/dest/constant; the 16bit constant is signed, hence the range is -32768 ... 32767; this is sign extended to 32bit, which means you'll get a range of 0xffff8000 ... 0x7fff. See also:
IBM Developerworks PPC Assembly Introduction, particularly "listing 3."
That's what the error message is trying to tell you.

Related

Windows x86 assembly entry point is wrong

I wrote a test program for learning purposes in x86 assembly using NASM as assembler and MinGW32 (ld) as linkerW.
I am working on Windows 10.
section .text
global my_start
my_start:
nop
nop
nop
nop
jmp my_start
I am using the following command for assembling:
nasm -f win32 -l main.lst main.asm
And the following command for linking:
ld -nostdlib -nostartfiles -s -o main.exe -e my_start main.obj
Now if I run the program I get an sgmentation fault error.
To find out why I used GDB for debugging and found out that windows is executing my executable at file begin where the DOS Header is laying.
So windows is trying to execute the magic number "MZ" (4d 5a) and following bytes as assembler instructions.
So, now I am very confused why this happens because I specified an entry point (-e my_start) followed by valid x86 assembler instructions.
Why exactly my executable start's execute at DOS header and not at my specified entry point in my code segment?
How I can fix this?
EDIT:
I tried now GoLink and using this linker everything is working fine:
GoLink.exe main.obj /entry my_start
I also compared the entry point of the optional header and both are equal.
But comparing both files a lot of things are different so I cannot tell what exactly is wrong so I will stick with GoLink for a while and maybe come back to this problem if I have a bit more experience.

error: unknown "%" symbol on SPARC

My program works fine on Ubuntu.
It encounters error when I compile it with gcc on a Solaris SPARC system.
I have several pieces of code like:
printf("endian_convert: %s\n", endian_convert);
asm("movl $8, %esi\n\t"
"movl $.LC0, %edi\n\t"
"movl $0, %eax");
This is the error I get on SPARC:
gcc -g -Wall -Werror -pedantic -Wextra src/utfconverter.c -o bin/utf
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 957: error: unknown "%"-symbol
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 957: error: statement syntax
.......
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 1058: error: unknown "%"-symbol
/usr/ccs/bin/as: "/var/tmp//cc9czJEf.s", line 1058: error: statement syntax
*** Error code 1 make: Fatal error: Command failed for target `utf'
So, the "%" symbol is considered as unknown on SPARC?
How can I fix this and make it working on SPARC?
(The original version of the question didn't mention that the errors were from a SPARC Solaris system, and just called it C90 because the old version of gcc installed on it defaulted to -std=c90, leading to error messages about things that are illegal in C90.)
Wait a minute, "works fine on Ubuntu but not on C90"? /usr/ccs/bin/as (in your screenshot) looks like Solaris. That + the hostname is a clue that this might be a SPARC machine, not x86 at all.
Obviously x86 assembly isn't valid SPARC assembly syntax. It's a different CPU architecture.
If you'd used gcc foo.c -S and looked at the resulting foo.s asm output file, you'd see that it was full of SPARC asm, except for text inserted literally by your asm statements.
SPARC syntax does use % decorators on register names, but the register names are different. e.g. add %i0, %i1, %o0 adds input registers i0 and i1, storing the result in output register o0. (Input as in function arg and output as in function result. SPARC uses a sliding window onto a large virtual register file that might or might not spill to memory, depending on whether the CPU microarchitecture is out of registers when the save instruction runs.)
Remember that these errors are from the Solaris assembler, not from gcc. You're using gcc but it's using the system assembler instead of the GNU assembler.
Anyway, I recommend rewriting your code into pure portable C, rather than using #ifdef __x86__ to keep using that inline asm, or writing a SPARC port of it.
BTW, your asm statement looks horrible. A different version of gcc might store a different constant at .LC0, breaking your code. More importantly, you're not using input/output constraints to tell the compiler what value is where. If you're assuming it's ok to set eax in asm inside a function, that's incorrect. The function can and will inline, and then your asm is just floating free in the middle of wherever your function inlined. See the end of this answer for links to some GNU C inline asm tutorials.
Also, you don't need inline asm to endian-convert. You will get better asm from using endian.h functions like uint32_t le32toh(uint32_t little_endian_32bits); which use gcc builtins or inline asm to get the compiler to make optimal assembly output itself.
See also https://gcc.gnu.org/wiki/DontUseInlineAsm, which applies even if you did know how to use it properly.

Gcc complains about vstmia - why?

I'm trying to compile a program for Raspberry Pi 2B (ARMv7 / Neon), but I get an error from an inline assembly code:
Error: VFP single precision register expected -- `vstmia.64
r9,{d16-d31}'
The code is:
asm volatile (
"vstmia.64 %[reg]!, {d0 - d15} # read all regs\n\t"
"vstmia.64 %[reg], {d16 - d31} # read all regs\n\t"
::[reg] "r" (&vregs):
);
Funny thing is that it doesn't complain about the first vstmia.
I tried with single {d0 - d32} first and I thought maybe there were too many 64-bit registers, but that's obviously not the problem.
vregs is a 8-byte aligned storage.
I'm using arm-linux-gnueabihf-gcc 4.8.3, with this command line:
arm-linux-gnueabihf-gcc -mcpu=cortex-a7 -marm -O2 -g -std=gnu11 -MMD -MP -MF"ARM_decode_table.d" -MT"ARM_decode_table.o" -c -o "ARM_decode_table.o" "../ARM_decode_table.c"
By not specifying an appropriate -mfpu option, you get whatever FPU support the compiler's default configuration provides. From your configuration in this case, that is --with-fpu=vfp, which means crusty old VFPv2 with only 16 D registers overlaying the 32 S registers. Thus the first instruction targeting d0-d15 is fine, but the assembler refuses to assemble the second instruction which it knows won't work on the chosen target.
For Cortex-A7 with NEON, -mfpu=neon-vfpv4 will let the toolchain know that it can let rip and use everything you have available.

unrecognized -a option `ck_size'

I am using GCC ver-4.6.4 (both in Mac and Linux Mint 15) to compile a code I do for research.
The command I am using is :
gfortran -O2 -fopenmp -Wl,-stack_size,1000000 <...Lots of files...> -o a.out
, where I omit the actual file names.
This code compiles OK in Mac, however I get the following error in Mint:
/usr/bin/ld: unrecognized -a option `ck_size'
collect2: error: ld returned 1 exit status
make[1]: *** [a.out] Error 1
In Mint, this will compile if I do not use any flags at all, therefore this problem is related to OpenMP.
However, I do need OpenMP and do not understand what it says in the error, because I do not have 'ck_size'. BTW, deleting -O2 doesn't help.
The problem is not related to OpenMP, it is related to your different OS's.
-stack_size is specific to Macintosh and refers to the maximal size of arrays on the stack. Linux changes the stack size via the terminal command ulimit (to check your Mint settings type, ulimit -a to see everything, the stack size can be seen with ulimit -s, see the ulimit man page for more information).
Thus, you need to scrap that whole -stack_size,100000 portion from your compiler flag, it means nothing in Linux.
You passed -Wl,-stack_size,1000000 to gfortran, which is passing on the option "-stack_size 1000000" to the linker ld. It is interpreting "st" as single letter options "-s" and "-t", then reading the next letter as an option "-a", and the rest of the word ("ck_size") as its parameter.
I could find no reference to a -stack_size option for ld. It looks like the option is --stack, so you need to put something like -Wl,--stack,1000000 instead.

gcc cross assembler problem

I have bulit gcc cross compiler with 'powerpc-eabi' as TARGET in windows using cygwin.
When assembling the follwing code lis r4, %hi(IMMR_OFFSET), I was getting the following
errors.
init/code/sfiles/init_core.s:141: Error: bad expression
init/code/sfiles/init_core.s:141: Error: syntax error; found `h', expected `,'
init/code/sfiles/init_core.s:141: Error: junk at end of line: `hi(IMMR_OFFSET)'
I would like to know why the above errors appear for every lis instruction similar to above.
Please help in this direction.
The value of IMMR_OFFSET is defined in another .h file as below....
.equ IMMR_OFFSET, 0xF0010000
I am using the follwing command for assembly....
c:/cygwin/home/cdot/powerpc/bin/powerpc-eabi-as -mbig-endian -g --defsym _NDI_=1
--defsym _DBGR_ON_=1 --defsym DEBUG=1 --defsym _PARAM_DEBUG_=1 --defsym _NIU_=1
-gdwarf-2 -I init/code/hfiles -o init/build/niu_ndi_dbgr_init_core.o init/code/
sfiles/init_core.s 2>init/build/niu_ndi_dbgr_init_core.err
I have a feeling that your assembly source is expecting to be built with a different assembler...
Some PPC assemblers do support the %hi(foo) syntax, but not the GNU assembler (unless there is some poorly documented option that I'm not aware of).
It also won't recognise r4 as a register name unless you use the -mregnames flag.
The equivalent in the GNU assembler syntax is
lis 4, IMMR_OFFSET#h
(or lis r4, IMMR_OFFSET#h will also work if you use -mregnames).
Similarly, %lo(foo) and %ha(foo) would need to be written as foo#l and foo#ha respectively.

Resources