Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/insn: Support big endian cross-compiles

The x86 instruction decoder code is shared across the kernel source and
the tools. Currently objtool seems to be the only tool from build tools
needed which breaks x86 cross-compilation on big endian systems. Make
the x86 instruction decoder build host endianness agnostic to support
x86 cross-compilation and enable objtool to implement endianness
awareness for big endian architectures support.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Co-developed-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>

authored by

Martin Schwidefsky and committed by
Josh Poimboeuf
1d509f2a c8d7b7e5

+160 -112
+33
arch/x86/include/asm/insn.h
··· 7 7 * Copyright (C) IBM Corporation, 2009 8 8 */ 9 9 10 + #include <asm/byteorder.h> 10 11 /* insn_attr_t is defined in inat.h */ 11 12 #include <asm/inat.h> 13 + 14 + #if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) 12 15 13 16 struct insn_field { 14 17 union { ··· 22 19 unsigned char got; 23 20 unsigned char nbytes; 24 21 }; 22 + 23 + static inline void insn_field_set(struct insn_field *p, insn_value_t v, 24 + unsigned char n) 25 + { 26 + p->value = v; 27 + p->nbytes = n; 28 + } 29 + 30 + #else 31 + 32 + struct insn_field { 33 + insn_value_t value; 34 + union { 35 + insn_value_t little; 36 + insn_byte_t bytes[4]; 37 + }; 38 + /* !0 if we've run insn_get_xxx() for this field */ 39 + unsigned char got; 40 + unsigned char nbytes; 41 + }; 42 + 43 + static inline void insn_field_set(struct insn_field *p, insn_value_t v, 44 + unsigned char n) 45 + { 46 + p->value = v; 47 + p->little = __cpu_to_le32(v); 48 + p->nbytes = n; 49 + } 50 + 51 + #endif 25 52 26 53 struct insn { 27 54 struct insn_field prefixes; /*
+47 -54
arch/x86/lib/insn.c
··· 5 5 * Copyright (C) IBM Corporation, 2002, 2004, 2009 6 6 */ 7 7 8 + #include <linux/kernel.h> 8 9 #ifdef __KERNEL__ 9 10 #include <linux/string.h> 10 11 #else ··· 16 15 17 16 #include <asm/emulate_prefix.h> 18 17 18 + #define leXX_to_cpu(t, r) \ 19 + ({ \ 20 + __typeof__(t) v; \ 21 + switch (sizeof(t)) { \ 22 + case 4: v = le32_to_cpu(r); break; \ 23 + case 2: v = le16_to_cpu(r); break; \ 24 + case 1: v = r; break; \ 25 + default: \ 26 + BUILD_BUG(); break; \ 27 + } \ 28 + v; \ 29 + }) 30 + 19 31 /* Verify next sizeof(t) bytes can be on the same instruction */ 20 32 #define validate_next(t, insn, n) \ 21 33 ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) 22 34 23 35 #define __get_next(t, insn) \ 24 - ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) 36 + ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); leXX_to_cpu(t, r); }) 25 37 26 38 #define __peek_nbyte_next(t, insn, n) \ 27 - ({ t r = *(t*)((insn)->next_byte + n); r; }) 39 + ({ t r = *(t*)((insn)->next_byte + n); leXX_to_cpu(t, r); }) 28 40 29 41 #define get_next(t, insn) \ 30 42 ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) ··· 171 157 b = peek_next(insn_byte_t, insn); 172 158 attr = inat_get_opcode_attribute(b); 173 159 if (inat_is_rex_prefix(attr)) { 174 - insn->rex_prefix.value = b; 175 - insn->rex_prefix.nbytes = 1; 160 + insn_field_set(&insn->rex_prefix, b, 1); 176 161 insn->next_byte++; 177 162 if (X86_REX_W(b)) 178 163 /* REX.W overrides opnd_size */ ··· 308 295 309 296 if (inat_has_modrm(insn->attr)) { 310 297 mod = get_next(insn_byte_t, insn); 311 - modrm->value = mod; 312 - modrm->nbytes = 1; 298 + insn_field_set(modrm, mod, 1); 313 299 if (inat_is_group(insn->attr)) { 314 300 pfx_id = insn_last_prefix_id(insn); 315 301 insn->attr = inat_get_group_attribute(mod, pfx_id, ··· 346 334 * For rip-relative instructions, the mod field (top 2 bits) 347 335 * is zero and the r/m field (bottom 3 bits) is 0x5. 348 336 */ 349 - return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); 337 + return (modrm->nbytes && (modrm->bytes[0] & 0xc7) == 0x5); 350 338 } 351 339 352 340 /** ··· 365 353 if (!insn->modrm.got) 366 354 insn_get_modrm(insn); 367 355 if (insn->modrm.nbytes) { 368 - modrm = (insn_byte_t)insn->modrm.value; 356 + modrm = insn->modrm.bytes[0]; 369 357 if (insn->addr_bytes != 2 && 370 358 X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { 371 - insn->sib.value = get_next(insn_byte_t, insn); 372 - insn->sib.nbytes = 1; 359 + insn_field_set(&insn->sib, 360 + get_next(insn_byte_t, insn), 1); 373 361 } 374 362 } 375 363 insn->sib.got = 1; ··· 419 407 if (mod == 3) 420 408 goto out; 421 409 if (mod == 1) { 422 - insn->displacement.value = get_next(signed char, insn); 423 - insn->displacement.nbytes = 1; 410 + insn_field_set(&insn->displacement, 411 + get_next(signed char, insn), 1); 424 412 } else if (insn->addr_bytes == 2) { 425 413 if ((mod == 0 && rm == 6) || mod == 2) { 426 - insn->displacement.value = 427 - get_next(short, insn); 428 - insn->displacement.nbytes = 2; 414 + insn_field_set(&insn->displacement, 415 + get_next(short, insn), 2); 429 416 } 430 417 } else { 431 418 if ((mod == 0 && rm == 5) || mod == 2 || 432 419 (mod == 0 && base == 5)) { 433 - insn->displacement.value = get_next(int, insn); 434 - insn->displacement.nbytes = 4; 420 + insn_field_set(&insn->displacement, 421 + get_next(int, insn), 4); 435 422 } 436 423 } 437 424 } ··· 446 435 { 447 436 switch (insn->addr_bytes) { 448 437 case 2: 449 - insn->moffset1.value = get_next(short, insn); 450 - insn->moffset1.nbytes = 2; 438 + insn_field_set(&insn->moffset1, get_next(short, insn), 2); 451 439 break; 452 440 case 4: 453 - insn->moffset1.value = get_next(int, insn); 454 - insn->moffset1.nbytes = 4; 441 + insn_field_set(&insn->moffset1, get_next(int, insn), 4); 455 442 break; 456 443 case 8: 457 - insn->moffset1.value = get_next(int, insn); 458 - insn->moffset1.nbytes = 4; 459 - insn->moffset2.value = get_next(int, insn); 460 - insn->moffset2.nbytes = 4; 444 + insn_field_set(&insn->moffset1, get_next(int, insn), 4); 445 + insn_field_set(&insn->moffset2, get_next(int, insn), 4); 461 446 break; 462 447 default: /* opnd_bytes must be modified manually */ 463 448 goto err_out; ··· 471 464 { 472 465 switch (insn->opnd_bytes) { 473 466 case 2: 474 - insn->immediate.value = get_next(short, insn); 475 - insn->immediate.nbytes = 2; 467 + insn_field_set(&insn->immediate, get_next(short, insn), 2); 476 468 break; 477 469 case 4: 478 470 case 8: 479 - insn->immediate.value = get_next(int, insn); 480 - insn->immediate.nbytes = 4; 471 + insn_field_set(&insn->immediate, get_next(int, insn), 4); 481 472 break; 482 473 default: /* opnd_bytes must be modified manually */ 483 474 goto err_out; ··· 492 487 { 493 488 switch (insn->opnd_bytes) { 494 489 case 2: 495 - insn->immediate1.value = get_next(short, insn); 496 - insn->immediate1.nbytes = 2; 490 + insn_field_set(&insn->immediate1, get_next(short, insn), 2); 497 491 break; 498 492 case 4: 499 - insn->immediate1.value = get_next(int, insn); 493 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 500 494 insn->immediate1.nbytes = 4; 501 495 break; 502 496 case 8: 503 - insn->immediate1.value = get_next(int, insn); 504 - insn->immediate1.nbytes = 4; 505 - insn->immediate2.value = get_next(int, insn); 506 - insn->immediate2.nbytes = 4; 497 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 498 + insn_field_set(&insn->immediate2, get_next(int, insn), 4); 507 499 break; 508 500 default: /* opnd_bytes must be modified manually */ 509 501 goto err_out; ··· 517 515 { 518 516 switch (insn->opnd_bytes) { 519 517 case 2: 520 - insn->immediate1.value = get_next(short, insn); 521 - insn->immediate1.nbytes = 2; 518 + insn_field_set(&insn->immediate1, get_next(short, insn), 2); 522 519 break; 523 520 case 4: 524 - insn->immediate1.value = get_next(int, insn); 525 - insn->immediate1.nbytes = 4; 521 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 526 522 break; 527 523 case 8: 528 524 /* ptr16:64 is not exist (no segment) */ ··· 528 528 default: /* opnd_bytes must be modified manually */ 529 529 goto err_out; 530 530 } 531 - insn->immediate2.value = get_next(unsigned short, insn); 532 - insn->immediate2.nbytes = 2; 531 + insn_field_set(&insn->immediate2, get_next(unsigned short, insn), 2); 533 532 insn->immediate1.got = insn->immediate2.got = 1; 534 533 535 534 return 1; ··· 564 565 565 566 switch (inat_immediate_size(insn->attr)) { 566 567 case INAT_IMM_BYTE: 567 - insn->immediate.value = get_next(signed char, insn); 568 - insn->immediate.nbytes = 1; 568 + insn_field_set(&insn->immediate, get_next(signed char, insn), 1); 569 569 break; 570 570 case INAT_IMM_WORD: 571 - insn->immediate.value = get_next(short, insn); 572 - insn->immediate.nbytes = 2; 571 + insn_field_set(&insn->immediate, get_next(short, insn), 2); 573 572 break; 574 573 case INAT_IMM_DWORD: 575 - insn->immediate.value = get_next(int, insn); 576 - insn->immediate.nbytes = 4; 574 + insn_field_set(&insn->immediate, get_next(int, insn), 4); 577 575 break; 578 576 case INAT_IMM_QWORD: 579 - insn->immediate1.value = get_next(int, insn); 580 - insn->immediate1.nbytes = 4; 581 - insn->immediate2.value = get_next(int, insn); 582 - insn->immediate2.nbytes = 4; 577 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 578 + insn_field_set(&insn->immediate2, get_next(int, insn), 4); 583 579 break; 584 580 case INAT_IMM_PTR: 585 581 if (!__get_immptr(insn)) ··· 593 599 goto err_out; 594 600 } 595 601 if (inat_has_second_immediate(insn->attr)) { 596 - insn->immediate2.value = get_next(signed char, insn); 597 - insn->immediate2.nbytes = 1; 602 + insn_field_set(&insn->immediate2, get_next(signed char, insn), 1); 598 603 } 599 604 done: 600 605 insn->immediate.got = 1;
-4
arch/x86/tools/insn_sanity.c
··· 14 14 #include <sys/types.h> 15 15 #include <sys/stat.h> 16 16 #include <fcntl.h> 17 - 18 - #define unlikely(cond) (cond) 19 - #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) 20 - 21 17 #include <asm/insn.h> 22 18 #include <inat.c> 23 19 #include <insn.c>
+33
tools/arch/x86/include/asm/insn.h
··· 7 7 * Copyright (C) IBM Corporation, 2009 8 8 */ 9 9 10 + #include <asm/byteorder.h> 10 11 /* insn_attr_t is defined in inat.h */ 11 12 #include "inat.h" 13 + 14 + #if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) 12 15 13 16 struct insn_field { 14 17 union { ··· 22 19 unsigned char got; 23 20 unsigned char nbytes; 24 21 }; 22 + 23 + static inline void insn_field_set(struct insn_field *p, insn_value_t v, 24 + unsigned char n) 25 + { 26 + p->value = v; 27 + p->nbytes = n; 28 + } 29 + 30 + #else 31 + 32 + struct insn_field { 33 + insn_value_t value; 34 + union { 35 + insn_value_t little; 36 + insn_byte_t bytes[4]; 37 + }; 38 + /* !0 if we've run insn_get_xxx() for this field */ 39 + unsigned char got; 40 + unsigned char nbytes; 41 + }; 42 + 43 + static inline void insn_field_set(struct insn_field *p, insn_value_t v, 44 + unsigned char n) 45 + { 46 + p->value = v; 47 + p->little = __cpu_to_le32(v); 48 + p->nbytes = n; 49 + } 50 + 51 + #endif 25 52 26 53 struct insn { 27 54 struct insn_field prefixes; /*
+47 -54
tools/arch/x86/lib/insn.c
··· 5 5 * Copyright (C) IBM Corporation, 2002, 2004, 2009 6 6 */ 7 7 8 + #include <linux/kernel.h> 8 9 #ifdef __KERNEL__ 9 10 #include <linux/string.h> 10 11 #else ··· 16 15 17 16 #include "../include/asm/emulate_prefix.h" 18 17 18 + #define leXX_to_cpu(t, r) \ 19 + ({ \ 20 + __typeof__(t) v; \ 21 + switch (sizeof(t)) { \ 22 + case 4: v = le32_to_cpu(r); break; \ 23 + case 2: v = le16_to_cpu(r); break; \ 24 + case 1: v = r; break; \ 25 + default: \ 26 + BUILD_BUG(); break; \ 27 + } \ 28 + v; \ 29 + }) 30 + 19 31 /* Verify next sizeof(t) bytes can be on the same instruction */ 20 32 #define validate_next(t, insn, n) \ 21 33 ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) 22 34 23 35 #define __get_next(t, insn) \ 24 - ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) 36 + ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); leXX_to_cpu(t, r); }) 25 37 26 38 #define __peek_nbyte_next(t, insn, n) \ 27 - ({ t r = *(t*)((insn)->next_byte + n); r; }) 39 + ({ t r = *(t*)((insn)->next_byte + n); leXX_to_cpu(t, r); }) 28 40 29 41 #define get_next(t, insn) \ 30 42 ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) ··· 171 157 b = peek_next(insn_byte_t, insn); 172 158 attr = inat_get_opcode_attribute(b); 173 159 if (inat_is_rex_prefix(attr)) { 174 - insn->rex_prefix.value = b; 175 - insn->rex_prefix.nbytes = 1; 160 + insn_field_set(&insn->rex_prefix, b, 1); 176 161 insn->next_byte++; 177 162 if (X86_REX_W(b)) 178 163 /* REX.W overrides opnd_size */ ··· 308 295 309 296 if (inat_has_modrm(insn->attr)) { 310 297 mod = get_next(insn_byte_t, insn); 311 - modrm->value = mod; 312 - modrm->nbytes = 1; 298 + insn_field_set(modrm, mod, 1); 313 299 if (inat_is_group(insn->attr)) { 314 300 pfx_id = insn_last_prefix_id(insn); 315 301 insn->attr = inat_get_group_attribute(mod, pfx_id, ··· 346 334 * For rip-relative instructions, the mod field (top 2 bits) 347 335 * is zero and the r/m field (bottom 3 bits) is 0x5. 348 336 */ 349 - return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); 337 + return (modrm->nbytes && (modrm->bytes[0] & 0xc7) == 0x5); 350 338 } 351 339 352 340 /** ··· 365 353 if (!insn->modrm.got) 366 354 insn_get_modrm(insn); 367 355 if (insn->modrm.nbytes) { 368 - modrm = (insn_byte_t)insn->modrm.value; 356 + modrm = insn->modrm.bytes[0]; 369 357 if (insn->addr_bytes != 2 && 370 358 X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { 371 - insn->sib.value = get_next(insn_byte_t, insn); 372 - insn->sib.nbytes = 1; 359 + insn_field_set(&insn->sib, 360 + get_next(insn_byte_t, insn), 1); 373 361 } 374 362 } 375 363 insn->sib.got = 1; ··· 419 407 if (mod == 3) 420 408 goto out; 421 409 if (mod == 1) { 422 - insn->displacement.value = get_next(signed char, insn); 423 - insn->displacement.nbytes = 1; 410 + insn_field_set(&insn->displacement, 411 + get_next(signed char, insn), 1); 424 412 } else if (insn->addr_bytes == 2) { 425 413 if ((mod == 0 && rm == 6) || mod == 2) { 426 - insn->displacement.value = 427 - get_next(short, insn); 428 - insn->displacement.nbytes = 2; 414 + insn_field_set(&insn->displacement, 415 + get_next(short, insn), 2); 429 416 } 430 417 } else { 431 418 if ((mod == 0 && rm == 5) || mod == 2 || 432 419 (mod == 0 && base == 5)) { 433 - insn->displacement.value = get_next(int, insn); 434 - insn->displacement.nbytes = 4; 420 + insn_field_set(&insn->displacement, 421 + get_next(int, insn), 4); 435 422 } 436 423 } 437 424 } ··· 446 435 { 447 436 switch (insn->addr_bytes) { 448 437 case 2: 449 - insn->moffset1.value = get_next(short, insn); 450 - insn->moffset1.nbytes = 2; 438 + insn_field_set(&insn->moffset1, get_next(short, insn), 2); 451 439 break; 452 440 case 4: 453 - insn->moffset1.value = get_next(int, insn); 454 - insn->moffset1.nbytes = 4; 441 + insn_field_set(&insn->moffset1, get_next(int, insn), 4); 455 442 break; 456 443 case 8: 457 - insn->moffset1.value = get_next(int, insn); 458 - insn->moffset1.nbytes = 4; 459 - insn->moffset2.value = get_next(int, insn); 460 - insn->moffset2.nbytes = 4; 444 + insn_field_set(&insn->moffset1, get_next(int, insn), 4); 445 + insn_field_set(&insn->moffset2, get_next(int, insn), 4); 461 446 break; 462 447 default: /* opnd_bytes must be modified manually */ 463 448 goto err_out; ··· 471 464 { 472 465 switch (insn->opnd_bytes) { 473 466 case 2: 474 - insn->immediate.value = get_next(short, insn); 475 - insn->immediate.nbytes = 2; 467 + insn_field_set(&insn->immediate, get_next(short, insn), 2); 476 468 break; 477 469 case 4: 478 470 case 8: 479 - insn->immediate.value = get_next(int, insn); 480 - insn->immediate.nbytes = 4; 471 + insn_field_set(&insn->immediate, get_next(int, insn), 4); 481 472 break; 482 473 default: /* opnd_bytes must be modified manually */ 483 474 goto err_out; ··· 492 487 { 493 488 switch (insn->opnd_bytes) { 494 489 case 2: 495 - insn->immediate1.value = get_next(short, insn); 496 - insn->immediate1.nbytes = 2; 490 + insn_field_set(&insn->immediate1, get_next(short, insn), 2); 497 491 break; 498 492 case 4: 499 - insn->immediate1.value = get_next(int, insn); 493 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 500 494 insn->immediate1.nbytes = 4; 501 495 break; 502 496 case 8: 503 - insn->immediate1.value = get_next(int, insn); 504 - insn->immediate1.nbytes = 4; 505 - insn->immediate2.value = get_next(int, insn); 506 - insn->immediate2.nbytes = 4; 497 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 498 + insn_field_set(&insn->immediate2, get_next(int, insn), 4); 507 499 break; 508 500 default: /* opnd_bytes must be modified manually */ 509 501 goto err_out; ··· 517 515 { 518 516 switch (insn->opnd_bytes) { 519 517 case 2: 520 - insn->immediate1.value = get_next(short, insn); 521 - insn->immediate1.nbytes = 2; 518 + insn_field_set(&insn->immediate1, get_next(short, insn), 2); 522 519 break; 523 520 case 4: 524 - insn->immediate1.value = get_next(int, insn); 525 - insn->immediate1.nbytes = 4; 521 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 526 522 break; 527 523 case 8: 528 524 /* ptr16:64 is not exist (no segment) */ ··· 528 528 default: /* opnd_bytes must be modified manually */ 529 529 goto err_out; 530 530 } 531 - insn->immediate2.value = get_next(unsigned short, insn); 532 - insn->immediate2.nbytes = 2; 531 + insn_field_set(&insn->immediate2, get_next(unsigned short, insn), 2); 533 532 insn->immediate1.got = insn->immediate2.got = 1; 534 533 535 534 return 1; ··· 564 565 565 566 switch (inat_immediate_size(insn->attr)) { 566 567 case INAT_IMM_BYTE: 567 - insn->immediate.value = get_next(signed char, insn); 568 - insn->immediate.nbytes = 1; 568 + insn_field_set(&insn->immediate, get_next(signed char, insn), 1); 569 569 break; 570 570 case INAT_IMM_WORD: 571 - insn->immediate.value = get_next(short, insn); 572 - insn->immediate.nbytes = 2; 571 + insn_field_set(&insn->immediate, get_next(short, insn), 2); 573 572 break; 574 573 case INAT_IMM_DWORD: 575 - insn->immediate.value = get_next(int, insn); 576 - insn->immediate.nbytes = 4; 574 + insn_field_set(&insn->immediate, get_next(int, insn), 4); 577 575 break; 578 576 case INAT_IMM_QWORD: 579 - insn->immediate1.value = get_next(int, insn); 580 - insn->immediate1.nbytes = 4; 581 - insn->immediate2.value = get_next(int, insn); 582 - insn->immediate2.nbytes = 4; 577 + insn_field_set(&insn->immediate1, get_next(int, insn), 4); 578 + insn_field_set(&insn->immediate2, get_next(int, insn), 4); 583 579 break; 584 580 case INAT_IMM_PTR: 585 581 if (!__get_immptr(insn)) ··· 593 599 goto err_out; 594 600 } 595 601 if (inat_has_second_immediate(insn->attr)) { 596 - insn->immediate2.value = get_next(signed char, insn); 597 - insn->immediate2.nbytes = 1; 602 + insn_field_set(&insn->immediate2, get_next(signed char, insn), 1); 598 603 } 599 604 done: 600 605 insn->immediate.got = 1;