#emit Discussion
#1

Anyone knows how to use JZER/JUMP/etc?

This doesn't seem to work:
Код:
#emit l.15
#emit INC pos
#emit LOAD.pri pos
#emit LOAD.S.alt cmdtext
#emit LIDX
#emit EQ.C.pri 20
#emit JZER 16
#emit JUMP 15

#emit l.16

#emit LOAD.S.alt cmdtext
#emit LOAD.pri pos
#emit IDXADDR
Код:
Run time error 22: "AMX not initialized (or doubly initialized)"
Reply
#2

95% of this forum (including me) have no idea how to use #emit. So I believe that you may not find an answer to your question.
Reply
#3

Hm, I didn't even consider emitting labels possible, but it almost works:
Quote:

CODE 0 ; 0
;program exit point
halt 0

proc ; main
; line 1
break ; c
; line 2
break ; 10
push.c 0
call .Hello
;$exp
zero.pri
retn

proc ; Hello
; line 6
break ; 30
; line 7
break ; 34
;$lcl pos fffffffc
stack fffffffc
zero.pri
stor.s.pri fffffffc
;$exp
;$lcl cmdtext fffffff8
stack fffffffc
zero.pri
stor.s.pri fffffff8
;$exp

inc fffffffc
load.pri fffffffc
load.s.alt fffffff8
lidx
eq.c.pri 14
jzer 10
jump f
l. 10
load.s.alt fffffff8
load.pri fffffffc
idxaddr
; line 18
break ; b4
const.pri 1
stack 8
retn


DATA 0 ; 0
dump 6c 2e 31 35 0

STKSIZE 1000

As you can see, for some reason it almost works, but adds space before number. I wouldn't work with this. From quick analysis of YSI I see JUMP.rel and JZER.rel is more flexible approach. Also, unless you want to use pure Pcode, you can just write it as

pawn Код:
new tmp;

do {
    #emit INC pos
    #emit LOAD.pri pos
    #emit LOAD.S.alt cmdtext
    #emit LIDX
    #emit STOR.S.pri tmp
} while (20 != tmp);

#emit LOAD.S.alt cmdtext
#emit LOAD.pri pos
#emit IDXADDR
Reply
#4

I can't find JZER.rel in PAWN Imp Guide.

I am guessing that JZER.rel works like SCTRL? We add 4 bytes for each instruction and operand to calculate the relative address.

EDIT:
Код:
fatal error 104: invalid assembler instruction "jzer.rel"
I am not using amx_assembly so I can't use @emit
--------------------------------------------------------------------
Код:
static nullstr[] = "";
getproperty(0,cmdtext,cellmin,nullstr);
Код:
push.c f4
;$par
push.c 80000000
;$par
push.s 10
;$par
push.c 0
;$par
push.c 10
sysreq.c 2	; getproperty
is faster than

Код:
getproperty(.name = cmdtext);
Код:
const.pri 104
heap 4
movs 4
push.alt
;$par
push.c 80000000
;$par
push.s 10
;$par
push.c 0
;$par
push.c 10
sysreq.c 2	; getproperty
This happens if the default argument is a string!

Speed Test:
138ms,140ms,136ms
160ms,155ms,154ms
Reply
#5

Oh, my bad then. Yes, JZER.rel is just a wrapper apparently.
Код:
stock AsmError:AsmEmitJzerRel(ctx[AsmContext], offset) {
	return AsmEmitJumpInstruction(ctx, OP_JZER, offset);
}
I wasn't aware of this second notation to getproperty.

Getting back to main topic: I think you need to retrieve CIP, add your offset, and use JUMP with new value - doing a faux relative jump. Same with JZER. It seems labels will get mangled when #emitting, so better to operate on known values. Use noop for padding if you wish.
Reply
#6

Код:
native getproperty(id=0, const name[]="", value=cellmin, string[]="");
You can give the arguments in the order of your wish by preceding the parameter name with '.'
Код:
getproperty(.name = "name", .value = 100);
--------------------------------------------------------------------------
I made a different kind of loop.

Код:
#emit LCTRL 6 
#emit ADD.C 16 // 2*4 = 8 bytes
#emit STOR.pri addr //2*4 = 8 bytes

if(cmdtext[++pos] == ' ')
{
    #emit LOAD.pri addr
    #emit SCTRL 6
}
--------------------------------------------------------------------------

Main Topic:
If you look at the PAWNCC generated assembly, you'll find that it adds the label number to the JZER instruction rather than the address.

But the PAWN Imp Guide tells this "if PRI == 0 then CIP = CIP + offset"

Unlike JUMP.pri there is no JZER.pri so I have to give a number

So its impossible to use JZER?

Was searching YSI if ****** had ever used JUMP or the conditional jump instructions but couldn't find any!! He uses SCTRL everywhere
Reply
#7

Never mind. Just read your comment above.

_____________

Just to not ruin this comment...

You might find something useful.

https://sampforum.blast.hk/showthread.php?tid=358084

https://github.com/Zeex/amx_assembly...ter/opcode.inc
Reply
#8

Figured out how to use JUMP & Conditional JUMP Instructions

Код:
lable1:
print("HI");

#emit JUMP lable1
Reply
#9

And how is that different from the generally frowned upon
pawn Код:
goto label1;
?
Reply
#10

Quote:
Originally Posted by Vince
Посмотреть сообщение
And how is that different from the generally frowned upon
pawn Код:
goto label1;
?
I mentioned Conditional JUMP Instructions too in my post.

Код:
#emit JZER lable
You cannot have conditional gotos.

Moreover my intention was let people who did not know how to give offset to jump instructions. I had asked many before and no one knew.

Код:
if(k == 0) goto lable;
will produce an assembly output something like this

Код:
#emit LOAD.S.pri k
#emit JZER somewhere
somewhere:
JUMP lable
you can avoid that extra jump using the following code
Код:
#emit LOAD.S.pri k
#emit JZER lable
Reply
#11

I just can't see what is wrong in the code below

Код:
stock _INI_LOG(INI:handle, msg[], {Float, _}:...)
{
	printf("ERR MSG %s",msg);

    static arg_count_bytes;
    static str[128],start_adr,end_adr;

    new File:LogFile = fopen(INI_LOG_FILE,io_append);

    #emit LOAD.S.pri  8
	#emit CONST.alt 8 //2 STATIC ARGUMENTS ; 2*4 = 8
	#emit SUB
	#emit STOR.pri arg_count_bytes

    if(arg_count_bytes)
    {
        #emit LCTRL	5
        #emit CONST.alt	msg
        #emit ADD
        #emit STOR.pri	start_adr

        #emit LOAD.alt	arg_count_bytes
        #emit ADD
        #emit STOR.pri	end_adr

        do
        {
            #emit LOAD.I
            #emit PUSH.pri
            #emit LOAD.pri end_adr
            #emit CONST.alt 4
			#emit SUB
			#emit STOR.pri end_adr
        }while(end_adr > start_adr);

        #emit PUSH.S	msg
        #emit PUSH.C 	128
        #emit PUSH.ADR	str

		#emit LOAD.pri arg_count_bytes
		#emit CONST.alt 12
		#emit ADD
		#emit STOR.pri arg_count_bytes
        #emit PUSH.pri

        #emit SYSREQ.C	format

        #emit LOAD.pri arg_count_bytes
		#emit CONST.alt 4
		#emit ADD
		#emit XCHG

        #emit LCTRL	4
        #emit ADD
        #emit SCTRL	4

        if(LogFile)
            fwrite(LogFile,str);
        else
        {
            print("Could not open Log File ("#INI_LOG_FILE")");
            print(str);
		}
	}
	else
	{
        if(LogFile)
        {
            fwrite(LogFile,str);
			fclose(LogFile);
		}
        else
        {
            print("Could not open Log File("#INI_LOG_FILE")");
            print(str);
		}
    }
}
Код:
[08:42:39] ERR MSG [INI]CreateINI:File already exists(%s)
[08:42:39] ERR MSG [INI]Warning:Creating another instance of the same file(%s)
[08:42:39] ERR MSG [INI]ReadString:Key(%s) not found in section ID %d 
[08:42:39] [debug] Run time error 6: "Invalid instruction"
[08:42:39] [debug]  Unknown opcode 0x24000000 at address 0x00000061
[08:42:39] [debug] AMX backtrace:
[08:42:39] [debug] #0 00000061 in public OnFilterScriptInit () at H:\eXtended INI Processor\Server\pawno\include\eINI.inc:254
[08:42:39]   Loaded 1 filterscripts.
It works few times and then suddenly fails
The line 254 is the printf at the very beginning of the function. So did I corrupt the AMX?

Did some random changes to my OnFilterScriptInit which has no relationship with my INI Include but the error seems to change

Код:
[08:50:43] -4081998 ERR MSG [INI]CreateINI:File already exists(%s)
[08:50:43] [debug] Server crashed while executing TestEINI.amx
[08:50:43] [debug] AMX backtrace:
[08:50:43] [debug] #0 native format () [00472b80] from samp-server.exe
[08:50:43] [debug] #1 000001e0 in _INI_LOG (INI:handle=-4081998, msg[]=@0x0009563c "[INI]CreateINI:File already ex...", ... <1 argument>) at H:\eXtended INI Processor\Server\pawno\include\eINI.inc:277
[08:50:43] [debug] #2 0000095c in INI:eINI_CreateINI (fname[]=@0x0009a924 "NewFile.ini") at H:\eXtended INI Processor\Server\pawno\include\eINI.inc:483
[08:50:43] [debug] #3 00011888 in public OnFilterScriptInit () at H:\eXtended INI Processor\Server\filterscripts\TestEINI.pwn:44
[08:50:43] [debug] Native backtrace:
[08:50:43] [debug] #0 00403334 in ?? () from samp-server.exe
[08:50:43] [debug] #1 625658ca in ?? () from plugins\crashdetect.DLL
[08:50:43] [debug] #2 6256774f in ?? () from plugins\crashdetect.DLL
[08:50:43] [debug] #3 62560834 in ?? () from plugins\crashdetect.DLL
[08:50:43] [debug] #4 6256591a in ?? () from plugins\crashdetect.DLL
[08:50:43] [debug] #5 0046a918 in ?? () from samp-server.exe
Код:
#emit ADD
        #emit STOR.pri	end_adr

        do <- LINE 277
        {
            #emit LOAD.I
            #emit PUSH.pri
Reply
#12

With LOAD.S.pri/alt :
  • I use the value 8, I get the args count in bytes. : *( dat + frm + 8 )
  • I use the value 0, I get an address pointing to the args count in bytes of the last function called. : *( dat + frm )
I would like to know what is the the value 4 when I use it with LOAD.S.pri/alt ? : *( dat + frm + 4 )
Reply
#13

You will get the return address.

0 stores current frame address
4 stores function return address
8 stores the argument count in terms of total size

I have explained the stack structure after a function call here
forum.sa-mp.com/showthread.php?p=3596399
Reply
#14

I have 3 questions.

In the PDF "Implementor’s Guide", let's take LOAD.pri : pri = PRI = [address]
It is mentioned :
Quote:

An item between square brackets indicates a memory access (relative to the data register, except for jump and call instructions)

So, his code in C is :
PHP код:
pri = *(data address
1. My first question is : there is any difference between a "data register" and a "data segment" ?

2. My second question is based on the tests I made.
I know when I declare a variable, her value is stored in memory, but we don't have acces to it easily, because I thought that it was only necessary to rely on the semantics.

Example : If I declare a variable named "myVar" with the value 41566421 and I want to get her address in the memory :
PHP код:
#include "a_samp"
main()
{
    new 
        
myVar 41566421,
        
globalAddress;
    
#emit ADDR.pri myVar
    #emit LOAD.I
    #emit STOR.S.pri globalAddress
    
printf("0x%08x"globalAddress);

It prints me : 0x027A40D5
Edit : Logic, 0x027A40D5 in decimal is 41566421... my bad

But the real address is among these :


If there is a difference in my first question, what data is use in the p-code LOAD.I ?
Otherwise : why it doesn't print me the good address ?

I looked the code in y_amx, and I see a semi-constant "AMX_REAL_DATA" initializes with some manipulations.

3. Is it better to use the p-code STACK twice or once in such cases ? :

PHP код:
#include "a_samp"
main()
{
    new 
        
string[] = "Dutheil";
    
#emit ADDR.pri string
    #emit PUSH.pri
    #emit PUSH.C 4
    #emit SYSREQ.C print
    #emit ADDR.pri string
    #emit ADD.C 12
    #emit PUSH.pri
    #emit PUSH 4
    #emit SYSREQ.C print
    #emit STACK 16 // fix the stack

or ? :
PHP код:
#include "a_samp"
main()
{
    new 
        
string[] = "Dutheil";
    
#emit ADDR.pri string
    #emit PUSH.pri
    #emit PUSH.C 4
    #emit SYSREQ.C print
    #emit STACK 8 // fix the stack
    #emit ADDR.pri string
    #emit ADD.C 12
    #emit PUSH.pri
    #emit PUSH 4
    #emit SYSREQ.C print
    #emit STACK 8 // fix the stack

Reply
#15

Quote:
Originally Posted by Dutheil
Посмотреть сообщение
1. My first question is : there is any difference between a "data register" and a "data segment" ?
Well the data register DAT points to the start of the data section / segment
You can use lctrl and sctrl to load / set the registers

Quote:
Originally Posted by Dutheil
Посмотреть сообщение
2. My second question is based on the tests I made.
Because you used load.i, addr.pri already returns the address (FRM + offset)
load.i doesn't use the DAT register, it just loads the address, it usually works except if address is between HEA and STK or the unsigned address is over the memory size
PHP код:
// amx.c
    
case OP_LOAD_I:
        
/* verify address */
        
if (pri>=hea && pri<stk || (ucell)pri>=(ucell)amx->stp)
            
ABORT(amx,AMX_ERR_MEMACCESS);
        
pri=_R(data,pri); // #define _R(base,addr) (* (cell *)((unsigned char*)(base)+(int)(addr)))
        
break; 
No time to look into y_amx but if it says AMX_REAL_DATA it is probably the data section relative to the real memory block of the server

Quote:
Originally Posted by Dutheil
Посмотреть сообщение
3. Is it better to use the p-code STACK twice or once in such cases ?
Well that doesn't matter at all as long as HEA and STK do no collide
Reply
#16

So, I noticed something :
In LOAD.I, the variable data is used, but in LCTRL 1, this is hdr->dat.
They don't store the same value, that's for sure.
Reply
#17

Quote:
Originally Posted by Dutheil
Посмотреть сообщение
So, I noticed something :
In LOAD.I, the variable data is used, but in LCTRL 1, this is hdr->dat.
They don't store the same value, that's for sure.
To correct myself there is a data variable used in load.i (not the DAT register) but it should be equivalent to AMX_REAL_DATA (amx->base (start of amx memory) + hdr->dat (the DAT register))
It shouldn't matter because all opcodes are relative to the data segment
Reply
#18

How can I get the name of any public function into this without index id ?
Example:
PHP код:
#include "a_samp"
forward CustomPublicFunction();
main()
{
    
CustomPublicFunction();
}
public 
CustomPublicFunction()
{
    
// get here the name of CustomPublicFunction

Reply
#19

There's funcidx which returns the index, unless that's what you mean by "without index id"
Reply
#20

Quote:
Originally Posted by Misiur
Посмотреть сообщение
There's funcidx which returns the index, unless that's what you mean by "without index id"
No, what he meant was to get the name of the callback that the function is in.
Код:
#include "a_samp" 

forward CustomPublicFunction(); 

main() 
{ 
    CustomPublicFunction(); 
} 

public CustomPublicFunction() 
{ 
   print(GetCallbackName()); // will print "CustomPublicFunction"
}
EDIT: https://sampforum.blast.hk/showthread.php?tid=353862
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)