aarch64: Fix -run.
This adds some more support for properly transfering some offsets over the different stages of a relocations life. Still not at all psABI compliant and DSOs can't yet be generated. But it runs the testsuite in qemu-arm64.
This commit is contained in:
		
							parent
							
								
									b14ef0e24b
								
							
						
					
					
						commit
						6d055312a2
					
				
					 2 changed files with 54 additions and 10 deletions
				
			
		
							
								
								
									
										62
									
								
								tccelf.c
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								tccelf.c
									
										
									
									
									
								
							| 
						 | 
					@ -451,7 +451,7 @@ ST_FUNC void relocate_syms(TCCState *s1, int do_resolve)
 | 
				
			||||||
                if (addr) {
 | 
					                if (addr) {
 | 
				
			||||||
                    sym->st_value = (addr_t)addr;
 | 
					                    sym->st_value = (addr_t)addr;
 | 
				
			||||||
#ifdef DEBUG_RELOC
 | 
					#ifdef DEBUG_RELOC
 | 
				
			||||||
		    printf ("relocate_sym: %s -> 0x%x\n", name, sym->st_value);
 | 
							    printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
                    goto found;
 | 
					                    goto found;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -797,8 +797,21 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case R_AARCH64_JUMP26:
 | 
					        case R_AARCH64_JUMP26:
 | 
				
			||||||
        case R_AARCH64_CALL26:
 | 
					        case R_AARCH64_CALL26:
 | 
				
			||||||
 | 
						    /* This check must match the one in build_got_entries, testing
 | 
				
			||||||
 | 
						       if we really need a PLT slot.  */
 | 
				
			||||||
 | 
						    if (sym->st_shndx == SHN_UNDEF)
 | 
				
			||||||
 | 
						        /* We've put the PLT slot offset into r_addend when generating
 | 
				
			||||||
 | 
							   it, and that's what we must use as relocation value (adjusted
 | 
				
			||||||
 | 
							   by section offset of course).  */
 | 
				
			||||||
 | 
							val = s1->plt->sh_addr + rel->r_addend;
 | 
				
			||||||
 | 
					#ifdef DEBUG_RELOC
 | 
				
			||||||
 | 
						    printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr, val,
 | 
				
			||||||
 | 
							    (char *) symtab_section->link->data + sym->st_name);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
            if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
 | 
					            if (((val - addr) + ((uint64_t)1 << 27)) & ~(uint64_t)0xffffffc)
 | 
				
			||||||
                tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed");
 | 
						      {
 | 
				
			||||||
 | 
					                tcc_error("R_AARCH64_(JUMP|CALL)26 relocation failed (val=%lx, addr=%lx)", addr, val);
 | 
				
			||||||
 | 
						      }
 | 
				
			||||||
            *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 |
 | 
					            *(uint32_t *)ptr = 0x14000000 | (type == R_AARCH64_CALL26) << 31 |
 | 
				
			||||||
                ((val - addr) >> 2 & 0x3ffffff);
 | 
					                ((val - addr) >> 2 & 0x3ffffff);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
| 
						 | 
					@ -818,7 +831,17 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s)
 | 
				
			||||||
                 & 0xff8) << 7;
 | 
					                 & 0xff8) << 7;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case R_AARCH64_COPY:
 | 
					        case R_AARCH64_COPY:
 | 
				
			||||||
          break;
 | 
					            break;
 | 
				
			||||||
 | 
					        case R_AARCH64_GLOB_DAT:
 | 
				
			||||||
 | 
					        case R_AARCH64_JUMP_SLOT:
 | 
				
			||||||
 | 
					            /* They don't need addend */
 | 
				
			||||||
 | 
					#ifdef DEBUG_RELOC
 | 
				
			||||||
 | 
						    printf ("reloc %d @ 0x%lx: val=0x%lx name=%s\n", type, addr,
 | 
				
			||||||
 | 
							    val - rel->r_addend,
 | 
				
			||||||
 | 
							    (char *) symtab_section->link->data + sym->st_name);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					            *(addr_t *)ptr = val - rel->r_addend;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
 | 
					            fprintf(stderr, "FIXME: handle reloc type %x at %x [%p] to %x\n",
 | 
				
			||||||
                    type, (unsigned)addr, ptr, (unsigned)val);
 | 
					                    type, (unsigned)addr, ptr, (unsigned)val);
 | 
				
			||||||
| 
						 | 
					@ -1211,6 +1234,7 @@ static unsigned long put_got_entry(TCCState *s1,
 | 
				
			||||||
            plt = s1->plt;
 | 
					            plt = s1->plt;
 | 
				
			||||||
            if (plt->data_offset == 0)
 | 
					            if (plt->data_offset == 0)
 | 
				
			||||||
                section_ptr_add(plt, 32);
 | 
					                section_ptr_add(plt, 32);
 | 
				
			||||||
 | 
					            symattr->plt_offset = plt->data_offset;
 | 
				
			||||||
            p = section_ptr_add(plt, 16);
 | 
					            p = section_ptr_add(plt, 16);
 | 
				
			||||||
            put32(p, s1->got->data_offset);
 | 
					            put32(p, s1->got->data_offset);
 | 
				
			||||||
            put32(p + 4, (uint64_t)s1->got->data_offset >> 32);
 | 
					            put32(p + 4, (uint64_t)s1->got->data_offset >> 32);
 | 
				
			||||||
| 
						 | 
					@ -1372,6 +1396,23 @@ ST_FUNC void build_got_entries(TCCState *s1)
 | 
				
			||||||
                put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
 | 
					                put_got_entry(s1, reloc_type, sym->st_size, sym->st_info,
 | 
				
			||||||
                              sym_index);
 | 
					                              sym_index);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    case R_AARCH64_JUMP26:
 | 
				
			||||||
 | 
						    case R_AARCH64_CALL26:
 | 
				
			||||||
 | 
					                if (!s1->got)
 | 
				
			||||||
 | 
					                    build_got(s1);
 | 
				
			||||||
 | 
					                sym_index = ELFW(R_SYM)(rel->r_info);
 | 
				
			||||||
 | 
					                sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
 | 
				
			||||||
 | 
					                if (sym->st_shndx == SHN_UNDEF) {
 | 
				
			||||||
 | 
							    unsigned long ofs;
 | 
				
			||||||
 | 
							    reloc_type = R_AARCH64_JUMP_SLOT;
 | 
				
			||||||
 | 
					                    ofs = put_got_entry(s1, reloc_type, sym->st_size,
 | 
				
			||||||
 | 
										sym->st_info, sym_index);
 | 
				
			||||||
 | 
							    /* We store the place of the generated PLT slot
 | 
				
			||||||
 | 
							       in our addend.  */
 | 
				
			||||||
 | 
							    rel->r_addend += ofs;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
#elif defined(TCC_TARGET_C67)
 | 
					#elif defined(TCC_TARGET_C67)
 | 
				
			||||||
            case R_C60_GOT32:
 | 
					            case R_C60_GOT32:
 | 
				
			||||||
            case R_C60_GOTOFF:
 | 
					            case R_C60_GOTOFF:
 | 
				
			||||||
| 
						 | 
					@ -1895,8 +1936,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
 | 
				
			||||||
        uint64_t plt = s1->plt->sh_addr;
 | 
					        uint64_t plt = s1->plt->sh_addr;
 | 
				
			||||||
        uint64_t got = s1->got->sh_addr;
 | 
					        uint64_t got = s1->got->sh_addr;
 | 
				
			||||||
        uint64_t off = (got >> 12) - (plt >> 12);
 | 
					        uint64_t off = (got >> 12) - (plt >> 12);
 | 
				
			||||||
        if ((off + ((uint64_t)1 << 20)) >> 21)
 | 
					        if ((off + ((uint32_t)1 << 20)) >> 21)
 | 
				
			||||||
            tcc_error("Failed relocating PLT");
 | 
					            tcc_error("Failed relocating PLT (off=0x%lx, got=0x%lx, plt=0x%lx)", off, got, plt);
 | 
				
			||||||
        put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
 | 
					        put32(p, 0xa9bf7bf0); // stp x16,x30,[sp,#-16]!
 | 
				
			||||||
        put32(p + 4, (0x90000010 | // adrp x16,...
 | 
					        put32(p + 4, (0x90000010 | // adrp x16,...
 | 
				
			||||||
                      (off & 0x1ffffc) << 3 | (off & 3) << 29));
 | 
					                      (off & 0x1ffffc) << 3 | (off & 3) << 29));
 | 
				
			||||||
| 
						 | 
					@ -1914,8 +1955,8 @@ ST_FUNC void relocate_plt(TCCState *s1)
 | 
				
			||||||
            uint64_t addr = got +
 | 
					            uint64_t addr = got +
 | 
				
			||||||
                (get32(p) | (uint64_t)get32(p + 4) << 32);
 | 
					                (get32(p) | (uint64_t)get32(p + 4) << 32);
 | 
				
			||||||
            uint32_t off = (addr >> 12) - (pc >> 12);
 | 
					            uint32_t off = (addr >> 12) - (pc >> 12);
 | 
				
			||||||
            if ((off + ((uint64_t)1 << 20)) >> 21)
 | 
					            if ((off + ((uint32_t)1 << 20)) >> 21)
 | 
				
			||||||
                tcc_error("Failed relocating PLT");
 | 
					                tcc_error("Failed relocating PLT (off=0x%lx, addr=0x%lx, pc=0x%lx)", off, addr, pc);
 | 
				
			||||||
            put32(p, (0x90000010 | // adrp x16,...
 | 
					            put32(p, (0x90000010 | // adrp x16,...
 | 
				
			||||||
                      (off & 0x1ffffc) << 3 | (off & 3) << 29));
 | 
					                      (off & 0x1ffffc) << 3 | (off & 3) << 29));
 | 
				
			||||||
            put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
 | 
					            put32(p + 4, (0xf9400211 | // ldr x17,[x16,#...]
 | 
				
			||||||
| 
						 | 
					@ -2590,9 +2631,12 @@ static int elf_output_file(TCCState *s1, const char *filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /* relocate symbols in .dynsym now that final addresses are known */
 | 
					            /* relocate symbols in .dynsym now that final addresses are known */
 | 
				
			||||||
            for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) {
 | 
					            for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) {
 | 
				
			||||||
                /* relocate to PLT if symbol corresponds to a PLT entry */
 | 
					 | 
				
			||||||
                if (sym->st_shndx == SHN_UNDEF) {
 | 
					                if (sym->st_shndx == SHN_UNDEF) {
 | 
				
			||||||
                    if (sym->st_value)
 | 
					                    /* relocate to PLT if symbol corresponds to a PLT entry,
 | 
				
			||||||
 | 
							       but not if it's a weak symbol */
 | 
				
			||||||
 | 
							    if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
 | 
				
			||||||
 | 
							        sym->st_value = 0;
 | 
				
			||||||
 | 
							    else if (sym->st_value)
 | 
				
			||||||
                        sym->st_value += s1->plt->sh_addr;
 | 
					                        sym->st_value += s1->plt->sh_addr;
 | 
				
			||||||
                } else if (sym->st_shndx < SHN_LORESERVE) {
 | 
					                } else if (sym->st_shndx < SHN_LORESERVE) {
 | 
				
			||||||
                    /* do symbol relocation */
 | 
					                    /* do symbol relocation */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								tccrun.c
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								tccrun.c
									
										
									
									
									
								
							| 
						 | 
					@ -196,7 +196,7 @@ static int tcc_relocate_ex(TCCState *s1, void *ptr)
 | 
				
			||||||
        if (0 == (s->sh_flags & SHF_ALLOC))
 | 
					        if (0 == (s->sh_flags & SHF_ALLOC))
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        length = s->data_offset;
 | 
					        length = s->data_offset;
 | 
				
			||||||
        // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
 | 
					        // printf("%-12s %08lx %04x\n", s->name, s->sh_addr, length);
 | 
				
			||||||
        ptr = (void*)s->sh_addr;
 | 
					        ptr = (void*)s->sh_addr;
 | 
				
			||||||
        if (NULL == s->data || s->sh_type == SHT_NOBITS)
 | 
					        if (NULL == s->data || s->sh_type == SHT_NOBITS)
 | 
				
			||||||
            memset(ptr, 0, length);
 | 
					            memset(ptr, 0, length);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue