Christopher Condit wrote:
> __asm__ __volatile__(
> " CHI %3,20\n"
> " BH LABEL1\n"
> " LA 2,1\n"
> " B LABEL2
> "LABEL1 LA 2,0\n"
> "LABEL2 BR 14\n"
> : "=a" (retValue)
> : "d" (pProc), "d" (pStack), "d" (cbStack)
> );
Well, "BH LABEL1" is a mnemonic for "BC 2,LABEL1". The second
operand of this instruction is a memory operand (displacement
+ base register + index register) whose effective address is
used as branch target address.
However, you have not specified any base or index register,
so the value of LABEL1 will be used as displacement alone.
Now, as a valid displacement can only lie in the range 0..4096,
this could only work if the address of LABEL1 were below 4096,
which it never is when building a regular Linux binary.
Therefore the assembler truncates the address by throwing
away everything but the low 12 bits, and warns you that it
did ("relocation truncated to fit"). Of course the resulting
target address is not equal to LABEL1, and hence the program
will crash.
There's two ways to fix this. First, you could continue
using "BC", but specify a proper base register, e.g.
BASR 1,0
LABEL0: CHI %3,20
BH LABEL1-LABEL0(1)
LA 2,1
B LABEL2-LABEL0(1)
LABEL1: LA 2,0
LABEL2: BR 14
The second (much easier) way is to use BRC instead of BC.
The GNU assembler recognizes mnemonics for this as well;
they start with J instead of with B, so for BRC 2,... you'd
use JH ... This is guaranteed to work as long as the
distance between branch source and target is less than 64K
E.g.
CHI %3,20
JH LABEL1
LA 2,1
J LABEL2
LABEL1: LA 2,0
LABEL2: BR 14
(On a 64-bit machine you could use JG... instead of J...;
this will even work for distances up to 4 GB.)
Also, I'd prefer using relative labels instead of named
labels in inline asms, because the latter will become
multiply defined if the inline asm happens to be expressed
multiple times in the final assembler output (which can
happen if the function containing the inline asm is
inlined into multiple other functions). This would look
like so:
CHI %3,0
JH 1f
LA 2,1
J 2f
1: LA 2,0
2: BR 14
Note that there are other things wrong with your sample.
You should never do a 'BR 14' from an inline assembly;
register 14 is reserved for use by the compiler, and it
is in particular not guaranteed that it will contain
the return address at all times. Furthermore, even if
it happens to do, you'll return from the function
containing the inline assembly without performing any
of the required cleanup at function exit (e.g. restore
registers, clean up stack frame, ...).
You should only leave the inline asm by 'falling off
the end'.
Furthermore, it appears you are trying to load a value
into register 2 in the hope that this will be used as
some sort of 'return value'. This does not work; you
must use the argument syntax (e.g. %0) to access the
input *and* output of the asm. In addition, accessing
any register 'by number' is forbidden, unless you tell
the compiler you are doing so by specifying the register
in the clobber list of the asm.
>On the other hand, it's news to me that AT&T/Unix assembler can work on an
>IBM S/390 box. I was only brought in on this project cuz I know IBM
>assembler. If Unix assembler can be used just as well, maybe I will try to
>dump this thing back on our Unix guy...
Well, you'll have to distiguish between the *instruction set*
of the architecture and the *syntax* used to express instructions
by the assembler. On Linux for zSeries, you'll of course have to
use the S/390 (or z/Architecture) instruction set, but the GNU
assembler we use uses a syntax simliar to the AT&T syntax on
various Unix platforms.
So, using assembler on Linux for zSeries is different *both*
from using assembler on some other Unix platform *and* from
using assembler on OS/390 ;-)
Bye,
Ulrich
--
Dr. Ulrich Weigand
[EMAIL PROTECTED]