NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: mjrice on June 01, 2021, 07:15:21 PM
-
Hi,
How would I rotate the other dword of qword the same 8 bits?
mov eax, [eax]?
-mjrice
------------------------------------------
global lanorm_
section .text ;rotation of 64-bit word
lanorm_:
push ebp
mov ebp, esp
mov eax, [ebp+8] ;eax <- addr of qword
pop ebp
mov eax, [eax+4] ;eax <- contents of hi dword of qword
rol eax, 8
mov edx, 0
ret
100 FORMAT(A8)
READ(*,100) LW
WRITE(*,100) LW
MW=LANORM(LW)
WRITE(*,100) MW
END
mrice@debian10-uni:~/work$ nasm -f elf lanorm.asm -o lanorm.o
mrice@debian10-uni:~/work$ gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
mrice@debian10-uni:~/work$ gfortran test.o lanorm.o -o test
mrice@debian10-uni:~/work$ ./test
ABCDEFGH
ABCDEFGH
HEFG
mrice@debian10-uni:~/work$
-
Figured it out for myself. Trying to get nasm reoriented after a two year absence.
Working with 64-bit integers and reals in 32 bit nasm. The following asm code should (I hope) count the blanks in one of the dwords of a double dword argument ("ABCD##GH" -> 2). But there seems to be some problem with my data statement (see below).
--mjrice
-----------------------------------------------
global lcount_
section .text ;return blank count in hi-end dw
section .data
blank db 32
k1 dw 0 ;byte index
k2 dw 0 ;blank count
lcount_:
push ebp
mov ebp, esp
mov eax, [ebp+8] ;eax <- addr of qword
nextbyte:
cmp k1, 4
jz finished
cmp [eax+k1], blank
jz add1
inc k1 ;increment byte index
jmp nextbyte
add1:
inc k2 ;increment byte-count
inc k1 ;increment byte index
jmp nextbyte
finished:
pop ebp
mov eax, k2
mov edx, 0
ret
-----------------------------------------------------------------
mrice@debian10-uni:~/work$ nasm -f elf lcount.asm -o lcount.o
lcount.asm:7: error: label or instruction expected at start of line
lcount.asm:8: error: label or instruction expected at start of line
mrice@debian10-uni:~/work$
-
Rotate QWORD 8 bits to the left in i386 mode:
bits 32
struc rot8left64_stk
resd 1 ; return address.
.lo: resd 1
.hi: resd 1
endstruc
section .text
global rot8left64
rot8left64:
mov eax, [esp+rot8left64_stk.lo]
mov edx, [esp+rot8left64_stk.hi]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-
These two lines are what the compiler is complaining about.
k1 dw 0 ;byte index
k2 dw 0 ;blank count
I don't understand what that has to do with a qword as I'm not using any in my code.
-mjrice
-
To fredericopissarra:
Thanks!
I misunderstood your last message, that you weren't addressing my compiler problem but offering a way to rotate a qword in 32-bit environment, a replacement for my first lanorm effort?
My usual input to lanorm is a 64-bit 8-char word, composed of some number of blanks on the left, possibly 0, the rest being non-blank character(s). It's task to rotate the non-blank characters all the way to the left, followed by all the blank characters (left-justification). So the number of blanks determine the number of 8-bit rotates. Thus my most recent post of the function lcount, which counts blanks in a dword.
--mjrice
-
mrice@debian10-uni:~$ cd work
mrice@debian10-uni:~/work$ nasm -f elf rot8left64.asm -o rot8left64.o
rot8left64.asm:11: error: symbol `rot8left64_stk.lo' undefined
rot8left64.asm:12: error: symbol `rot8left64_stk.hi' undefined
mrice@debian10-uni:~/work$
The code:
----------------------------------------------
struc rot8left64_stk
resd 1 ; return address.
lo: resd 1
hi: resd 1
endstruc
section .text
global rot8left64
rot8left64:
mov eax, [esp+rot8left64_stk.lo]
mov edx, [esp+rot8left64_stk.hi]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-mjrice
-
sorry. The structure is defined as:
struc rot8left64_stk
resd 1
.lo: resd 1
.hi: resd 1
endstruc
-
I added inhalt.asm to my fortran to deal with its fussiness about un-declared integer and real variables and functions, your rot8left64,asm function being "real" to fortran and the receiver variable (MW) in my main program being an "integer." Discrimination!? But there's still a linking problem (see bottom output).
-mjrice
-----------------TEST.F95----------------------
100 FORMAT(A8)
READ(*,100) LW
WRITE(*,100) LW
MW=INHALT(ROT8LEFT64(LW))
WRITE(*,100) MW
END
------------------------------------------------
global inhalt_
section .text ;return contents given the addr of a 64-bit integer
inhalt_:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov eax, [eax]
pop ebp
; fld qword [eax]
mov edx, [eax+4]
mov eax, [eax]
ret
-----------------------------------
struc rot8left64_stk
resd 1 ; return address.
.lo: resd 1
.hi: resd 1
endstruc
section .text
global rot8left64
rot8left64:
mov eax, [esp+rot8left64_stk.lo]
mov edx, [esp+rot8left64_stk.hi]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-------------------------------------------
mrice@debian10-uni:~$ cd work
mrice@debian10-uni:~/work$ nasm -f elf inhalt.asm -o inhalt.o
mrice@debian10-uni:~/work$ nasm -f elf rot8left64.asm -o rot8left64.o
mrice@debian10-uni:~/work$ gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
mrice@debian10-uni:~/work$ gfortran test.o inhalt.o rot8left64.o -o test
/usr/bin/ld: test.o: in function `MAIN__':
test.f95:(.text+0x115): undefined reference to `rot8left64_'
collect2: error: ld returned 1 exit status
mrice@debian10-uni:~/work$
-
/usr/bin/ld: test.o: in function `MAIN__':
test.f95:(.text+0x115): undefined reference to `rot8left64_'
What this says to you?
-
MAIN_ is my fortran program, but I see no misspelling of ROT8LEFT64. What does it mean to you?
-mjrice
-
An afterthought: ROT8LEFT64 might be a procedure, not a function?
-mjrice
-
An afterthought: ROT8LEFT64 might be a procedure, not a function?
-mjrice
Change:
global rot8left64
rot8left64:
To:
global rot8left64_
rot8left64_:
-
Hurray, this time it found the function, but got a segmentation error.
As requested:
struc rot8left64_stk
resd 1 ; return address.
.lo: resd 1
.hi: resd 1
endstruc
section .text
global rot8left64_
rot8left64_:
mov eax, [esp+rot8left64_stk.lo]
mov edx, [esp+rot8left64_stk.hi]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
----------------------------------
mrice@debian10-uni:~$ cd work
mrice@debian10-uni:~/work$ nasm -f rot8left64.asm -o rot8left64.o
nasm:fatal: unrecognised output format `rot8left64.asm' - use -hf for a list
type `nasm -h' for help
mrice@debian10-uni:~/work$ nasm -f elf rot8left64.asm -o rot8left64.o
mrice@debian10-uni:~/work$ nasm -f elf inhalt.asm -o inhalt.o
mrice@debian10-uni:~/work$ gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
mrice@debian10-uni:~/work$ gfortran test.o rot8left64.o inhalt.o -o test
mrice@debian10-uni:~/work$ ./test
ABCDEFG
ABCDEFG
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0xb7cd974b
#1 0xb7cd884e
#2 0xb7f29d6b
#3 0x474449
Segmentation fault
mrice@debian10-uni:~/work$
-
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0xb7cd974b
#1 0xb7cd884e
#2 0xb7f29d6b
#3 0x474449
Segmentation fault
mrice@debian10-uni:~/work$
I'm not familiar about fortran ABI. Strings, as I understood, are blocks of chars, not NUL terminated, with a hidden length argument attached. I can't find a reliable reference for mixing fortran/asm...
So, what, exactly this inhalt_ function is supposed to do? Why use a stack frame?
-
Not sure what you mean by, "why use a stack frame?" But, from Joseph Weizenbaum's "Symetric List Processor" document:
4. CONT(A) are functions which have as their values the
and information stored in the word the machine
5. INHALT(A) address of which appears as an integer in A.
Here's CONT:
(Note: NOT from the Weizenbaum document, which only supplies the fortran.)
global cont_
section .text ;return the (64-bit real) contents of a (32-bit address)
cont_:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov eax, [eax]
pop ebp
fld qword [eax]
; mov edx, [eax+4]
; mov eax, [eax]
ret
As you can see, the code is identical to INHALT except for how the result is returned.
Fortran assumes an undeclared variable or function name to be integer if it begins with any letter of "ijklmn", otherwise assumes it as real. Contradicions arise with:
I=C
I=D(_)
C=I
C=I(_)
-mjrice
-
Not sure what you mean by, "why use a stack frame?" But, from Joseph Weizenbaum's "Symetric List Processor" document:
4. CONT(A) are functions which have as their values the
and information stored in the word the machine
5. INHALT(A) address of which appears as an integer in A.
Here's CONT:
(Note: NOT from the Weizenbaum document, which only supplies the fortran.)
global cont_
section .text ;return the (64-bit real) contents of a (32-bit address)
cont_:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov eax, [eax]
pop ebp
fld qword [eax]
; mov edx, [eax+4]
; mov eax, [eax]
ret
As you can see, the code is identical to INHALT except for how the result is returned.
Fortran assumes an undeclared variable or function name to be integer if it begins with any letter of "ijklmn", otherwise assumes it as real. Contradicions arise with:
I=C
I=D(_)
C=I
C=I(_)
-mjrice
I mean... The prologue (push ebp/mov ebp,esp) and epilogue (pop ebp) aren't necessary. The same function can be implemented as:
struc cont_stk
resd 1 ; return address
.ptr: resd 1
endstruc
global cont_
cont_:
mov eax,[esp+cont_stk.ptr] ; Get the pointer from stack
mov eax,[eax] ; Get pointer pointed by EAX
fld qword [eax] ; Get double pointed by the second pointer.
ret
Assuming this is correct... Why 2 indirections?
-
If A is double (REAL*8?), then I assume the stack would be, after que call:
; ESP+4 -> A (8 bytes)
; ESP -> ret addres
struc cont_stk
resd 1
.A: resq 1
endstruc
global count_:
count_:
fld qword [esp+count_stk.A]
ret
Or... If A is a pointer:
; ESP+4 -> ptr A (4 bytes)
; ESP -> ret addres
struc cont_stk
resd 1
.Aptr: resd 1
endstruc
global count_:
count_:
mov eax,[esp+count_stk.Aptr]
fld qword [eax]
ret
-
All fortran function and subroutine args are pointers. One can change their values inside a function.
procedure swap(a, b)
temp : Integer;
begin
temp := a;
a := b;
b := temp;
end swap;
The struc is interesting. I understand it's done with a macro and a recent addition to nasm, not built into the compiler from the ground up. I first encountered macros in Lisp back in the '70s. Not being aware of this macro's existence could be the reason they weren't used in this code. I wrote some of the simple code, Frank did the more complicated functions and subroutines, four or more years ago. It works very well. What I'm doing now is trying to add to that, this first followed by three more.
From what I've read about a struc, one needs to be instantiated before use. I'm confused, where in the code does this occur?
-mjrice
struc rot8left64_stk
resd 1 ; return address.
.lo: resd 1
.hi: resd 1
endstruc
section .text
global rot8left64_
rot8left64_:
mov eax, [esp+rot8left64_stk.lo]
mov edx, [esp+rot8left64_stk.hi]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-
All fortran function and subroutine args are pointers. One can change their values inside a function.
procedure swap(a, b)
temp : Integer;
begin
temp := a;
a := b;
b := temp;
end swap;
Interesting...
The struc is interesting. I understand it's done with a macro and a recent addition to nasm, not built into the compiler from the ground up.
Nope... struc is always there since the first versions of NASM. It's not a MACRO, mas macro too are constructs NASM has -- since the first versions...
From what I've read about a struc, one needs to be instantiated before use. I'm confused, where in the code does this occur?
If you want to create an instance of a struct... Not the case here. I am using only to avoid stack offset calculations.
-
Thanks for the information.
I removed my INHALT function, renamed your function by adding an "i" to the front, and reran it (same input). Segmentation fault is gone but the result, after to two lines of input and output, is 5 characters similar to ??*?? (the asterisk replacing a character missing from my keyboard. When I copied the characters and pasted them into a new text file they got printed on the right side of the page. Expand the page rightward and they remain on the right of the page.
Apparently the data isn't getting where it's supposed to go.
-mjrice
-
Thanks for the information.
I removed my INHALT function, renamed your function by adding an "i" to the front, and reran it (same input). Segmentation fault is gone but the result, after to two lines of input and output, is 5 characters similar to ??*?? (the asterisk replacing a character missing from my keyboard. When I copied the characters and pasted them into a new text file they got printed on the right side of the page. Expand the page rightward and they remain on the right of the page.
Apparently the data isn't getting where it's supposed to go.
-mjrice
If it's true all functions receive pointers as arguments then the code is wrong... It should be (with that info):
struc rot8left64_stk
resd 1
.ptr: resd 1
endstruc
global rot8left64_
rot8leff64_:
mov eax,[esp+rot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-
mrice@debian10-uni:~/work$ nasm -f elf krot8left64.asm -o krot8left64.o
krot8left64.asm:8: error: symbol `rot8left64_stk.ptr' undefined
mrice@debian10-uni:~/work$
-
Do you see something i missed?
mrice@debian10-uni:~/work$ gfortran test.o krot8left64.o -o test
/usr/bin/ld: test.o: in function `MAIN__':
test.f95:(.text+0x115): undefined reference to `krot8left64_'
collect2: error: ld returned 1 exit status
mrice@debian10-uni:~/work$
100 FORMAT(A8)
READ(*,100) LW
WRITE(*,100) LW
MW=KROT8LEFT64(LW)
WRITE(*,100) MW
END
struc krot8left64_stk
resd 1
.ptr: resd 1
endstruc
global krot8left64_
krot8leff64_:
mov eax,[esp+krot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-
bits 32 ; to be sure.
struc krot8left64_stk
resd 1
.ptr: resd 1
endstruc
section .text ; This was missing.
global krot8left64_
krot8leff64_:
mov eax,[esp+krot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-
Check line 7 of the new code you gave me.
-------------------------------
struc rot8left64_stk
resd 1
.ptr: resd 1
endstruc
global rot8left64_
rot8leff64_:
mov eax,[esp+rot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
Fixed it! The "bits 32" line doesn't matter. Same answer, with and without. I'd never seen it before, thought it was left in accidentally.
mrice@debian10-uni:~$ cd work
mrice@debian10-uni:~/work$ nasm -f elf krot8left64.asm -o krot8left64.o
mrice@debian10-uni:~/work$ gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
mrice@debian10-uni:~/work$ gfortran test.o krot8left64.o -o test
mrice@debian10-uni:~/work$ ./test
ABCDEFG
ABCDEFG
G ABCDEF
mrice@debian10-uni:~/work$
Looking better. Where to from here?
-
I first printed out the characters formed by eax and edx before any shld. They matched the input.
I then printed out the integer formed by eax and edx after the first shld, commenting out the second shld, just to check where we are at that point.
5135868584534286407
4746454442412047
G F E D B A b G
Reversed
G ABDEFG
I then wrote them out as charcters. They match, both missing the "C".
ABCDEFG
ABCDEFG
G ABDEFG
The "C" gets placed back in after the second shld.
Any thoughts?
-
Any thoughts?
Nope... I am not familiar with FORTRAN and not interested in the language since the compiler don't give me an optimized code (did some tests here). I'm sorry, but from now on, you're on your own...
-
Thanks for trying.
-
Not redy to give up, yet. If gfortran is the problem, might this give me a correct answer?
extern printf
section .text
global main
main:
push ebp
mov ebp, esp
push msg
call printf
push msg
call rot8left64
;
; a way to move result, in eax & edx, to ans?
;
push ans
call printf
add esp, 8
leave
ret
section .data
msg dq ' ABCDEFG'
ans dq
---------------------------------------
global rot8left64
rot8left64:
mov eax,[esp+rot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, eax
shld eax, edx, 8
shld edx, ecx, 8
ret
-
Shouldn't
shld eax, edx, 8
shld edx, ecx, 8
actually be
shld eax, edx, 8
shr edx,8
shld edx, ecx, 8
?
It seems to me that after the first shld, the low byte of edx is all zero. So you are inserting a zero byte into your result.
-
Shouldn't
shld eax, edx, 8
shld edx, ecx, 8
actually be
shld eax, edx, 8
shr edx,8
shld edx, ecx, 8
?
It seems to me that after the first shld, the low byte of edx is all zero. So you are inserting a zero byte into your result.
The lower byte of EAX will be filled with the upper byte of EDX in the first SHLD. SHLD.
A small program to demonstrate:
; Using x86-64 because I don't have a i386 linux here.
bits 64
default rel
section .rodata
hexdigits:
db "0123456789ABCDEF"
nl:
db `\n`
section .text
global _start
_start:
mov edx,0x01234567
mov eax,0x89abcdef
push rax
push rdx
mov eax,edx
call printhex
mov eax,[rsp+8]
call printhex
call printnl
pop rdx
pop rax
call f
push rax
mov eax,edx
call printhex
pop rax
call printhex
call printnl
mov eax,60
xor edi,edi
syscall
; Under test...
f:
mov ecx,eax
shld eax,edx,8 ; EAX << EDX << 8
shld edx,ecx,8 ; EDX << ECX << 8
ret
printnl:
mov eax,1
mov edi,eax
mov edx,eax
lea rsi,[nl]
syscall
ret
printhex:
mov ebx,8
rol eax,4
.loop:
push rax
and eax,0xf
lea rsi,[hexdigits+eax]
mov eax,1
mov edi,eax
mov edx,eax
syscall
pop rax
rol eax,4
dec ebx
jnz .loop
ret
-
As I understand it (asterisk representing zero):
The 1st shld changes eax (" ABC") to "ABCD" leaving edx with "EFG*".
The 2nd shld changes edx ("EFG*") to "EFG " leaving ecx with "ABC*".
That is, if ecx holds a copy of eax's initial value (" ABC").
-mjrice
-
As I understand it (asterisk representing zero):
The 1st shld changes eax (" ABC") to "ABCD" leaving edx with "EFG*".
The 2nd shld changes edx ("EFG*") to "EFG " leaving ecx with "ABC*".
That is, if ecx holds a copy of eax's initial value (" ABC").
-mjrice
Nope... as demonstrated by the code above, your "string" in EDX:EAX as 0x20414243:0x44454647, the first SHLD will get EAX as 0x45464720, and the second EDX as 0x41424344. So your "string" will be translated from " ABCDEFG" to "ABCDEFG ".
-
" ABCDEFG" to "ABCDEFG " happens to be exactly what it is supposed to do, move all the leading blanks, one by one, from left to right. That's why I needed to know how many leading blanks are in the qword. I thought I made that very clear.
-
The input to rot8left64, no exceptions (X=blank), A...H represent alphanumeric characters.
"ABCDEFGH"
"XABCDEFG"
"XXABCDEF"
"XXXABCDE"
"XXXXABCD"
"XXXXXABC"
"XXXXXXAB"
"XXXXXXXA"
-
I stand corrected. I have never used shld, so just looked it up. Didn't realise that shld eax,edx,8 only changes eax.
-
The input to rot8left64, no exceptions (X=blank), A...H represent alphanumeric characters.
"ABCDEFGH"
"XABCDEFG"
"XXABCDEF"
"XXXABCDE"
"XXXXABCD"
"XXXXXABC"
"XXXXXXAB"
"XXXXXXXA"
That's because there is something wrong with the calling convention you are using... AND I made a mistake... rotating the string to left as an uint64 is the same as rotating the chars to the right:
; rot.asm
bits 64
default rel
section .text
global rot
rot:
mov eax,[rdi]
mov edx,[rdi+4]
mov ecx,eax
shld eax,edx,8
shld edx,ecx,8
mov [rdi],eax
mov [rdi+4],edx
ret
/* test.c */
#include <stdio.h>
extern void rot( char * );
int main( void )
{
char s[] = " ABCDEFG";
printf( "%s\n", s );
rot( s );
printf( "%s\n", s );
}
$ nasm -felf64 -o rot.o rot.asm
$ cc -O2 -c -o test.o test.c
$ cc -o test test.o
$ ./test
ABCDEFG
G ABCDEF
To rotate the chars to the left I should rotate to the right:
rot8left64_:
mov ecx,edx
shrd edx,eax,8
shrd eax,ecx,8
ret
-
I'm trying to duplicate the code, and its execution, in my post from June 08, 2021, 10:29:54 PM, the one that gave G ABCDEFG. In that I compiled krot8left64.asm, eliminating the need for INHALT, so I must have changed your rot8left64.asm to krot8left64.asm, and its call from fortran to krot8left64, as below. But now the link step fails and I'm failing to see why. Your code is as it was in that post, except for the addition of the "K". Do
you see a problem?
;;;;;;;;;;;;;;;;;;;;;
100 FORMAT(A8)
READ(*,100) LW
WRITE(*,100) LW
MW=KROT8LEFT64(LW)
WRITE(*,100) MW
END
;;;;;;;;;;;;;;;;;;;;;
bits 32 ; to be sure.
struc krot8left64_stk
resd 1
.ptr: resd 1
endstruc
global krot8left64_
rot8left64_:
mov eax,[esp+krot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx,edx
shld edx,eax,8
shld eax,ecx,8
ret
;;;;;;;;;;;;;;;;;;;;;
mrice@debian10-uni:~$ nasm -f elf krot8left64.asm
mrice@debian10-uni:~$ gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
mrice@debian10-uni:~$ gfortran test.o krot8left64.o -o test
/usr/bin/ld: test.o: in function `MAIN__':
test.f95:(.text+0x115): undefined reference to `krot8left64_'
collect2: error: ld returned 1 exit status
mrice@debian10-uni:~$
-
I was missing to "K" on one of the rot8left64's. Fixed.
mrice@debian10-uni:~$ nasm -f elf krot8left64.asm
mrice@debian10-uni:~$ gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
mrice@debian10-uni:~$ gfortran test.o krot8left64.o -o test
mrice@debian10-uni:~$ ./test
ABCDEFG
ABCDEFG
ABCDEFG
mrice@debian10-uni:~$
The fortran:
100 FORMAT(A8)
READ(*,100) LW
WRITE(*,100) LW
MW=KROT8LEFT64(LW)
WRITE(*,100) MW
END
The asm:
bits 32 ; to be sure.
struc krot8left64_stk
resd 1
.ptr: resd 1
endstruc
global krot8left64_
krot8left64_:
mov eax,[esp+krot8left64_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx,edx
shrd edx,eax,8
shrd eax,ecx,8
ret
Thanks to all.
-mjrice
-
Just after posting my previous message my Debian x86 Box went kaput on me, Will get it all back later today as I have backup on Dropbox. By the way, I'm doing this for fun. Have been at it since the late '70s when I implemented part of Weizenbaum's SLIP on a 16 bit IBM 1130 clone, later doing it again for 64-bit. It's quite a surprising "app" for the early 1960s. Would be happy to share what I have with anyone interested. Will post an example when I get operational again.
The shifting (rotation?) function krot8left64.asm needs to pass its input qword to yet another function, one that returns the qword's number of blanks, it to be used to loop through the shrds the needed number of times. Or maybe there's a simpler way to do this without a function call?
-mjrice
-
I modified the bottom part of my code, as below, but something is amiss. My input is "XXXXXXXA" (X as blank) but only get a blank output. Why didn't the "A" get shifted left 6 times?
mov esi, 6
l2:
shrd edx,eax,8
shrd eax,ecx,8
dec esi
jnz l2
ret
-
Just realized I wasn't resaving edx in ecx after a shift.
mrice@debian10-uni:~/work$ ./test
A
A
A
mrice@debian10-uni:~/work$
-
An attempt at counting blanks. Anyone see a problem in my code? Answer should be 3.
-mjrice
mrice@debian10-uni:~/work$ ./test
ABCDE
ABCDE
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0xb7cfa74b
#1 0xb7cf984e
#2 0xb7f4ad6b
#3 0x4e2045
Segmentation fault
mrice@debian10-uni:~/work$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bits 32 ; to be sure.
Section .data
indx dw 0
nblank dw 0
struc kblank_stk
resd 1
.ptr: resd 1
endstruc
global kblank_
kblank_:
mov eax,[esp+kblank_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
testeax:
cmp byte [eax+indx], " "
jnz testedx
inc dword [nblank]
testedx:
cmp byte [edx+indx], " "
jnz bumpup
inc dword [nblank]
bumpup:
inc dword [indx]
cmp dword [indx], 4
jz finished
jmp testeax
finished:
mov eax, nblank
mov edx, 0
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
100 FORMAT(A8)
110 FORMAT(I8)
READ(*,100) LW
WRITE(*,100) LW
MW=KBLANK(LW)
WRITE(*,110) MW
END
-
How does one test a single byte of a register for a particular value? Maybe one doesn't, or can't?
-mjrice
-
;;;;;This
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, 0
cmp al, 32
jnz finished
inc ecx
finished:
mov eax, ecx
mov edx, 0
ret
;;;;;Produced
mrice@debian10-uni:~/work$ ./test
ABCDEFG
ABCDEFG
0
mrice@debian10-uni:~/work$
;;;;;Question
For an input of "ABCDEFG ", doesn't register AL hold the blank?
-mjrice
-
How do you get the size of an string? I recall that FORTRAN don't use NUL char terminated strings...
Hummmm... reading about FORTRAN seems like it not allow for variable size strings (am I right?). So, to scan for a string of 8 chars counting spaces, you should do something like this.
bits 32
section .text
struc kblank_stk
resd 1 ; ret addr
.str: resd 1 ; pointer to string.
endstruc
global kblank_
kblank_:
; SysV ABI for i386 mode. Must preserve ESI.
push esi
mov ecx,8 ; # of chars to check.
xor edx,edx ; # of spaces found.
; Get string pointer from stack.
mov esi,[esp+kblank_stk.str]
jmp .test
align 4
.loop:
lodsb ; AL = next char from string.
cmp al,' ' ; AL == ' '?
jnz .skip ; No, skip counting
inc edx ; Increment # spaces found
.skip:
dec ecx ; Decrement char counter
.test:
test ecx,ecx ; Is there any char left?
jnz .loop ; Yes, loop.
; Restore ESI.
pop esi
mov eax,edx ; return count in EAX.
ret
-
Welcome back. I think you're correct about the strings.
I've been busy. After my last message I poked around some and finally wrote some code that will count blanks in my 8 character 64-bit variables. I'm using ECX as a counter (code below). Tried using ESI so I wouldn't have to set it for the later shifting but got segmentation errors. Compiler, don't know which, perhaps both, seem to flake out on me, was giving me segmentation errors for the code below earlier, so I removed both NASM and gfortran and reinstalled both, after rebooting. The code then ran fine. Weird, huh? I'll try ESI again tomorrow. I knew the code was good because when I finally got it to run I emailed a copy to myself. I'm aware that EAX must be restored before
shifting occurs. Will try out your code tomorrow.
-mjrice
mrice@debian10-uni:~/work$ ./test
ABCDEFG
ABCDEFG
1
mrice@debian10-uni:~/work$ ./test
A
A
7
;;;;;;;;;;;;;;;;;;;
bits 32 ; to be sure.
struc kjunk_stk
resd 1
.ptr: resd 1
endstruc
global kjunk_
kjunk_:
mov eax,[esp+kjunk_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx, 0
l1:
cmp al, 32
jnz l2
inc ecx
l2:
ror eax, 8
cmp al, 32
jnz l3
inc ecx
l3:
ror eax, 8
cmp al, 32
jnz l4
inc ecx
l4:
ror eax, 8
cmp al, 32
jnz l5
inc ecx
l5:
; ror eax, 8
mov eax, edx
l6:
cmp al, 32
jnz l7
inc ecx
l7:
ror eax, 8
cmp al, 32
jnz l8
inc ecx
l8:
ror eax, 8
cmp al, 32
jnz l9
inc ecx
l9:
ror eax, 8
cmp al, 32
jnz finished
inc ecx
finished:
mov eax, ecx
mov edx, 0
ret
-
Code I sent worked fine after changing ECX to ESI.
Added this line up before the rotations to save EAX
; mov ebx, eax ;save EAX
It alone caused a seg-fault. I commented it out and, suprise! - it worked again.
Also, after label "finished:", I swapped these
mov eax, esi
mov edx, 0
for
; mov eax, ebx ;restore EAX
;
; mov ecx, edx
;
;l10:
; shrd edx,eax,8
; shrd eax,ecx,8
; mov ecx, edx
; dec esi
; jnz l10
Can you think of any reason why using EBX would cause a seg-fault?
-
Just ran the code you supplied:
ABCD
ABCD
0
mrice@debian10-uni:~/work$ ./test
ABCDEF
ABCDEF
0
mrice@debiIan10-uni:~/work$ ./test
A
A
0
Let me know if you have any changes.
-
Got my code working. EAX gets used and abused in the blank search, so I pushed it before, and popped it after. Will post code later. May be a way to make it briefer now that we have it working.
mrice@debian10-uni:~/work$ ./test
ABCD
ABCD
ABCD
mrice@debian10-uni:~/work$ ./test
ABCDEF
ABCDEF
ABCDEF
mrice@debian10-uni:~/work$
-
mrice@debian10-uni:~/work$ ./test
A
A
A
mrice@debian10-uni:~/work$ ./test
ABCDEFG
ABCDEFG
ABCDEFG
mrice@debian10-uni:~/work$ ./test
ABCDEFGH
ABCDEFGH
ABCDEFGH
The function, named lanorm.asm, because that's what it's called by the other code.
bits 32 ; to be sure.
struc lanorm_stk
resd 1
.ptr: resd 1
endstruc
global lanorm_
lanorm_:
mov eax,[esp+lanorm_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
push eax ;save eax
mov esi, 0 ;initialize counter for blanks
l1:
cmp al, 32 ;search EAX for blanks
jnz l2
inc esi
l2:
ror eax, 8
cmp al, 32
jnz l3
inc esi
l3:
ror eax, 8
cmp al, 32
jnz l4
inc esi
l4:
ror eax, 8
cmp al, 32
jnz l5
inc esi
l5:
mov eax, edx ;search EDX for blanks
l6:
cmp al, 32
jnz l7
inc esi
l7:
ror eax, 8
cmp al, 32
jnz l8
inc esi
l8:
ror eax, 8
cmp al, 32
jnz l9
inc esi
l9:
ror eax, 8
cmp al, 32
jnz finished
inc esi
finished:
pop eax ;restore EAX
mov ecx, edx
l10:
shrd edx,eax,8
shrd eax,ecx,8
mov ecx, edx
dec esi
jnz l10
ret
-
Finding that the AL register points at the "highest" character :
mov al, 63
ABCDEFGH becomes ?BCDEFGH
Here's a much shorter version, with no blank counting.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
bits 32 ; to be sure.
struc lanorm_stk
resd 1
.ptr: resd 1
endstruc
global lanorm_
lanorm_:
mov eax,[esp+lanorm_stk.ptr] ; get pointer
mov edx, [eax+4] ; get QWORD from pointer.
mov eax, [eax]
mov ecx,edx
loop:
cmp al, 32
jnz finished
shrd edx,eax,8
shrd eax,ecx,8
mov ecx, edx
jmp loop
finished:
ret
-
You still don't provide any reference of what calling convention is used by gfortran and what exactly you want to do, so the only thing I can do is to GUESS...
gfortran (and fortran, in general) is a shitty compiler in terms of optimization. You **could** make your function in fortran and take e look at the generated assembly code using -S option (and `-masm=intel` to see assembly in intel syntax, not AT&T syntax), but gfortran creates a bad code (in terms of optimization)...
OR.. you can use `gcc` (which is a very good compiler, in terms of optimization)... Here's a test of a function rotating 8 first chars in a string:
/* test.c */
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
// Generic rotate left 1 QWORD 'bits' bits.
static uint64_t rotateleft ( uint64_t n, unsigned int bits )
{
// Rotate bits to the left.
n = ( n << bits ) |
( n >> sizeof ( uint64_t ) * CHAR_BIT - bits );
return n;
}
// This will deal only with the 8 first chars.
// Rotating them 1 char to the right.
void krotateright ( char *s )
{
// Convert the first 8 bytes to QWORD.
uint64_t n = * ( uint64_t * ) s;
// Rotate CHAT_BIT bits and stores back at the memory pointed by s.
* ( uint64_t * ) s = rotateleft ( n, CHAR_BIT );
}
/* test */
int main ( void )
{
char s[] = "ABCDEFG ";
for ( int i = 0; i < 8; i++ )
{
printf ( "\"%s\" --rotate right 1 char--> ", s );
krotateright ( s );
printf ( "\"%s\"\n", s );
}
}
Compiling and running:
$ cc -O2 -o test test.c
$ ./test
"ABCDEFG " --rotate right 1 char--> " ABCDEFG"
" ABCDEFG" --rotate right 1 char--> "G ABCDEF"
"G ABCDEF" --rotate right 1 char--> "FG ABCDE"
"FG ABCDE" --rotate right 1 char--> "EFG ABCD"
"EFG ABCD" --rotate right 1 char--> "DEFG ABC"
"DEFG ABC" --rotate right 1 char--> "CDEFG AB"
"CDEFG AB" --rotate right 1 char--> "BCDEFG A"
"BCDEFG A" --rotate right 1 char--> "ABCDEFG "
If you compile with:
$ cc -O2 -S -masm=intel -fcf-protection=none test.c -o test.s
This will generate the assembly listing of the entire code. Take a look at `test.s` and you'll see something like this:
krotateright:
push ebx
mov ecx, [esp+8]
mov eax, [ecx]
mov edx, [ecx+4]
mov ebx, eax
shrd eax, edx, 8
shrd edx, ebx, 8
mov [ecx], eax
mov [ecx+4], edx
pop ebx
ret
Which isn't the best code possible, but it is a start.
-
A lot of this is already implemented. Will send an example to give you a better idea of what SLIP all about.
-
Two figures attached, both from the ACM document "Symmetric List Processor," author Joseph Weizenbaum.
The part I'm working on now allows a user to enter a textual representation of a list, like the one in Fig. 3, from the keyboard, and construct from it an internal list, as shown in the diagrams. Currently lists can only be constructed programmatically. Will post an example of that next.
-
Ran this this morning.
! Sums structural list of real numbers, prints list and sum.
dimension space(100) ! Set aside list space
call initas(space,100)
l1 = 0
l2 = 0
idummy = list(l1) ! Function list both assigns list-name to its argument and returns the list name
idummy = list(l2)
idummy = newbot(1.0,l1)
idummy = newbot(6.0,l2)
idummy = newbot(l2,l1)
idummy = newbot(3.0,l1)
call prlsts(l1,3) ! 3 means list is real numbers; 2 is characters; 1 is integers
total = 0.0
k = lrdrov(l1) ! Create list reader
1 x = advsel(k,f) ! Advance reader structurally, (s), by element (e). Parameter f is a flag
if (f .ne. 0) go to 2 ! Reader at end of list?
total = total + x
go to 1
2 continue
print *, total
end
mrice@debian10-uni:~/slip/test$ ./test
BEGIN LIST
1.0000
BEGIN SUBLIST
6.0000
END SUBLIST
3.0000
END LIST
10.000000000000000
-
Btw, used your shifting function to create 8 masks I'll need for my next task. Just changed the Rs to Ls in the shifting functions. Started at the low end with 255 rather than the high end with -72 quadrillion.
mrice@debian10-uni:~$ ./test
FF00000000000000
FF000000000000
FF0000000000
FF00000000
FF000000
FF0000
FF00
FF
! Create a mask for each of 8 characters
INTEGER CP,COPY
DIMENSION CP(8)
100 FORMAT(Z16)
DO 10, I=1,8
CP(I)=0
10 CONTINUE
! Start with the low end
CP(8)=255
! Shift the other 7 leftward from it
DO 20, I=7,1,-1
COPY=CP(I+1)
CP(I)=KROT8LEFT64(COPY)
20 CONTINUE
DO 30, I=1,8
WRITE(*,100) CP(I)
30 CONTINUE
END
-
Oops, asked for the G CP(7), shifted it rightward, got the B instead.
READ(*,100) IGET
IWORD=ISHFT(IAND(IGET,CP(7)),-8)
mrice@debian10-uni:~$ ./test
ABCDEFGH
B
mrice@debian10-uni:~$
Think of the variable IGET as one 64 bit word from an array of 10 of them read from a punched card. The characters on the word are removed from that word one at a time and shoved one at a time into a waiting all blank 64 bit word from the left end, the same for each succeeding character, shifting earlier characters leftward, until a blank or a comma is found, then the word shifted leftward until all blanks, if any, are to the right of the other characters, forming a token which can be pushed up from the bottom of a waiting list. Encountering a right paren character completes the list. The function RDLSTA recursively reads sublists encountered in this process.
Looking for a way to data-ize the masks to be local to the function. Will try this later:
! DATA CP(1:8)
! /
! Z'FF00000000000000',
! Z'00FF000000000000',
! Z'0000FF0000000000',
! Z'000000FF00000000',
! Z'00000000FF000000',
! Z'0000000000FF0000',
! Z'000000000000FF00',
! Z'00000000000000FF'
! /
-
root@debian10-uni:/home/mrice# ./test
FF
FF00
FF0000
FF000000
FF00000000
FF0000000000
FF000000000000
FF00000000000000
root@debian10-uni:/home/mrice# gfortran -c -fdefault-integer-8 -fdefault-real-8 -fno-range-check test.f95 -o test.o
root@debian10-uni:/home/mrice# gfortran test.o krot8left64.o -o test
root@debian10-uni:/home/mrice# ./test
ABCDEFGH
G
Reversed the order of the masks and got the 7th character, the G. The computer that was used in he early 1960s must have been big endian?
Can't find a gfortran that will accept hexadecimals in a data statement. Tried gfortran-8. Now to write SQOUT, a function that will "squeeze out" individual characters as this fortran code does. Another function, to come later, called SQIN will squeeze the output from SQOUT into a waiting, initially all blank, 64 bit word a character at a time.
A line from the fortran code of the SLIP document:
SYMBOL = SQIN(CP(8),SQOUT(CP(IC),CRDBUF(IW)),PLACE)
CP(8) should probably be changed to CP(1)? Also, since IC currently starts at 1 and increments upward, it should begin at 8 and decrement downward. Or, easier, re-reverse the order of the masks? :-)
-
Finally found a way to localize the masking variables to the RDLSTA function.. Using them to print a few characters on the low end of "ABCDEFGH". On to asm function SQOUT(MASK,WORD).
mrice@debian10-uni:~$ ./test
ABCDEFGH
H
G
F
E
mrice@debian10-uni:~$
! Create a mask for each of 8 characters
INTEGER CP(8),COPY
DATA CP(1)/Z'00000000000000FF'/
DATA CP(2)/Z'000000000000FF00'/
DATA CP(3)/Z'0000000000FF0000'/
DATA CP(4)/Z'00000000FF000000'/
DATA CP(5)/Z'000000FF00000000'/
DATA CP(6)/Z'0000FF0000000000'/
DATA CP(7)/Z'00FF000000000000'/
DATA CP(8)/Z'FF00000000000000'/
100 FORMAT(A8)
110 FORMAT(Z16)
! DO 30, I=1,8
! WRITE(*,110) CP(I)
! 30 CONTINUE
READ(*,100) IGET
IWORD=ISHFT(IAND(IGET,CP(8)),0)
WRITE(*,100) IWORD
IWORD=ISHFT(IAND(IGET,CP(7)),-8)
WRITE(*,100) IWORD
IWORD=ISHFT(IAND(IGET,CP(6)),-16)
WRITE(*,100) IWORD
IWORD=ISHFT(IAND(IGET,CP(5)),-24)
WRITE(*,100) IWORD
END