News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Tricky problem with CodeAlign macro

Started by jj2007, February 16, 2010, 11:25:14 PM

Previous topic - Next topic

jj2007

Inspired by DednDave, I am trying to implement a CodeAlign macro:
QuoteCodeAlign MACRO ct
  int 3
MyLabel LABEL NEAR
  oml = MyLabel
  divl = oml         ; transfer, no error
;  tmp$ CATSTR <MyDivl=>, %oml   ; error, oml undefined
;  % echo tmp$
;  divl = divl mod ct         ; error, divl undefined
  mov eax, offset MyLabel      ; works fine
  mov eax, THIS NEAR      ; works fine, loads EIP
ENDM
[/b]

Apparently, oml = MyLabel does create a result, an offset of 16h relative to the start of the code segment. That would be a basis for calculating the necessary number of nops. However, the variable oml, while containing the right value as shown below, cannot be used as a normal integer variable. Any idea why??

00000015  CC      1   int 3
00000016      1 MyLabel LABEL NEAR
= 00000016      1   oml = MyLabel
= 00000016      1   divl = oml ; transfer, no error
     1 ;  tmp$ CATSTR <MyDivl=>, %oml ; error, oml undefined
     1 ;  % echo tmp$
     1 ;  divl = divl mod ct ; error, divl undefined
00000016  B8 00000016 R     1   mov eax, offset MyLabel ; works fine
0000001B  B8 0000001B R     1   mov eax, THIS NEAR ; works fine, loads EIP



Full code:
.nolist
include \masm32\include\masm32rt.inc
.listall

CodeAlign MACRO ct
  int 3
MyLabel LABEL NEAR
  oml = MyLabel
  divl = oml ; transfer, no error
;  tmp$ CATSTR <MyDivl=>, %oml ; error, oml undefined
;  % echo tmp$
;  divl = divl mod ct ; error, divl undefined
  mov eax, offset MyLabel ; works fine
  mov eax, THIS NEAR ; works fine, loads EIP
ENDM

.code
start:
print "Masm32 is easy!", 13, 10
nop
CodeAlign 4
.Repeat
inc eax
.Until eax!=123
; inkey "Press any key"
invoke ExitProcess, 0
; .err

end start

qWord

Do not ask my why, but before using labels for arithmetic calculations you have to form a differenc (or sum) of two:
(OFFSET B - OFFSET A)

if label B is at position 0 (in segment) you've get the current relative offset in segment.

I've upload an macro in this thread



FPU in a trice: SmplMath
It's that simple!

jj2007

Thanks, qWord. In the meantime I discovered that odd behaviour myself - $-start works fine:

.nolist
include \masm32\include\masm32rt.inc

CodeAlign MACRO ct
LOCAL nops
  nops = ct-($-start) mod ct ; we take the start: label as reference
  if nops ne ct
REPEAT nops
nop ; for testing, we just insert nops
ENDM
  endif
  tmp$ CATSTR <MyNops=>, %nops ; watch in output window
  % echo tmp$
ENDM

.code
start:
REPEAT 10
    nop
ENDM
CodeAlign 16
; nop ; use for testing
mov eax, $ ; same as THIS NEAR
and eax, 15
print str$(eax), ": should be zero", 13, 10
REPEAT 6
    nop
ENDM
CodeAlign 16
mov eax, THIS NEAR ; same as $
and eax, 15
inkey str$(eax), ": should be zero", 13, 10
exit
end start


The code assembles, and the first alignment produces the desired result, but the second one doesn't. Probably something really stupid, but right now I am too tired... good night everybody :8)

dedndave

get a good nights sleep, Jochen
this one has me baffled - lol
but, you and qWord will make it work   :8)

jj2007

I am making progress, and there is good and bad news. First, the good news:
It works perfectly, and it is so simple:
QuoteCodeAlign MACRO ct
LOCAL nops, diff
  diff = $-start
  nops = ct-($-start) mod ct   ; we take the start: label as reference
  if nops ne ct
   REPEAT nops
      nop               ; for testing, we just insert nops
   ENDM
  endif
  tmp$ CATSTR <MyNops=>, %nops, <, d=>, %diff   ; watch in output window
  % echo tmp$
ENDM
[/b]

Now the bad news: It works only for JWasm, because ML.exe has a featureTM that occasionally adds several bytes to the location counter, in a not so predictable way. If the fathers of this design are still around, they should show up now, please :8)

dedndave

ummmmmm - JWam probably doesn't have the problem, to begin with
if it does, we can get Japheth to fix it   :bg

nice macro, though   :U

but, i think qWord is on to something
if you combine his macro with the assemblers ALIGN, you might have something that works in all cases
for example:
a secondary routine in a library is one place where he says it won't work
but, if you use a non-executed ALIGN directive at the beginning of that routine,
you might be able to make the macro method work because it has a known reference point - i dunno
i.e., use an ALIGNed label as a reference point instead of Start:

jj2007

Quote from: dedndave on February 17, 2010, 09:57:20 AM
ummmmmm - JWam probably doesn't have the problem, to begin with
if it does, we can get Japheth to fix it   :bg
JWasm works perfectly, it's only ml that has a problem

Quote
i.e., use an ALIGNed label as a reference point instead of Start:

start: is aligned, unless you have put yourself code before the label. In that case,
align 16
start:

will provide you again with a perfectly aligned reference point.
The issue is not the reference, it's that ml arbitrarily calculates the program counter in a wrong way. Have a look at the testbed in Olly...

dedndave

QuoteQuote from: dedndave on Today at 01:57:20 AM
ummmmmm - JWam probably doesn't have the problem, to begin with
if it does, we can get Japheth to fix it   BigGrin
JWasm works perfectly, it's only ml that has a problem

my point was that JWasm doesn't need the CodeAlign macro   :red

jj2007

Quote from: dedndave on February 17, 2010, 10:15:10 AM
my point was that JWasm doesn't need the CodeAlign macro   :red

That's true, good point :bg

dedndave


00401032 B832104000              mov eax, 00401032
00401037 BA37104000              mov edx, 00401037
0040103C 83EA05                  sub edx, 005               ;5 accounts for "mov edx,immed32"
0040103F 3BC2                    cmp eax, edx

shouldn't that be sub edx,10 ?
mov eax,immed32 = 5 bytes
mov edx,immed32 = 5 bytes
total = 10 bytes

EDIT - btw - i like the trick with inkey   :bg

jj2007

Quote from: dedndave on February 17, 2010, 10:39:18 AM
shouldn't that be sub edx,10 ?

No, it just tests what would have been the result if edx had been used in the same position as eax, so it's 5 bytes.
mov eax, THIS NEAR ; loads... what?
mov edx, $ ; loads EIP
sub edx, 5 ; account for mov edx, $

dedndave


00401032 B832104000              mov eax, 00401032
00401037 BA37104000              mov edx, 00401037
0040103C 83EA05                  sub edx, 005
0040103F 3BC2                    cmp eax, edx
00401041 7414                    je 00401057
00401043 6827304000              push 00403027 ;(StringData)"$ and THIS NEAR seem to be different"
00401048 E8BB000000              call 00401108
0040104D 684C304000              push 0040304C ;(StringData)" <cr><lf>"
00401052 E8B1000000              call 00401108

;this is the macro expansion - it does not appear to have generated the correct number of NOP's

00401057 90                      nop
00401058 90                      nop
00401059 90                      nop
0040105A 90                      nop
0040105B 90                      nop
0040105C 90                      nop

0040105D B85D104000              mov eax, 0040105D
00401062 83E007                  and eax, 007
00401065 684F304000              push 0040304F
0040106A 50                      push eax
0040106B E830000000              call 004010A0
00401070 684F304000              push 0040304F
00401075 E88E000000              call 00401108
0040107A 6864304000              push 00403064 ;(StringData)": should be zero <cr><lf>"
0040107F E884000000              call 00401108
00401084 E8B7000000              call 00401140

it should only generate 1 NOP
it generated 6
6-1 = 5

jj2007

Quote from: dedndave on February 17, 2010, 11:25:09 AM
;this is the macro expansion - it does not appear to have generated the correct number of NOP's

Yes, for ML.exe it fails because it assumes a much higher offset, 131 instead of 88 bytes. Jwasm handles it correctly...

dedndave

i see that one nop is put in there by you (not sure why)
so - there should be only one nop
i am still not understanding the problem completely, other than it is generating the wrong number of nops
it seems to be something along the line of - when the macro gets expanded, masm is assigning a different PC value than we expect

EDIT - i seem to recall having seen this problem before
but i may have a way around it - let me try it

dedndave

well - my novice macro skills are a major limitation   :bg
but, maybe my results will give you a clue...

here is the macro i tried

CodeAlign MACRO ct
LOCAL nearlabel,nops
nearlabel:
  nops = ct-((nearlabel-start) and (ct-1))
echo ct
echo start
echo nearlabel
echo nops
  if nops
   REPEAT nops
      nop               ; for testing, we just insert nops
   ENDM
  endif
ENDM

here is the assembly-time output

8
start
??0020
??0021

i can't get it to show me the address of "start"
it's probably because start has not been defined when the macro is

the hope was to figure out how masm PC behaves when the macro is expanded and compensate for it with a math expression