gcc cross assembler problem - gcc

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.

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.

gnu arm assembler command line macro fails with "Invalid identifier for .ifdef"

My toolchain is a recent version of arm-gcc.
I have a piece of code in an assembly file which must be conditionally included/assembled.
.ifdef MACRO_FROM_CMDLINE
Assembly instr1
Assembly instr2
.endif
Encapsulated code is a recent addition.
I have tried both:
gcc -x assembler-with-cpp --defsym MACRO_FROM_CMDLINE=1 <along with other necessary options>
gcc -x assembler-with-cpp -D MACRO_FROM_CMDLINE=1 <along with other necessary options>
The -D results in "Invalid identifier for .ifdef " and ".endif without .if" errors.
The --defsym results in "MACRO_FROM_CMDLINE=1 : No such file or directory", "unrecognized option --defsym" errors.
The gcc binary drives the compilation process by invoking a number of other programs in sequence to actually perform the various stages of work (compiling, assembling, linking).
When you say:
gcc -x assembler-with-cpp -D MACRO_FROM_CMDLINE=1 ...
you are asking it to run the source through the C preprocessor, and then run the result through the assembler.
The C preprocessor step will turn:
.ifdef MACRO_FROM_CMDLINE
into:
.ifdef 1
before passing it to the assembler, which then can't make sense of it. This is why you get the "invalid identifier" error. It also explains why using C preprocessor #ifdef fixes the problem.
--defsym doesn't work because it's an option to the assembler, not the gcc driver program. (The gcc driver does understand and pass through some options to some of the programs it invokes, but not all.)
You can, however, pass arbitrary options through to the assembler using the
-Wa,option[,option...]
syntax, which tells the gcc driver to pass those option(s) through to the assembler (as a list of space-separated options).
For example:
gcc -x assembler-with-cpp -Wa,--defsym,MACRO_FROM_CMDLINE=1 ...
adds
--defsym MACRO_FROM_CMDLINE=1
to the list of options passed to as when gcc invokes it, and that's how to make your original .ifdef example work.
You can see the individual programs invoked by gcc, and the options it actually passes to them, by adding the -v option.
In this case, you should see something called cc1 (the actual GCC C compiler binary) invoked with the -E flag (preprocess only) to preprocess the input to a temporary file, and then as invoked on the temporary file to assemble it.
Strange, but it it turns out I needed to use the C syntax in the assembly file.
#ifdef MACRO
Assembly Instruction
Assembly Instruction
#endif
And the macro had to be passed using the -D option.

"Illegal instruction" on basic assembly program - not even hello world - why is linking needed?

I just figured this out but instead of splitting my new question ("why?") into another question I think its best if the solution to this problem and an explanation were to be kept on the same page.
I'm writing a basic assembly program to just start and immediately quit using the kernel interrupt at int 0x80. My current code is simply as follows:
/* Simple exit via kern-interrupt */
.globl start
start:
pushl $0x0
movl $0x1, %eax
subl $4, %esp
int $0x80
assembled with
as -arch i386 <file>.s
upon executing I get a one-line error:
Illegal instruction
It's bizzare, even commenting everything out still results in Illegal instruction despite there being no instructions at all. Am I missing a linking step, despite there being no other files to link to? Yes I am
EDIT: Allow me to rephrase my question, why do you need to link when there is no library or anything to link to?
You do need to link it to create an executable. By default, as just gives you an object file, which is something you can link into an executable (either with other object files or on its own) but is not itself a valid executable. Try:
as -arch i386 -o file.o file.s
ld -o file file.o
In answer to your question:
Why do you need to link when there is no library or anything to link to?
Because the assembler doesn't know that you're not going to link with something else.
Unlike the gcc compiler where it assumes you want a program unless told otherwise (with the -c option), as gives you an object file by default. From the manpage:
"as" is primarily intended to assemble the output of the GNU C compiler "gcc" for use by the linker "ld"
If you want a one-step command, you can create a script such as asld:
as -arch i386 -o $1.o $1.s
ld -o $1 $1.o
and then just use asld file.
Or, you could set up makefiles to do all the heavy lifting for you.
You could make the same argument about a C program, I am not using any libraries why do I have to link.
Because that is how the toolchain was designed. One set of tools takes you from source code (any/many languages) to object files which are most of the time incomplete. The link stage, even if as paxdiablo shows, only takes your object file and makes it an executable, is required. If nothing else your .text address is (usually) needed and that comes from the linker stage.
It makes a lot of sense to do it this way, the link stage is complicated enough as it is, make that one tool that does that job and is good at that job. Do your system engineering and define an interface to that tool. The language tools have a complicated job to do have them just do that job, the output being an object file, which is as far as they can resolve without having to become a linker.
If you wish to not use this toolchain and perhaps use nasm or something like that where you can go directly from assembly to binary in one command line step.

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

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.

Resources