I have a few suggestions and corrections.

1. You have to actually allocate space for your local variables.
   This means either calculating how much space you'll need and
   annotating the TEXT pseudo-instruction or decrementing the SP
   as you go.

2. Calls into the kernel must look like normal calls. When writing
   in C, libc takes care of this for you. In assembly you have to
   do it yourself. There are two ways to do this: define a procedure
   and call it or push a fake return address onto the stack. I see
   you've chosen the latter but the former would make the code read
   nicer.

3. There's no need to but the buffer in the data section. It can
   be a local variable. See point 2.

4. The pread(2) system call takes a 64-bit offset like pwrite(2).

5. There's no need to define a procedure called main. The linker
   doesn't care as long as your code starts at _main.

6. Since you're using the address of the buffer quite frequently,
   your program will read better if you store it in a register.

7. It helps to pass informative error strings to exits(2).

I've attached a program that accomplishes the same task.

Cheers,
  Anthony
#define STDIN  0
#define STDOUT 1
#define EOF    0

#define BUFSIZE    4096
#define BUFOFFSET  20

#define SYS_EXITS  8
#define SYS_PREAD  50
#define SYS_PWRITE 51

TEXT _main(SB),$(BUFSIZE+BUFOFFSET)
        LEAL    BUFOFFSET(SP), SI

read:
        // read into the buffer from stdin.
        MOVL    $STDIN, 0(SP)
        MOVL    SI, 4(SP)
        MOVL    $BUFSIZE, 8(SP)
        MOVL    $-1, 12(SP)
        MOVL    $-1, 16(SP)
        CALL    pread(SB)
        CMPL    AX, $EOF
        JLE     exit

        // call conv to transform lowercase ASCII to uppercase.
        MOVL    SI, 0(SP)
        MOVL    AX, 4(SP)
        CALL    conv(SB)

        // write the potentially modified buffer to stdout.
        MOVL    $STDOUT, 0(SP)
        MOVL    SI, 4(SP)
        MOVL    AX, 8(SP)
        MOVL    $-1, 12(SP)
        MOVL    $-1, 16(SP)
        CALL    pwrite(SB)
        CMPL    AX, 8(SP)
        JEQ     read
        MOVL    $writefail<>(SB), 0(SP)
        CALL    exits(SB)

exit:
        JEQ     3(PC)
        MOVL    $readfail<>(SB), 0(SP)
        CALL    exits(SB)
        MOVL    $0, 0(SP)
        CALL    exits(SB)
        RET

// void conv(char *buf, int n)
TEXT conv(SB), $0
        MOVL    buf+0(FP), SI
        MOVL    n+4(FP), AX
        MOVL    $0, CX
        CMPL    CX, AX
        JGE     done
loop:
        MOVB    (SI)(CX*1), BL
        CMPB    BL, $'a'
        JLT     5(PC)
        CMPB    BL, $'z'
        JGT     3(PC)
        SUBB    $0x20, BL
        MOVB    BL, (SI)(CX*1)
        INCL    CX
        CMPL    CX, AX
        JLT     loop
done:
        RET

// void exits(char *status)
TEXT exits(SB),$0
        MOVL    $SYS_EXITS, AX
        INT     $64
        RET

// int pread(int fd, char *buf, int n, vlong off)
TEXT pread(SB),$0
        MOVL    $SYS_PREAD, AX
        INT     $64
        RET

// int pwrite(int fd, char *buf, int n, vlong off)
TEXT pwrite(SB),$0
        MOVL    $SYS_PWRITE, AX
        INT     $64
        RET

GLOBL   readfail<>(SB),$13
DATA    readfail<>+0(SB)/8, $"read fai"
DATA    readfail<>+8(SB)/5, $"lure\z"

GLOBL   writefail<>(SB),$14
DATA    writefail<>+0(SB)/8, $"write fa"
DATA    writefail<>+8(SB)/6, $"ilure\z"

Reply via email to