QLiberator decompiler

Anything QL Software or Programming Related.
EmmBee
Trump Card
Posts: 240
Joined: Fri Jan 13, 2012 5:29 pm
Location: Kent

Re: QLiberator decompiler

Post by EmmBee »

HAOUI wrote:
IMHO, What we need instead, is PARNAM$() or PARTYP$() working for compiled $$external. I already wrote similar functions as assembler extensions that work for $$external (see sources and binary in attached archive). I called them PARNAMEX$() and PARSTREX$(). I am not totally happy with these extensions but it does work. I think it could be better written with some more information. Also, it could be easily amended to support interpreted programms and replace tk2 original functions.
Any feedback, suggestion welcomed.
Alain
paramex.zip
I've just tested this out. It works well. Just what we need. Well done!
If it can be amended to work in Basic as well, that would be great.
It would be a total replacement for the existing similar commands in TK2.


Martin_Head
Aurora
Posts: 852
Joined: Tue Dec 17, 2013 1:17 pm

Re: QLiberator decompiler

Post by Martin_Head »

I know how to decompile a compiled SuperBASIC program. But I don't know a great deal about how QLiberator actually works.

To use a name with a Procedure, you could use the same method as the operating system. It looks at the name table entry, If it finds a 'name' it converts it into a string. It does this by manipulating the the name table entry. I can't remember the exact details, but I have done it for SuperBASIC extensions in the past, by copying a short routine from the SMSQ/E source code.
You could do this on the SuperBASIC side, or perhaps in the QLib object itself.

I'm pretty sure that QLiberator externals, are just added to the underlying SuperBASIC using BP.INIT like normal SuperBASIC extensions.

I was having a little look yesterday at my QLIB dumps. On the Externals list page of my De-Lib Decompiler Technical Notes, The Externals list seems to be the data for a BP.INIT in the initialization area of the _OBJ file. If you study the Externals list code , it does look like BP.INIT data. Where the offset to the start of the command, is that offset to the NOP. That NOP($4E71) is followed by a MOVE.L #...,D4. That value being a pointer to the start of the code for the Procedure/Function.

I don't know where, or how QLiberator generates this code, or if the NOP serves a purpose. But it may be possible to use those two bytes as a short branch to a subroutine to do the name table manipulation. Assuming that QLib uses a name table the same as QDOS.


HAOUI
Bent Pin Expansion Port
Posts: 89
Joined: Tue Dec 14, 2010 2:17 pm

Re: QLiberator decompiler

Post by HAOUI »

EmmBee Wrotes
I've just tested this out. It works well. Just what we need. Well done!
If it can be amended to work in Basic as well, that would be great.
It would be a total replacement for the existing similar commands in TK2.
Attached archive contains mimics of TK2 PARUSE(), PARTYP(), PARAM$() and PARSTR$() commands which can work in interpreted programs and QLIB compiled $$external. They use same parameters in both cases.

Mainly useful to fetch NAME type actual parameters passed without quotes to compiled $$external.

Under S*BASIC interpreters, they work strictly as original TK2 commands.

When used in COMPILED $$external PROCedure :
PARUSE(),PARTYP() work as expected
PARNAM$(),PARSTR$() fetch actuals parameters passed from any S*BASIC caller

Included sources, binaries and rudimentary readme.

Alain
tkparex.zip
(15.05 KiB) Downloaded 116 times


HAOUI
Bent Pin Expansion Port
Posts: 89
Joined: Tue Dec 14, 2010 2:17 pm

Re: QLiberator decompiler

Post by HAOUI »

Thank you Martin_Head for your feedback. Appreciated.

My understanding now is :

1) Indeed, $$external is registred by BP.INIT as machine-code PROC but as it is not and can't be executed, QLIB as you say insert a call to a RUNTIME machine-code at the start of external which creates a job and executes external as a normal and independant QLIBerated program

2) QLIBerated programs use the same Name Table as QDOS but not the same Return Table. This is why PARNAM$ and PARSTR$ TK2 commands couldn't never work and may easily crash system.

3) The created job starts with its own Name Table. Manual states that it is a copy of the caller NT but this is not completely true. Unfortunately this NT doesn't contain the passed parameters (they still available on the NT of the caller until return from job). So, using of classical assembler methods you mentionned can't work, either.

4) By-pass I found is to access the NT of the caller and search wanted parameters. It does work but I don't like very much this method, because I have to enter SuperVisor mode and we can't know the number of actually entered parameters when command was issued (QDOS doesn't create an entry in its Return Table when calls "machine-code" exts).

As I said before, giving that external copies back altered parameters, I guess that somebody (RUNTIME or Job, it can't be SB or QDOS) holds some pointers to this area (but where ?). Without more info, I am afraid to have to deassemble QLIB RUNTIMEs to understand /improve (too old now for this hack..).

Alain


Martin_Head
Aurora
Posts: 852
Joined: Tue Dec 17, 2013 1:17 pm

Re: QLiberator decompiler

Post by Martin_Head »

I don't think the QLib runtime module has anything to do with externals. I think the externals are handled by the _OBJ file itself.

I had a very quick look at your assembler code, where you are examining the name table entries with A3 and A5. This is the routine I was thinking about for converting a 'name' into a 'string'

Code: Select all

; ***************************************************************
;        UT_GTNM1 Take a supplied string, or name parameter and 
;        put it on the maths stack as a string. Missing parameters
;        cause an empty string to be placed on the maths stack.
;        On exit BV_RIP is cleared
;        Based on code from SMSQE copyright 1985 Tony Tebby
;  
; Entry  A1 points to top of Maths stack
;        A3 Points to first parameter in name table
;        A5 Points to last paramter in name table
; Exit   A1 Points to string on Maths stack
;        D0 Error return
; D1-D3,A2  Smashed
; ***************************************************************

ut_gtnm1 cmp.l    a3,a5                         ;is there at least one param?
         bgt.s    ut_gtnam                      ;yes, there is

; Return an empty string on the maths stack
ut_gtnul bsr      ut_ckri6                      ;make room for string on maths stack - 6 bytes
         sub.l    #2,a1                         ;total length of string 2 bytes (length word)
         clr.w    (a6,a1.l)                     ;set string length to zero bytes
         bra.s    utgn_ok                       ;exit without error

; Get the name type word from the name table entry
ut_gtnam moveq    #$f,d0                        ;extract type of name
         move.w   (a6,a3.l),d1                  ;get the type word from the name table entry
         cmp.w    #$0300,d1                     ;internal substring array?
         beq.s    ut_gtnst                      ;..yes, get it
         
         and.b    d1,d0                         ;..no, mask out everything but last 4 bits
         beq.s    ut_gtnul                      ;return an empty string if a null parameter

         tst.w    2(a6,a3.l)                    ;is there a name?
         bmi.s    ut_gtnst                      ;..no, it's $FFFF. Get it as a normal string

         subq.b   #1,d0                         ;is it a string?
         bne.s    ut_gnmpt                      ;..no, get it as a name instead

; Get a normal string parameter onto the maths stack
ut_gtnst bsr.s    ut_gnst1                      ;get one string (no check)
         bne.s    utgn_rts                      ;problem? Exit with error
         
         moveq    #3,d1                         ;round up to word, including char count
         add.w    (a6,a1.l),d1                  ;get length of string on maths stack
         bclr     #0,d1
         add.l    d1,bv_rip(a6)                 ;clear maths stack, but leave A1 pointing at the string
         bra.s    utgn_ok                       ;exit without error

; Get a name parameter onto the maths stack
ut_gnmpt moveq    #0,d1
         move.w   2(a6,a3.l),d1                 ;get the pointer to the real entry - in the name table
         blt.s    ut_gtnul                      ;... expression is no good - in case a $FFFF slips through
         lsl.l    #3,d1                         ;in multiples of 8 bytes - length of name table entries
         add.l    bv_ntbas(a6),d1               ;add to base of BASIC name table - to find entry in name table

ut_ntnam moveq    #0,d3
         move.w   2(a6,d1.l),d3                 ;get the entry from name table
         add.l    bv_nlbas(a6),d3               ;and add to start of name list, to find entry in name list
         
; Put the name pointed at by D3 onto the maths stack
ut_nmtos moveq    #3,d1                         ;get the length of the name as a long word
         add.b    (a6,d3.l),d1                  ;get length of entry from name list
         bclr     #0,d1                         ; rounded up (+2)
         bsr.s    ut_chkri                      ;make room for D1 bytes on the maths stack

         add.l    d1,d3                         ;move to end of string (ish)

ut_nm_lp subq.l   #1,d3                         ;adjust pointers
         subq.l   #1,a1
         move.b   -1(a6,d3.l),0(a6,a1.l)        ;copy bytes of name onto maths stack
         subq.w   #1,d1                         ;decrement loop count
         bgt.s    ut_nm_lp
         clr.b    (a6,a1.l)                     ;clear top byte of string length word

utgn_ok  moveq    #0,d0

utgn_rts rts


; Reserve D1 bytes on the maths stack 
ut_ckri6 movem.l  d1/d2/d3/a2,-(a7)             ;save registers
         moveq    #6,d1                         ;we want 6 free bytes on the stack
         bra.s    utc_do

ut_chkri movem.l  d1/d2/d3/a2,-(a7)             ;save registers

utc_do   move.w   bv_chrix,a2                   ;reserve space
         jsr      (a2)
         movem.l  (a7)+,d1/d2/d3/a2             ;and restore them

ut_setri move.l   bv_rip(a6),a1
         rts


; Get a normal string parameter onto the maths stack
; Returns with D3=no of strings returned, and D0 an error code
ut_gnst1 move.l   a5,-(a7)                      ;save name table top pointer
         lea      8(a3),a5                      ;set name table to have just one entry
                  
         movem.l  d4/d6/a0/a2,-(a7)             ;save registers
         move.w   ca_gtstr,a2                   ;get a string
         jsr      (a2)                          ;do the operation
         movem.l  (a7)+,d4/d6/a0/a2             ;restore registers
         
         move.l   (a7)+,a5                      ;restore name table top pointer
         rts

I pulled this from my MDI driver source. It allows me to have a SuperBASIC extension that can use a command like - MOUNT_MDI 1,dos1_imagefile_img


HAOUI
Bent Pin Expansion Port
Posts: 89
Joined: Tue Dec 14, 2010 2:17 pm

Re: QLiberator decompiler

Post by HAOUI »

I understood what you meant and made several similar assembler routines in the past for extensions, but this has no chance to work for externals. As I said before, parameters passed to the external are not copied into the name table of the created job for external. That's why I tried this time to access the name table of the caller, no other choice I am afraid.
Also, I do confirm, when external is called, QLIB RUNTIME (embeded or rte) is started first.
Thanks,
Alain


User avatar
RalfR
Aurora
Posts: 872
Joined: Fri Jun 15, 2018 8:58 pm

Re: QLiberator decompiler

Post by RalfR »

EmmBee wrote:Ralf, about sedit_63 - have you renamed the vars, yet?
Just found the source today. A test.win where I have copied a lot of files without directories.

Always good to have a backup in the office! Now I have to put all the files together.

Image


4E75 7000
EmmBee
Trump Card
Posts: 240
Joined: Fri Jan 13, 2012 5:29 pm
Location: Kent

Re: QLiberator decompiler

Post by EmmBee »

Ralf R. wrote:
EmmBee wrote:Ralf, about sedit_63 - have you renamed the vars, yet?
Just found the source today. A test.win where I have copied a lot of files without directories.

Always good to have a backup in the office! Now I have to put all the files together.

Image
Would be good if the original authors of QLiberator could suddenly find their sources!


User avatar
RalfR
Aurora
Posts: 872
Joined: Fri Jun 15, 2018 8:58 pm

Re: QLiberator decompiler

Post by RalfR »

EmmBee wrote:Would be good if the original authors of QLiberator could suddenly find their sources!
I am pretty sure, that TT has the sources, I think he was much involved in that project.


4E75 7000
HAOUI
Bent Pin Expansion Port
Posts: 89
Joined: Tue Dec 14, 2010 2:17 pm

Re: QLiberator decompiler

Post by HAOUI »

Ralf R. wrote:
EmmBee wrote:Would be good if the original authors of QLiberator could suddenly find their sources!
This is the best thing that could happen, especially for RUNTIMEs which could not be decompiled. Deassembling 11 Kbytes of pure binary code may give thousands and thousands of assembler instructions, uncommented/undocumented. A real nightmare. IMHO, any improvement on the compiler side may need some work on RUNTIMEs also.
Alain


Post Reply