Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

[9fans] more on why vc can't produce amd64 executables

72 views
Skip to first unread message

erik quanstrom

unread,
Aug 21, 2013, 2:36:40 PM8/21/13
to
vc vlongs are broken for cast

for example, _v2uc produces the code:

acid; asm(_v2uc)
_v2uc 0x00005360 MOVW rv+8(FP),R1
_v2uc+0x4 0x00005364 JMP (R31)
_v2uc+0x8 0x00005368 AND $0xff,R1

i think this should be
MOVW rv+12(FP),R1
JMP (R31)
AND $0xff,R1

since the high 32-bits of the vlong should be first, since
this is a BE machine. perhaps there's supposed to be a
special calling convention for vlongs?

here's an example of the issue:

void
main(void)
{
uvlong x;

x = 0x012345678abcdefull;
print("(uchar)x %.2ux\n", (uchar)x);
exits("");
}

mikro; v.x
x = 0012345678abcdef
(uchar)x ef

marshalling a 64-bit pointer in this way will lay down the
bytes with the hi and lo reversed.

- erik

erik quanstrom

unread,
Aug 21, 2013, 2:57:23 PM8/21/13
to
> You're casting a large int into a small int and this seems right.
> Just as (uchar)0x1234 => 0x34
>
> > marshalling a 64-bit pointer in this way will lay down the
> > bytes with the hi and lo reversed.
>
> Perhaps you meant to do *(uchar*)&x?

you're right. what was i thinking. still, pointers are marshaled wrong.
compiled on mips, this program

#include <u.h>
#include <libc.h>

void
main(void)
{
char *p;

p = malloc(100);
print("%p\n", p);
}
does this
; 6.crash
6.crash 203443: suicide: sys: trap: #SS pc=0x2048f2

- erik

Bakul Shah

unread,
Aug 21, 2013, 2:49:09 PM8/21/13
to
On Wed, 21 Aug 2013 14:36:40 EDT erik quanstrom <quan...@quanstro.net> wrote:
> uvlong x;
>
> x = 0x012345678abcdefull;
> print("(uchar)x %.2ux\n", (uchar)x);
...
> x = 0012345678abcdef
> (uchar)x ef

You're casting a large int into a small int and this seems right.
Just as (uchar)0x1234 => 0x34

> marshalling a 64-bit pointer in this way will lay down the
> bytes with the hi and lo reversed.

Bakul Shah

unread,
Aug 21, 2013, 3:25:52 PM8/21/13
to

On Aug 21, 2013, at 11:57 AM, erik quanstrom <quan...@quanstro.net> wrote:

>> You're casting a large int into a small int and this seems right.
>> Just as (uchar)0x1234 => 0x34
>>
>>> marshalling a 64-bit pointer in this way will lay down the
>>> bytes with the hi and lo reversed.
>>
>> Perhaps you meant to do *(uchar*)&x?

Incidentally, on a little endian machine you'd still get
0xef out of 0x0123456789abcdefull!

>
> you're right. what was i thinking. still, pointers are marshaled wrong.

> compiled on mips, this program
>
> #include <u.h>
> #include <libc.h>
>
> void
> main(void)
> {
> char *p;
>
> p = malloc(100);
> print("%p\n", p);
> }

> does this
> ; 6.crash
> 6.crash 203443: suicide: sys: trap: #SS pc=0x2048f2

How %p is treated is really upto the implementation but
it should not crash since p is never dereferenced. Does
this work?

uintptr q;
print("%p", q);

erik quanstrom

unread,
Aug 21, 2013, 3:29:27 PM8/21/13
to
> How %p is treated is really upto the implementation but
> it should not crash since p is never dereferenced. Does
> this work?
>
> uintptr q;
> print("%p", q);

no. if i change the print to print an integer, it still fails.

in fact, it's really the indirect call in print that fails.
this is the instruction

CALL *AX

acid; *AX
0x002014b300000000
acid; src(*AX>>32)
/sys/src/libc/fmt/dofmt.c:310
305 return _fmtrcpy(f, x, 1);
306 }
307
308 /* fmt an integer */
309 int
>310 _ifmt(Fmt *f)
311 {
312 char buf[88], *p, *conv;
313 uvlong vu;
314 ulong u;
315 uintptr pu;

- erik

erik quanstrom

unread,
Aug 21, 2013, 5:44:03 PM8/21/13
to
#include <u.h>
#include <libc.h>

void
f(void)
{
write(1, "hello\n", 6);
}

void (*call)(void) = f;

void
main(void)
{
call();
exits("");
}

the asm is the same when compiled on any arch,

; acid 6.crash4-mips
6.crash4-mips:amd64 plan 9 executable
/sys/lib/acid/port
/sys/lib/acid/amd64
acid; asm(main)
main 0x0020004e SUBQ $0x8,SP
main+0x4 0x00200052 MOVQ call(SB),AX
main+0xc 0x0020005a CALL* AX
main+0xe 0x0020005c MOVL $.string+0x7(SB),BP
main+0x13 0x00200061 CALL exits(SB)
main+0x18 0x00200066 ADDQ $0x8,SP
main+0x1c 0x0020006a RET
_main 0x0020006b SUBQ $0x90,SP

but the data is incorrect in the mips-compiled binary.
acid; *(call\Y)
0x0020002800000000

mikro; diff -c crash4-mipsa crash4-amd64a
crash4-mipsa:417,423 - crash4-amd64a:417,423
2005af 48c7c532000000 (4) MOVQ $50,BP
2005b6 0f05 (5) SYSCALL ,
2005b8 c3 (6) RET ,
- 400010 0000000028002000 (823) DATA call+0(SB)/8,$f+0(SB)
+ 400010 2800200000000000 (823) DATA call+0(SB)/8,$f+0(SB)
400030 68656c6c6f0a0000 (829) DATA .string<1>+0(SB)/8,$"hello\n\z\z"
400028 6d61696e (18) DATA _exits<2>+0(SB)/4,$"main\z\z\z\z"
400000 23632f7069640000 (829) DATA .string<7>+0(SB)/8,$"#c/pid\z\z"

i think a bug is setting inuxi8[i+4] = inuxi8[i] for 0<=i<4.
mikro; diffy -c *.c
diff -c /n/dump/2013/0821/sys/src/cmd/6l/obj.c obj.c
/n/dump/2013/0821/sys/src/cmd/6l/obj.c:1455,1471 - obj.c:1455,1471
int i, c;

for(i=0; i<4; i++) {
- c = find1(0x04030201L, i+1);
+ c = find1(0x0807060504030201ULL, i+1);
if(i < 2)
inuxi2[i] = c;
if(i < 1)
inuxi1[i] = c;
- inuxi4[i] = c;
+ if(i < 4){
+ inuxi4[i] = c;
+ fnuxi4[i] = c;
+ }
inuxi8[i] = c;
- inuxi8[i+4] = c+4;
- fnuxi4[i] = c;
fnuxi8[i] = c;
- fnuxi8[i+4] = c+4;
}
if(debug['v']) {
Bprint(&bso, "inuxi = ");
/n/dump/2013/0821/sys/src/cmd/6l/obj.c:1492,1504 - obj.c:1492,1504
}

int
- find1(long l, int c)
+ find1(uvlong l, int c)
{
char *p;
int i;

p = (char*)&l;
- for(i=0; i<4; i++)
+ for(i=0; i<8; i++)
if(*p++ == c)
return i;
return 0;
/n/dump/2013/0821/sys/src/cmd/6l/obj.c:1505,1517 - obj.c:1505,1517
}

int
- find2(long l, int c)
+ find2(uvlong l, int c)
{
short *p;
int i;

p = (short*)&l;
- for(i=0; i<4; i+=2) {
+ for(i=0; i<8; i+=2) {
if(((*p >> 8) & 0xff) == c)
return i;
if((*p++ & 0xff) == c)


unfortunately, compiling on mips *still* doesn't work right.
print prints %%p for %p. i don't know if my fix is wrong, or
if there is another bug.

- erik

Bakul Shah

unread,
Aug 22, 2013, 11:32:43 AM8/22/13
to
On Wed, 21 Aug 2013 17:44:03 EDT erik quanstrom <quan...@quanstro.net> wrote:
>
> i think a bug is setting inuxi8[i+4] = inuxi8[i] for 0<=i<4.
> mikro; diffy -c *.c
> diff -c /n/dump/2013/0821/sys/src/cmd/6l/obj.c obj.c
> /n/dump/2013/0821/sys/src/cmd/6l/obj.c:1455,1471 - obj.c:1455,1471
> int i, c;
>
> for(i=0; i<4; i++) {
> - c = find1(0x04030201L, i+1);
> + c = find1(0x0807060504030201ULL, i+1);

Why not
for(i=0; i<8; i++) {
Else what is the point of
c = find1(0x0807060504030201ULL, i+1);
Just eyeballing. I haven't looked at the actual code.

erik quanstrom

unread,
Aug 22, 2013, 12:54:11 PM8/22/13
to
> > i think a bug is setting inuxi8[i+4] = inuxi8[i] for 0<=i<4.
> > mikro; diffy -c *.c
> > diff -c /n/dump/2013/0821/sys/src/cmd/6l/obj.c obj.c
> > /n/dump/2013/0821/sys/src/cmd/6l/obj.c:1455,1471 - obj.c:1455,1471
> > int i, c;
> >
> > for(i=0; i<4; i++) {
> > - c = find1(0x04030201L, i+1);
> > + c = find1(0x0807060504030201ULL, i+1);
>
> Why not
> for(i=0; i<8; i++) {
> Else what is the point of
> c = find1(0x0807060504030201ULL, i+1);
> Just eyeballing. I haven't looked at the actual code.

as it turns out, floating point is already swapped by Ieee, and
anything less than or equal to 4 bytes is cast uprated to a ulong,
not a uvlong.

this version produces the same output with -a as on amd64.

i think it's a little more clear to straightforwardly set up the nuxi,
and special case the word-swapping in the floating point.
ideally, the low and high words would be merged to a vlong.

this fix likely won't survive its encounter with review intact, but
at least for now i can compile amd64 binaries on mips.
once a final form is in place a fix should be applied to all
compilers.

- erik

----
/n/atom/plan9/sys/src/cmd/6l/obj.c:1449,1472 - obj.c:1449,1482
}
}

+ static uvlong lorder = 0x0706050403020100ull;
+
void
+ letab(uchar *t, int w, int n)
+ {
+ uchar *o;
+ uint i;
+
+ o = (uchar*)&lorder;
+ o += (o[0]!=0)*(8-w); /* if big endian, use tail not head */
+ for(i = 0; i < n; i++)
+ t[i] = o[i];
+ }
+
+ void
nuxiinit(void)
{
- int i, c;
+ int i;

- for(i=0; i<4; i++) {
- c = find1(0x04030201L, i+1);
- if(i < 2)
- inuxi2[i] = c;
- if(i < 1)
- inuxi1[i] = c;
- inuxi4[i] = c;
- inuxi8[i] = c;
- inuxi8[i+4] = c+4;
- fnuxi4[i] = c;
- fnuxi8[i] = c;
- fnuxi8[i+4] = c+4;
- }
+ letab(inuxi1, 4, 1); /* cast to 4 bytes, 1 byte tab */
+ letab(inuxi2, 4, 2);
+ letab(inuxi4, 4, 4);
+ letab(inuxi8, 8, 8);
+ letab(fnuxi4, 4, 4);
+ letab(fnuxi8, 4, 4); /* undo Ieee swapping. */
+ for(i = 4; i < 8; i++)
+ fnuxi8[i] = fnuxi8[i-4]+4;
+
if(debug['v']) {
Bprint(&bso, "inuxi = ");
for(i=0; i<1; i++)
/n/atom/plan9/sys/src/cmd/6l/obj.c:1489,1523 - obj.c:1499,1504
Bprint(&bso, "\n");
}
Bflush(&bso);
- }
-
- int
- find1(long l, int c)
- {
- char *p;
- int i;
-
- p = (char*)&l;
- for(i=0; i<4; i++)
- if(*p++ == c)
- return i;
- return 0;
- }
-
- int
- find2(long l, int c)
- {
- short *p;
- int i;
-
- p = (short*)&l;
- for(i=0; i<4; i+=2) {
- if(((*p >> 8) & 0xff) == c)
- return i;
- if((*p++ & 0xff) == c)
- return i+1;
- }
- return 0;
}

long

0 new messages