Discussion:
BSD 2.11 Unix
(too old to reply)
Jonathan Harston
2021-07-12 01:10:20 UTC
Permalink
I've been experimenting with BSD 2.11 Unix. I'm having problems
getting assembly code to execute and do anything. I stripped
down to a minimal example:

ORG 0 ; position independant code
EQUW &0107 ; magic number, also branch to Startup
EQUW _DATA%-_TEXT% ; size of text
EQUW _BSS%-_DATA% ; size of initialised data
EQUW _END%-_BSS% ; size of uninitialised data
EQUW &0000 ; size of symbol data
EQUW _ENTRY%-_TEXT% ; entry point
EQUW &0000 ; not used
EQUW &0001 ; no relocation info
ORG 0 ; position independant code
._TEXT%
;

._ENTRY%
mov #1,r0 ; r0=STDOUT
trap 4 ; write()
equw msg_hello ; Start of data
equw end_hello-msg_hello ; Length of data
;
trap 1 ; exit()
halt ; drop to monitor
;

._DATA%
.msg_hello
equs "Hello world!",10,13
.end_hello
align
;

._BSS%
._END%

Running it just returns to the command prompt with no output.
Examining the binary with adb shows the expected code and
data, and single-stepping through it successfully sets R0, then
at the sys write() it makes the call, outputs nothing, and ends
at the exit().

If I can't even get any output so I can display debug messages,
I'm stumped!

Aside, I've written the same code in C and compiled it, and it
works fine, so my next direction of attack is to disassemble
the generated code and see what it's doing that my assembly
code isn't.

jgh
Paul Rubin
2021-07-12 01:27:23 UTC
Permalink
Post by Jonathan Harston
._ENTRY%
mov #1,r0 ; r0=STDOUT
trap 4 ; write()
Are you sure you are supposed to put the fd in r0? That doesn't look
right to me, but it's been a while.
Jonathan Harston
2021-07-12 11:22:06 UTC
Permalink
Post by Jonathan Harston
._ENTRY%
mov #1,r0 ; r0=STDOUT
trap 4 ; write()
Are you sure you are supposed to put the fd in r0? That doesn't look
right to me, but it's been a while.
That's correct for v1, v2, v3, v4, v5, v5, v6, v7 Unix. The above program
works on v5, v6, v7 Unix (I haven't had access to v1-v4).
Ian Hammond
2021-07-12 04:22:53 UTC
Permalink
Post by Jonathan Harston
I've been experimenting with BSD 2.11 Unix. I'm having problems
getting assembly code to execute and do anything. I stripped
ORG 0 ; position independant code
EQUW &0107 ; magic number, also branch to Startup
I'm not familiar with BSD, but in the earlier versions the magic number was 407
(which in fact is the PDP-11 branch instruction to skip past the header).
Jonathan Harston
2021-07-12 11:24:15 UTC
Permalink
Post by Ian Hammond
Post by Jonathan Harston
I've been experimenting with BSD 2.11 Unix. I'm having problems
getting assembly code to execute and do anything. I stripped
ORG 0 ; position independant code
EQUW &0107 ; magic number, also branch to Startup
I'm not familiar with BSD, but in the earlier versions the magic number was 407
(which in fact is the PDP-11 branch instruction to skip past the header).
Hex 107 is Oct 407. A binary dump of working code shows the same header and
magic numbers.
Ian Hammond
2021-07-12 15:25:04 UTC
Permalink
Post by Jonathan Harston
Post by Ian Hammond
Post by Jonathan Harston
I've been experimenting with BSD 2.11 Unix. I'm having problems
getting assembly code to execute and do anything. I stripped
ORG 0 ; position independant code
EQUW &0107 ; magic number, also branch to Startup
I'm not familiar with BSD, but in the earlier versions the magic number was 407
(which in fact is the PDP-11 branch instruction to skip past the header).
Hex 107 is Oct 407. A binary dump of working code shows the same header and
magic numbers.
My eyes are octal, I cannot see
I have not brought my hex with me
Bob Eager
2021-07-12 10:38:28 UTC
Permalink
Aside, I've written the same code in C and compiled it, and it works
fine,
so my next direction of attack is to disassemble the generated code and
see what it's doing that my assembly code isn't.
Why would you want to disassemble it, when you can just tell the compiler
to retain the .s file?
--
Using UNIX since v6 (1975)...

Use the BIG mirror service in the UK:
http://www.mirrorservice.org
Jonathan Harston
2021-07-12 11:22:51 UTC
Permalink
Post by Bob Eager
Aside, I've written the same code in C and compiled it, and it works
fine,
so my next direction of attack is to disassemble the generated code and
see what it's doing that my assembly code isn't.
Why would you want to disassemble it, when you can just tell the compiler
to retain the .s file?
Brain fart, that's what I meant. ;)
Scott Lurndal
2021-07-12 15:33:26 UTC
Permalink
Post by Jonathan Harston
I've been experimenting with BSD 2.11 Unix. I'm having problems
getting assembly code to execute and do anything. I stripped
ORG 0 ; position independant code
EQUW &0107 ; magic number, also branch to Startup
EQUW _DATA%-_TEXT% ; size of text
EQUW _BSS%-_DATA% ; size of initialised data
EQUW _END%-_BSS% ; size of uninitialised data
EQUW &0000 ; size of symbol data
EQUW _ENTRY%-_TEXT% ; entry point
EQUW &0000 ; not used
EQUW &0001 ; no relocation info
ORG 0 ; position independant code
._TEXT%
;
._ENTRY%
mov #1,r0 ; r0=STDOUT
trap 4 ; write()
equw msg_hello ; Start of data
equw end_hello-msg_hello ; Length of data
;
trap 1 ; exit()
halt ; drop to monitor
;
._DATA%
.msg_hello
equs "Hello world!",10,13
.end_hello
align
;
._BSS%
._END%
Running it just returns to the command prompt with no output.
Examining the binary with adb shows the expected code and
data, and single-stepping through it successfully sets R0, then
at the sys write() it makes the call, outputs nothing, and ends
at the exit().
If I can't even get any output so I can display debug messages,
I'm stumped!
Aside, I've written the same code in C and compiled it, and it
works fine, so my next direction of attack is to disassemble
the generated code and see what it's doing that my assembly
code isn't.
Standard code relies on exit() to flush the stream, which (stdout)
will be fully buffered.

Does your 'halt' call call exit()?
Scott Lurndal
2021-07-12 15:34:54 UTC
Permalink
Post by Scott Lurndal
Post by Jonathan Harston
I've been experimenting with BSD 2.11 Unix. I'm having problems
Aside, I've written the same code in C and compiled it, and it
works fine, so my next direction of attack is to disassemble
the generated code and see what it's doing that my assembly
code isn't.
Standard code relies on exit() to flush the stream, which (stdout)
will be fully buffered.
Never mind, I see you're using write directly.
Jonathan Harston
2021-07-12 15:52:00 UTC
Permalink
This is what I'm getting:

2.11 BSD UNIX (vixen.2bsd.com) (console)
login: root
erase, kill ^U, intr ^C
# cd usr/jgh
# ./fdump hello
0000 07 01 0E 00 0E 00 00 00 00 00 00 00 00 00 01 00 ................
0010 C0 15 01 00 04 89 0E 00 0E 00 01 89 00 00 48 65 @.............He
0020 6C 6C 6F 20 77 6F 72 6C 64 21 0A 0D ** ** ** ** llo world!..
# ./hello
#



(Unix v7)
Restricted rights: Use, duplication, or disclosure
is subject to restrictions stated in your contract with
Western Electric Company, Inc.
Thu Sep 22 07:13:20 EDT 1988

login: root
Password:
You have mail.
# cd usr/jgh
# ./fdump hello
0000 07 01 0E 00 0E 00 00 00 00 00 00 00 00 00 01 00 ................
0010 C0 15 01 00 04 89 0E 00 0E 00 01 89 00 00 48 65 @.............He
0020 6C 6C 6F 20 77 6F 72 6C 64 21 0A 0D ** ** ** ** llo world!..
# ./hello
Hello world!
#


The content being identical (header removed):
mov #1,r0
trap 4 ; write("Hello world!\n")
equw msg_hello
equw end_hello-msg_hello
trap 1 ; exit()
halt
.msg_hello
equs "Hello world!",10,13
.end_hello
Jonathan Harston
2021-07-12 22:00:03 UTC
Permalink
I've worked out what it is.

In Bell Labs PDP11 Unix, sys calls are:
TRAP n
DW parameter
DW parameter
etc.
code continues

In BSD PDP11 Unix, sys calls are:
mov parameter,-(sp)
mov parameter,-(sp)
etc
TRAP n
code continues.

In the Hello world example:
MOV #1,r0
TRAP 4
DW msgHello
DW lenHello
code continues

vs
MOV lenHello,-(sp)
MOV msgHello,-(sp)
MOV #1,-(sp)
TRAP 4
code continues

ubggre. That means the same binary won't run. My first thought is
to use TRAP 0 ; indirect but I bet that also uses the stack.

Anyway, knowing the issue, I know how to build a target-specific
binary by rebuilding the platform-specific code.

jgh
Jonathan Harston
2021-07-12 22:53:11 UTC
Permalink
Changing my I/O code to...

.CHAROUT
mov r0,-(sp) ; Push r0
mov sp,r0 ; r0=>data on stack
mov #1,-(sp) ; length
mov r0,-(sp) ; =>data
mov #1,-(sp) ; STDOUT=1
clr -(sp) ; padding for return address
trap 4 ; write()
add #8,sp ; drop parameters
mov (sp)+,r0 ; restore r0
rts pc

(called by
mov #hello,r1
.loop
movb (r1)+,r0 ; get byte from r1, inc r1
beq end ; exit if final byte
jsr pc,CHAROUT ; send character to output
br loop ; loop back
.end
jsr pc,QUIT ; quit to caller
halt
)


#./testfile
Hello world!

YAYYYY!!!!

<rolls up sleeves....>
Ian Hammond
2021-07-13 14:28:52 UTC
Permalink
Post by Jonathan Harston
ubggre. That means the same binary won't run. My first thought is
to use TRAP 0 ; indirect but I bet that also uses the stack.
Looking at the 2.11 source code I see that BSD deprecated indirect calls
(which makes sense since its (much more sensible) stack interface is
itself "indirect").

TRAP.C:
...
if (code >= nsysent)
callp = &sysent[0]; /* indir (illegal) */
else
callp = &sysent[code];


INIT_SYSENT.C:
struct sysent sysent[] = {
1, nosys, /* 0 = indir or out-of-range */
1, rexit, /* 1 = exit */
0, fork, /* 2 = fork */
3, read, /* 3 = read */
3, write, /* 4 = write */
...

Loading...