1

I have the following code:

.global _launchProgram
_launchProgram:
push bp
mov bp, sp
push cs
mov bx, [bp + 4]
mov cs, bx
mov es, bx
eseg
call #0x0
pop bx
mov cs, bx
pop bp
ret

In this code I am trying to make it to jump to another piece of code and execute it. This code is being called from C as shown below:

launchProgram(segment) //Here segment is an integer which holds the 
                       //memory segment where I have loaded my code

Thus in this function I make cs register to be equal to the segment variable and I use call 0x0 to jump to the start of that segment. But when I run it using:

as86 launchProgram.asm -o launchProgram.o

I get the following error:

00010 000C           E8         0000            call #0x0
***** relocation impossible.................................^

Why am I getting this error?

sarthak
  • 774
  • 1
  • 11
  • 27

2 Answers2

1

Your call #0x0 seems to specify an IP (Instruction Pointer)-relative call in as86 (an offset relative to the next instruction). Was that intentional? as86 might be complaining because it expected a label or a symbol instead, which the linker would be able to resolve (relocate) if needed.

The as86 man page has the following:

The 'near and 'far' do not allow multi-segment programming, all 'far' operations are specified explicitly through the use of the instructions: jmpi, jmpf, callf, retf, etc. The 'Near' operator can be used to force the use of 80386 16bit conditional branches. The 'Dword' and 'word' operators can control the size of operands on far jumps and calls.

The code assembles if I use callf 0x12345678,0x1234 instead, which generates the following instructions:

$ as86 a.asm -o a.o
$ objdump -D -b binary -mi386 -Maddr16,data16,intel a.o
...
3b: 8e cb                   mov    cs,bx
3d: 8e c3                   mov    es,bx
3f: 26 66 9a 78 56 34 12    es call 0x1234:0x12345678
46: 34 12 
48: 5b                      pop    bx
48: 5b                      pop    %bx
...

(-b binary it needed since it's raw code, -mi386 selects the instruction set, and -Maddr16,data16,intel selects Intel syntax and 16-bit code, which seems to be what as86 generates by default.)

The second operand to callf seems to be the segment selector part of the address (having a single operand to callf causes as86 to complain). My x86-fu is too weak to say if the segment override on the call actually makes sense there. You'd want callf #0x0,#0x0 in your code, of course.

If you want to "trick" as86 into generating a relative call that's identical to what you're trying to do (not sure if this makes sense -- you might get random bits from whatever IP happens to be), then you could do the following:

eseg
call zero_offset
zero_offset: pop bx

The output is

  53:   26 e8 00 00             es call 0x57

, where the 00 00 part shows that the offset is 0.

Ulfalizer
  • 4,664
  • 1
  • 21
  • 30
  • Thanks...but I still do not understand how would I jump to the start of the (new) cs segment. I want to jump to cs:0x0 but the as86 is still complaining if I use `callf cs, 0x0`but this `callf cs` seems to be working. In general, how can I make far calls using registers?? – sarthak Mar 15 '15 at 13:22
  • @sarthak: `callf cs` seems to generate an FF instruction (see rows 3 and 4 in http://x86.renejeschke.de/html/file_module_x86_id_26.html), which `objdump` just displays as "(bad)", so using `CS` with those probably isn't legal. I'm not an x86 expert, but try simply doing `callf 0x0,0x0` after `eseg`. Perhaps the segment override prefix will override the 0x0 segment selector in the instruction. – Ulfalizer Mar 15 '15 at 13:39
  • Do you really need to calculate the segment address at runtime btw? Otherwise you could probably just put it directly into the `callf` (as the second operand). – Ulfalizer Mar 15 '15 at 13:40
  • In what environment are you going to run this code by the way? – Ulfalizer Mar 15 '15 at 13:42
  • No I just need to jump to the start of the segment and I am using qemu for running – sarthak Mar 15 '15 at 13:43
  • Are you executing in real mode? – Ulfalizer Mar 15 '15 at 13:51
  • If you know the address of the segment, you should be able to do `callf ,0x0`, where the called address will be `16* + 0`. This will automatically set `CS` too, and push it to the stack. The call should be matched by a `retf`, which will restore `CS` from the stack as well. – Ulfalizer Mar 15 '15 at 14:01
  • If you don't know the address at compile-time, it seems you can use `callf` and a memory operand (address where the address to call is stored) for the address as well (using whatever syntax as86 has for variables). That will also set `CS`. – Ulfalizer Mar 15 '15 at 14:06
  • Sorry, that should have been `callf 0x0,`. – Ulfalizer Mar 15 '15 at 14:10
0

I don't think setting cs before call is a good idea, the called procedure don't know how to return. You have to execute a far call, call segment:offset. This will push the value of the ip and cs register on stack for return. For your code something like: call cs:0x00 Also is esag a x86 instruction?

Se this link

fhtuft
  • 966
  • 5
  • 8
  • I think you are talking about the nasm syntax. With as86 you cannot use the syntax like `call cs:0x0` instead you have to split this over two commands like I have done so eseg followed by call 0x0 should be `call es:0x0` – sarthak Mar 15 '15 at 10:28