Discussion:
[9fans] more on why vc can't produce amd64 executables
(too old to reply)
erik quanstrom
2013-08-21 18:36:40 UTC
Permalink
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
Bakul Shah
2013-08-21 18:49:09 UTC
Permalink
Post by erik quanstrom
uvlong x;
x = 0x012345678abcdefull;
print("(uchar)x %.2ux\n", (uchar)x);
...
Post by erik quanstrom
x = 0012345678abcdef
(uchar)x ef
You're casting a large int into a small int and this seems right.
Just as (uchar)0x1234 => 0x34
Post by erik quanstrom
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?
erik quanstrom
2013-08-21 18:57:23 UTC
Permalink
Post by Bakul Shah
You're casting a large int into a small int and this seems right.
Just as (uchar)0x1234 => 0x34
Post by erik quanstrom
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
2013-08-21 19:25:52 UTC
Permalink
Post by erik quanstrom
Post by Bakul Shah
You're casting a large int into a small int and this seems right.
Just as (uchar)0x1234 => 0x34
Post by erik quanstrom
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!
Post by erik quanstrom
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
2013-08-21 19:29:27 UTC
Permalink
Post by Bakul Shah
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
Post by Bakul Shah
310 _ifmt(Fmt *f)
311 {
312 char buf[88], *p, *conv;
313 uvlong vu;
314 ulong u;
315 uintptr pu;

- erik
erik quanstrom
2013-08-21 21:44:03 UTC
Permalink
#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
2013-08-22 15:32:43 UTC
Permalink
Post by erik quanstrom
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
2013-08-22 16:54:11 UTC
Permalink
Post by Bakul Shah
Post by erik quanstrom
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

Loading...