# C und Assembler mixen Linker Problem



## üäpöol (7. März 2012)

Hi,

ich hoffe es macht nichts, dass ich im Moment zwei Threads hier offen habe.
Die beiden Probleme sind miteinander verwandt.

Ich weiß nicht, ob mein Vorhaben überhaupt funktionieren kann.
Ich programmiere zurzeit ein kleines Betriebssystem. Ich habe eine kernel.asm mit der ich meinen C Kernel aufrufe. 
Nun kann ja die Sprache C an sich ziemlich wenig, was bedeutet, dass ich wiederum Assembler brauche. Ich aber kein Freund von inline-assembling und wollte deshalb die Funktionen in externe Dateien speichern, die ich assembliere und dann mit linke. Im Prinzip sieht das so aus:
<linke> kernel.bin kernelASM.elf kernelC.elf read.elf

Die kernel.asm ruft nur den C Kernel auf, sprich

```
; ...
extern main
call main
; ...
```

Die kernel.c sieht so aus:

```
extern int read();

int main() {
    read();
    return 0;
}
```

Die read.asm ist

```
global read

read:
     mov ah, 0x0
     int 0x16
     ret
```

Das Ergebnis des ganzen ist, dass read() übersprungen wird und gleich rebootet wird. Also habe ich die kernel.bin mal disassembliert und erkenne, dass nicht zu "read" gesprungen wird, sondern eine Adresse davor und das ist das "ret" des C Codes, was im Endeffekt bedeutet, dass read() übersprungen wird.
Also habe ich versuch, so zu linken:
<linke> kernel.bin kernelASM.elf read.elf kernelC.elf
was aber darauf hinaus läuft, dass zwar auf die richtige "read" Stelle gesprungen, aber nicht zu "main" gesprungen wird. Die Folge ist, dass das OS hängt.
Ich hoffe ihr versteht das Problem.
Weil ich vermute, dass es am Linker liegt (ld) poste ich hier mal das Linkerscript:

```
OUTPUT_FORMAT("binary")
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
```
Danke im Voraus und für's bis hierher lesen 

EDIT1:  
Assembler ist NASM, C Compiler ist gcc und Linker ist ld.

EDIT2:
Hier das Ergbnis des Disassemblers für beide Fälle:

kernelC.elf vor read.elf

```
00000000  E80700            call word 0xa
00000003  0000              add [bx+si],al
00000005  EA0000FFFF        jmp word 0xffff:0x0
0000000A  0000              add [bx+si],al
0000000C  8D4C24            lea cx,[si+0x24]
0000000F  0483              add al,0x83
00000011  E4F0              in al,0xf0
00000013  FF71FC            push word [bx+di-0x4]
00000016  55                push bp
00000017  89E5              mov bp,sp
00000019  51                push cx
0000001A  83EC04            sub sp,byte +0x4
0000001D  E80E00            call word 0x2e
00000020  0000              add [bx+si],al
00000022  B80000            mov ax,0x0
00000025  0000              add [bx+si],al
00000027  83C404            add sp,byte +0x4
0000002A  59                pop cx
0000002B  5D                pop bp
0000002C  8D61FC            lea sp,[bx+di-0x4]
0000002F  C3                ret
00000030  B400              mov ah,0x0
00000032  CD16              int 0x16
00000034  B400              mov ah,0x0
00000036  C3                ret
00000037  0000              add [bx+si],al
00000039  0000              add [bx+si],al
0000003B  0000              add [bx+si],al
; Und noch mehr "NUL"s -> add [bx+si],al
```

read.elf vor kernelC.elf

```
00000000  E81300            call word 0x16
00000003  0000              add [bx+si],al
00000005  EA0000FFFF        jmp word 0xffff:0x0
0000000A  0000              add [bx+si],al
0000000C  0000              add [bx+si],al
0000000E  0000              add [bx+si],al
00000010  B400              mov ah,0x0
00000012  CD16              int 0x16
00000014  B400              mov ah,0x0
00000016  C3                ret
00000017  008D4C24          add [di+0x244c],cl
0000001B  0483              add al,0x83
0000001D  E4F0              in al,0xf0
0000001F  FF71FC            push word [bx+di-0x4]
00000022  55                push bp
00000023  89E5              mov bp,sp
00000025  51                push cx
00000026  83EC04            sub sp,byte +0x4
00000029  E8E2FF            call word 0xe
0000002C  FF                db 0xff
0000002D  FF                db 0xff
0000002E  B80000            mov ax,0x0
00000031  0000              add [bx+si],al
00000033  83C404            add sp,byte +0x4
00000036  59                pop cx
00000037  5D                pop bp
00000038  8D61FC            lea sp,[bx+di-0x4]
0000003B  C3                ret
0000003C  0000              add [bx+si],al
0000003E  0000              add [bx+si],al
00000040  0000              add [bx+si],al
; Und noch mehr "NUL"s -> add [bx+si],al
```

EDIT3:
Kompletter Code:

kernel.asm

```
global start
start:	
	extern main
	call main
	
global restart
restart:
	db 0Eah
	dw 0000h
	dw 0FFFFh
```

kernel.c

```
extern void read();

int main() {
	read();
	return 0;
}
```

read.asm

```
global read
read:
	mov ah, 0x0
	int 0x16
	mov ah, 0
	ret
```

Ich glaube, dass war's erstmal.


----------



## üäpöol (10. März 2012)

Ich glaube ich habe das Problem gerade selbst gelöst.
Ich darf einfach nach dem "call main" nichts mehr schreiben.
Jetzt funktioniert's. 
Vielleicht hat ja noch jemand eine Erklärung parat.


----------



## Linuxfriend (11. März 2012)

ja. Du kannst du BIOS ints im Protected mode nicht verwenden.
Das Rebooten ist die Folge eines Tripple-Faults. Richt dir erst mal nen Exceptionhandler ein.
Ich schreibe dir demnächst mal ne PM.
LG
Linux best friend


----------

