Author Topic: Disassembling NWScript Bytecode  (Read 3617 times)

Legacy_DrMcCoy

  • Newbie
  • *
  • Posts: 33
  • Karma: +0/-0
Disassembling NWScript Bytecode
« on: January 15, 2016, 07:34:30 pm »


               

Over at xoreos.org, I wrote a blog post about Disassembling NWScript Bytecode. This is basically a progress report of me writing an NWScript disassembler, which might be extended into a full-fledged decompiler. It might be of interest to people here.


 


This is not just for NWN, but for the whole range of NWScript using games. Namely:


  • Neverwinter Nights

  • Neverwinter Nights 2

  • Knights of the Old Republic

  • Knights of the Old Republic II

  • Jade Empire

  • The Witcher

  • Dragon Age: Origins

  • Dragon Age II

Specifically, this might be, at least as far as I know, the first time there has been done anything with the scripts of the Dragon Age games. They each add two new script opcodes, to handle arrays and references, and I hadn't found any prior documentation or discussion about these. They were pretty easily to figure out by observing the stack of scripts that use them.


 


I don't want to spam all these forums, so I'll keep it contained here.



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Disassembling NWScript Bytecode
« Reply #1 on: January 15, 2016, 09:14:34 pm »


               

That's a nice write-up. Good stuff!


 


I don't believe the first one is a bug though.  In C, at least, I believe shadowing a higher scoped variable takes effect from the moment of declaration. So as soon as "int nSkill" happens you no longer have visibility to the parameter. That seems like the nwn compiler did just that.  That's a pretty easy one to work around anyway as shadowing variables like that is generally not great programming practice '<img'>


 


Gcc won't let me compile something which shadows a parameter but making "int x" a global variable and doing something like


int x = x + 1; in main produces the same thing. It adds 1 to the local stack variable. It does not deference the global x and then add 1 to 


that.


 


(your blog does not take comments or I would have left this there ...)


 


Cheers meaglyn


               
               

               
            

Legacy_DrMcCoy

  • Newbie
  • *
  • Posts: 33
  • Karma: +0/-0
Disassembling NWScript Bytecode
« Reply #2 on: January 15, 2016, 09:45:02 pm »


               

In C, at least, I believe shadowing a higher scoped variable takes effect from the moment of declaration.


Okay, I did not know that. '<img'>
 

That's a pretty easy one to work around anyway as shadowing variables like that is generally not great programming practice '<img'>


Yeah, I usually have -Wshadow enabled (and -Werror to boot), since I hate having those in my code.
 

something like
int x = x + 1; in main produces the same thing. It adds 1 to the local stack variable. It does not deference the global x and then add 1 to 
that.


In C (and C++), that direct case from the script, a local variable with the same name as a parameter, is not allowed, as far as I'm aware.

I would have thought, though, that a local variable would shadow a global (or a class member variable in C++) after the initialization, but it seems I was wrong. I learned something new today, then, thanks. '<img'>

Googling this, I found a quote from the C standard in this Stack Overflow reply. Yup, "immediately after its complete declarator (Clause 8) and before its initializer".

So not a bug in the compiler, except for maybe eating this script without a least issuing a warning. No idea what the original BioWare compiler did there, of course. The OpenKnights' nwnnsscomp does warn there, at least.
               
               

               
            

Legacy_DrMcCoy

  • Newbie
  • *
  • Posts: 33
  • Karma: +0/-0
Disassembling NWScript Bytecode
« Reply #3 on: February 01, 2016, 09:14:37 pm »


               

In case anybody wants to try this out, but couldn't compile xoreos-tools from sources: xoreos and xoreos-tools 0.0.4 has been released, which includes binaries of ncsdis for GNU/Linux, Windows and Mac OS X. It is still a command line tool, though, without a GUI.



               
               

               
            

Legacy_DrMcCoy

  • Newbie
  • *
  • Posts: 33
  • Karma: +0/-0
Disassembling NWScript Bytecode
« Reply #4 on: February 10, 2016, 12:45:14 am »


               

Oh, and while it's not really on-topic for this thread, I did an interview with "The Linux Gamer" about xoreos:

https://www.youtube....h?v=kDEmpUJviRM

 

It's more a general overview of what xoreos is, the current state, etc. In my badly accented, mumbling English. '<img'>



               
               

               
            

Legacy_meaglyn

  • Hero Member
  • *****
  • Posts: 1451
  • Karma: +0/-0
Disassembling NWScript Bytecode
« Reply #5 on: February 10, 2016, 12:52:08 am »


               

Nice! I watched it the other day when you posted it in the chat.


 


You look nothing like Dr McCoy, DrMcCoy '<img'>


 


BTW, where did you get the compiled code for the short-circuiting bug you were talking about? I can't reproduce that. My stock NWN compiler does the right thing there with an unconditional JMP instruction.  Maybe you were using an unpatched NWN install?


               
               

               
            

Legacy_DrMcCoy

  • Newbie
  • *
  • Posts: 33
  • Karma: +0/-0
Disassembling NWScript Bytecode
« Reply #6 on: February 10, 2016, 01:14:34 am »


               

You look nothing like Dr McCoy, DrMcCoy '<img'>




Pffft, I look like him on the inside '<img'>

 



BTW, where did you get the compiled code for the short-circuiting bug you were talking about?




In the NWM files that come with NWN. For example, "m0q01a01bimsck6" in Prelude.nwm. This is with the Diamond Edition from GOG, patched to 1.69 (and with the critical rebuild thing applied, and the Linux client).


But yes, my toolset is an older version. In fact, it's still the old, old German one I used from way back when. I never really used it all that much, because it likes to crash in Wine. '<img'>


Good to know that they've patched the issue in the NWN compiler, then. '<img'>


These buggy scripts are also there in KotOR (and KotOR2), btw. It is fixed in Jade Empire, so I guess they must have fixed it some time between 2003 and 2005, and also in an NWN patch then? Looking at the NWNv169.txt (which goes back til 1.18) patch notes, I can't find anything related to this, though.



               
               

               


                     Modifié par DrMcCoy, 10 février 2016 - 12:55 .