jaywalker
jaywalker

Reputation: 1146

X86 - Function is undefined

I am new at assembly and am trying to wrap my head around function calling in x86. I am provided the following code:

read_integer:

push ebp        
mov ebp, esp    

sub esp, 8 
mov dword [ebp-4], '0' 
mov dword [ebp-8], 0 

push ebx        
push ecx        
push edx        

.read_loop:
mov eax, 10     
mul dword [ebp-8] 
add eax, [ebp-4] 
sub eax, '0'    
mov [ebp-8], eax

mov eax, 3 
mov ebx, 0 
lea ecx, [ebp-4]
mov edx, 1 
int 0x80   

cmp dword [ebp-4], 10 
jne .read_loop  

ret 

I can call the read_integer function using call read_integer. However when I try to do the same for .read_loop using call .read_loop I get the error :

.read_loop is not defined.

What am I doing wrong?

Upvotes: 0

Views: 227

Answers (2)

Michael
Michael

Reputation: 58507

.read_loop is not meant to be called. It's a label local to read_integer marking the start of a loop.

If you take a look at the end of read_integer you see:

cmp dword [ebp-4], 10 
jne .read_loop  

Which will jump back to .read_loop as long as [ebp-4] doesn't equal 10. This is similar to if you had written the following in C:

do {
  // Whatever
} while (*(ebp-4) != 10);

To be able to jump somewhere you need to specify where to jump. Hardcoding the location would be really inconvenient, so you use labels and let the assembler figure out which address that label corresponds to.
But you might only want some labels to be visible within a certain scope (e.g. within read_integer). Perhaps you want to be able to use that same label name in some other function, or perhaps you just want to make it clear to whoever is reading the code that the label is local to the function. So some assemblers provide syntax for making a label local, as described by @Jean-FrançoisFabre.

Some assemblers go one step further and allow "anonymous" labels, such as:

1:
    jmp 2f   ; f for forwards
    ; Whatever
    jmp 1b   ; b for backwards
2:

Or:

-:
    jp +  ; this is Z80 assembly, so jp isn't a typo
    ; Whatever
    jp -
+:

Upvotes: 1

Jean-François Fabre
Jean-François Fabre

Reputation: 140287

the dot in .read_loop means that the label is local.

It is only visible inside the same "scope" made of 2 global labels.

global_label_1:
    code
.local_label
    code
    jne .local_label  <=== no ambiguity, the label is locally defined, jumps to the label above
global_label_2:
   code
.local_label    <=== same name but different scope
   code

It's useful because the code can be copied/pasted several times in different procedures without naming conflicts.

In your case, removing the leading dot will solved it: you want it global.

read_loop:
mov eax, 10
...
call read_loop    

EDIT: some assemblers also allow to access the inner label like this: call read_integer.read_loop

Upvotes: 1

Related Questions