Download Latest Version or1k64kpu-binutils-20160912.tgz (27.6 MB)
Email in envelope

Get an email when there's a new version of or1k64KPU binutils

Home
Name Modified Size InfoDownloads / Week
or1k64kpu-binutils-20160912.tgz 2016-09-13 27.6 MB
README 2016-09-13 9.5 kB
or1k64kpu-binutils-20160527.tgz 2016-06-27 25.6 MB
or1k64kpu-binutils-20150415.tgz 2015-04-13 86.9 MB
Totals: 4 Items   140.1 MB 0
Peter Breuer 2016

This is the assembler support for the gcc port to the KPU
encrypted processor based on OpenRISC 1.1 .

I've tried to pare the package down to the minimum necessary to compile
just "as", but "objdump" is also useful and that and the rest of the
stuff in the binutils subdirectory compiles too .

Probably the etc and intl subdirectories are unnecessary but when I
untarred my trial package and compiled straight off with "make" it
wanted etc/configure and intl/configure, so rather than expend mental
energy figuring out what was going on I have included those directories
whole.  It doesn't need those to compile when I make in my source
directory, honest!

Anything else you find you need can be taken from the source I ported
from

 http://opencores.org/or1k/OpenRISC_GNU_tool_chain

It is of course GPL/LGPL:

  Much of the code and documentation enclosed is copyright by
  the Free Software Foundation, Inc.  See the file COPYING or
  COPYING.LIB in the various directories, for a description of the
  GNU General Public License terms under which you can copy the files.

I have included those files at top level here.

With luck, just "make" will run the compilation OK. IF you find you
need to regenerate the makefiles, note that I have configured with

 ./configure --target=or1k-elf --prefix=/opt/or1k64kpu-toolchain \
 --program-prefix=or1k64kpu-elf- --enable-shared --disable-itcl  \
 --disable-tk --disable-tcl --disable-winsup --disable-libgui    \
 --disable-rda --disable-sid --enable-sim --disable-or1ksim      \
 --enable-gdb --with-sysroot --disable-newlib --enable-libgloss  \
 --disable-libquadmath --disable-libquadmath-support 

and I would have disabled everything else under the sun if I could 
have, on the way to compiling "as". USE THOSE PARAMETERS. 

Another difficulty I found when untarring and compiling the intended
package was that make in binutils sometimes fails with complaints about
unsupported "hard parameters" to link in libtool.  I have no deep idea
what that is about, but it is solved by replacing the references to
../libbfd/libbfd.la and ../opcodes/libopcodes.la in the binutils
makefiles to ../libbfd/.libs/libbfd.a and ../opcodes/.libs/libopcodes.a
respectively.

The ".la" files are "linker scripts", and I suppose the libtool I have
does not support one of the lines in them.  It's all shell scripting so
feel quite free to skip the libtool intermediate and run the gcc line
involved without libtool to shepherd it, referencing the real target
libraries instead, as above.  You should see the line just before the
fail notice from make (make V=1 helps there!).  Do that in case of need.
It works fine, but it's a bit tedious.  The makefile generates libtool
gcc blah, which fails, so you run gcc blah directly, with the .a instead
of .la files as arguments.  No libtool use, no libtool fail.

My modified binutils subdirectory makefiles should have caused that to
happen, but they may get blown away by configure, so just do it yourself
as required, and no panic.

What do you end up with?

Well, make install (as root) puts it all in /opt/or1k64kpu-toolchain
with the parameters above. You can link to the contents of the bin
subdirectory from /usr/local/bin and all will work fine.

The principal interest is or1k64kpu-elf-as, without which the ported gcc
(see https://sourceforge.net/p/or1k64kpu-gcc/) will not be much use.  But
or1k64kpu-elf-objdump is also very useful for disassembly purposes (-d).

Gcc produces assembler source, and the assembler here turns it into
(encrypted) machine code and ELF executables which can be run on
the KPU platform (https://sourceforge.net/projects/or1ksim64kpu/ for
the simulator).

You need to put a ".encrypt" line in the assembler source to start
getting encrypted code and data.  It is also polite to put ".noencrypt"
where your source finishes, or the assembler will end up encrypting
things like the debug section too, which is generally not what you want
at all.

In C, that means a 

    asm (".encrypt");

line at the top of the C source.

This assembler is really pretty good so long as the C source is written
without globals.  It's on the way to getting there with globals but not
there yet.  At the moment, the only reliable way for globals is to
declare foo_t common[1000]; and have foo_t a union of everything you
might like, and refer to the globals by offset in that "common" array.

That is:

     int test[2] = {500, 600};

works, but

     int test0 = 500;
     int test1 = 600;

does not. Test1 will behave like an alias of test0.

The problem is that the assembler resolves global addresses in a late
pass, and I do encryption in an earlier pass.  At the time I see the
address ("value", in the jargon) of test1 it is still set to a dummy "0"
address, just like test0.

I'l figure that out soon, but meanwhile, don't use globals unless you
know what you are doing (which puts you in the same place as 5 people on
Earth living in a bunker under MIT).  You CAN make the above work by
force by telling everybody what the address of test1 is going to be
ahead of time, with

    -Wa,--defsym,test1=0x4

(for example) to gcc, or "--defsym test1=0x4" to the assembler itself.
That will cause an early substitution for the address and by the time
encryption sees it it will be safely different from the address of
test0, which is all that is needed.

It doesn't make too much difference precisely what numbers you choose
so long as they are different, but divisible by 4 is always nice.  Just
be careful in case large numbers cause a lot of blank space to appear in
the executable file, padding up to that address.  Notionally they are
offsets into the data section.

It's really essential to use the --defsym trick if you have globals
defined in different files ("compilation units").  Then you have to have
a "extern int foo;" declaration in the C source file where the global is
used.

Really, just avoid globals.

So how are you supposed to write C without globals?

Put all your intended globals into one struct, which you declare
and define as a local variable in main(), and pass the address of that
as a parameter to all subroutines:

 main(...) {
   
   struct {
      int test0;
      int test1;
   } test = { 500, 600, };

   foo(&test, ....);

That puts the "globals" on the stack. Yes, it's a bad idea to put
a 1-gazillion sized dynamic local like that on the stack .. what's
left to run in? Either use a bigger stack or DO use a (single)
global instead, as explained above.

Oh ... by the way, the gcc compiler is broken with respect to switch
statements with more than a couple of cases, so don't use them. Use
if statements instead.

This assembler (and the C compiler) supports single floating point too.
But because the KPU is 32-bit under the encryption, one has to be
a little careful when passing floats around because they sometimes get
promoted to double in C.  That is true of printf, for example.  There
may also be other functions that do that promotion.

Pass floats in C as *(int *)&foo to printf, not foo. 

The C compiler also generates function calls to routines for float
multiplication, division, ...  even conversion to and from integer.  You
will need to write those.  It's easy enough to figure out what is
wanted and they're a couple of lines of assembler each, usually.  Of
course, I HAVE written them, and will supply them if asked ...  this is
simply not the right package to put them in, I don't think, because
everything in it is for the development platform (probably Intel) not
the target platform (KPU).

Here, for example, is the floating point multiplication routine
required by gcc, called __mulsf3 (signed float, 3 arguments), as
it would appear in a C source file:

asm (".align 4\n\t"
     ".proc   __mulsf3\n\t"
     ".global __mulsf3\n\t"
     ".type   __mulsf3, @function\n\t"
     "__mulsf3:\n\t"
     "l.jr r9\n\t"
     "lf.mul.s r11,r3,r4\n\t"
     );

That was the whole (2-line) assembler code, with a few lines above saying
this is a globally visible function symbol. You might also add a final
line sizing it for the assembler : ".size .-__mulsf3", but that's just
courtesy.

The r3 and r4 are the usual registers the gcc compiler aims to put 32-bit
arguments in for the function call. The r11 is the register it expects to
find a 32-bit return value in.

If you were less certain of that than I, you might write the routine in
C instead using a C function body:

__attribute__((leaf))
float __mulsf3(register float x, register float y)
{ 
    register float z asm("r11");
    asm ("lf.mul.s %0,%1,%2" 
        : "=r" (z) : "r" (x), "r" (y) : );
    return z;
}

but that will be nowhere near as effcient as my two-instruction version
above. It may well be about 20 instructions, considering that it
saves registers, etc.  The __attribute__((leaf)) avoids the C compiler
unnecessarily  saving stack and return address around the call.

What else do you need to know about this assembler?

It does all the encryption required.  The C compiler does none.  You can
change the encryption and the encryption key via command line arguments.
The default is

   --cipher=rc2

(64b blocksize)

but it also understands --cipher=aes128, and various paillier64/68/72
alternatives. It should be apparent where to augment the list if you
look at the source.

The (64b) key is supplied with

   --key0

If a 128b key is needed, use also --key1.


PTB Sept 2016
ptb@inv.it.uc3m.es


Source: README, updated 2016-09-13