adimetrius / Herschel

Ground work for Component Pascal 64-bit compiler
BSD 2-Clause "Simplified" License
21 stars 1 forks source link

Elf: wrong offset to global variables in code #5

Closed X547 closed 3 years ago

X547 commented 3 years ago

This is https://github.com/adimetrius/Herschel/commit/cc4bead0534a6824bca446a8d906e7952b0d8ffd.

In Albert example there are VAR s: ARRAY 64 OF SHORTCHAR; global variable and code s := "but not simpler"; that assigns value to it. But offset to global variable in code is wrong and it is outside of any ELF segments.

ElfDecoder:

Kind    File Offset File Size   Virt. Adr   Phys. Adr   Mem. Size   Align   Flags
load    00001000    00000088    00405000    00405000    00000088    00001000    write, read
load    00002000    00000058    00406000    00406000    00000058    00001000    exec, read
load    00003000    00000090    00407000    00407000    000000D0    00001000    write, read
load    00004000    000002D8    00408000    00408000    000002D8    00001000    write, read

Reloc (Addend) 
Address Old Kind    Value   Addend
00405080    00000000    abs64   exit    0
00405078    00000000    abs64   puts    0

Segment 0 (00405000, 00000088, data) 
00405000  17 82 06 FC D1 00 24 24 00 FD 10 80 70 40 00 00  ......$$....p@..
00405010  73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  s...............
00405020  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00405030  00 62 75 74 20 6E 6F 74 20 73 69 6D 70 6C 65 72  .but not simpler
00405040  00 41 6C 62 65 72 74 20 61 73 6B 65 64 20 74 6F  .Albert asked to
00405050  20 6D 61 6B 65 20 69 74 20 61 73 20 73 69 6D 70   make it as simp
00405060  6C 65 20 61 73 20 70 6F 73 73 69 62 6C 65 2C 00  le as possible,.
00405070  00 00 00 00 00 00 00 00                          ........        
  __imp_puts        
00405070                          00 00 00 00 00 00 00 00          ........
  __imp_exit        
00405080  00 00 00 00 00 00 00 00                          ........        

Segment 1 (00406000, 00000058, code) 
  $Start        
00406000    55  push  RBP
00406001    48|8B EC    mov  RBP, RSP
00406004    57  push  RDI
00406005    56  push  RSI
(* Libc.puts("Albert asked to make it as simple as possible,"); *)
00406006    48|8D 05 34 F0 FF FF    lea  RAX, [$00405041]
0040600D    48|8B F8    mov  RDI, RAX
00406010    FF 15 62 F0 FF FF   call  [__imp_puts]
00406016    90  nop  
(* s := "but not simpler"; *)
00406017    48|8D 35 13 F0 FF FF    lea  RSI, [$00405031]
0040601E    48|8D 3D 9B FF FF FF    lea  RDI, [$00405FC0] (* Albert.s global variable *)
00406025    B9 04 00 00 00  mov  ecx, 4
0040602A    F3  rep  
0040602B    A5  movsd  
0040602C    90  nop  
(* Libc.puts(s); *)
0040602D    48|8D 05 8C FF FF FF    lea  RAX, [$00405FC0]
00406034    48|8B F8    mov  RDI, RAX
00406037    FF 15 3B F0 FF FF   call  [__imp_puts]
0040603D    90  nop  
(* Libc.exit(28) *)
0040603E    BF 1C 00 00 00  mov  edi, 28
00406043    FF 15 37 F0 FF FF   call  [__imp_exit]
00406049    90  nop  
0040604A    5E  pop  RSI
0040604B    5F  pop  RDI
0040604C    48|8B E5    mov  RSP, RBP
0040604F    5D  pop  RBP
00406050    C3  ret  
00406051    90  nop  
00406052    90  nop  
00406053    90  nop  
00406054    90  nop  
00406055    90  nop  
00406056    90  nop  
00406057    90  nop  
X547 commented 3 years ago

Global variables can be allocated in same segment with read-write data by specifying memory size larger then file size. Part that is not covered with file data will be filled with zeroes. PE executables also supports this feature.

X547 commented 3 years ago

Global variables seems to be allocated in segment 2 (memory size 0D0H - file size 90H = 64 that match size of global variables). But offsets in code points at wrong place.

adimetrius commented 3 years ago

Great finding!

The proposed fix is to HrE:

PROCEDURE ApplyToBkmrks (IN b: Y.Bkmrks; **base**: INTEGER);
    VAR i: INTEGER;
BEGIN i := 0; WHILE b[i].offset # 0 DO FixupCode(b[i].last, **base + b[i].offset**); INC(i) END
END ApplyToBkmrks;

PROCEDURE ApplyGlobVarFixups (o: Y.GlobVar; **base**: INTEGER);
    VAR more: Y.BkmrksPtr;
BEGIN
    FixupCode(o.last, **base**);
    ApplyToBkmrks(o.bkmrks, **base**); more := o.moreBkmrks;
    WHILE more # NIL DO ApplyToBkmrks(more.bkmrks, **base**); more := more.more END
END ApplyGlobVarFixups;

PROCEDURE ApplyRIPFixupsToList (o: T.Symbol);
    VAR next: T.Symbol; base: INTEGER;
BEGIN
    WHILE o # NIL DO
        WITH o: T.Object DO
            IF T.used IN o.flags THEN 
                WITH 
                | o: Y.GlobVar DO 
                    IF o.imno = 0 THEN **base := varsWRTcode**  (* domestic var *)
                    ELSE **base := proxiesWRTcode** (* imported var *)
                    END;
                    ApplyGlobVarFixups(o, **base**)

See if it works, please

adimetrius commented 3 years ago

It didn't bolden the base, bummer

X547 commented 3 years ago

Fixed In HrBinder.