จะบังคับให้ NASM เข้ารหัส [1 + rax*2] เป็น disp32 + index*2 แทนที่จะเป็น disp8 + base + index ได้อย่างไร

หากต้องการ x = x*10 + 1 อย่างมีประสิทธิภาพ อาจเหมาะสมที่สุดที่จะใช้

lea   eax, [rax + rax*4]   ; x*=5
lea   eax, [1 + rax*2]     ; x = x*2 + 1

LEA แบบ 3 องค์ประกอบมีเวลาแฝงที่สูงกว่า บน CPU รุ่นใหม่ของ Intel เช่น 3 รอบต่อ 1 บนตระกูล Sandybridge ดังนั้น disp32 + index*2 จึงเร็วกว่า disp8 + base + index*1 บนตระกูล SnB กล่าวคือ CPU x86 กระแสหลักส่วนใหญ่ที่เราใส่ใจในการเพิ่มประสิทธิภาพ (ซึ่งส่วนใหญ่ใช้กับ LEA เท่านั้น ไม่ใช่ โหลด/จัดเก็บ เนื่องจาก LEA ทำงานบนหน่วยประมวลผล ALU ไม่ใช่ AGU ใน CPU x86 ที่ทันสมัยที่สุด) CPU ของ AMD มี LEA ที่ช้ากว่าโดยมี 3 องค์ประกอบหรือ scale > 1 (http://agner.org/optimize/)

แต่ NASM และ YASM จะปรับให้เหมาะสมสำหรับขนาดโค้ดโดยใช้ [1 + rax + rax*1] สำหรับ LEA ลำดับที่ 2 ซึ่งต้องการเพียง disp8 แทนที่จะเป็น disp32 (โหมดการกำหนดแอดเดรสจะมีรีจิสเตอร์พื้นฐานหรือ disp32 เสมอ)

นั่นคือพวกเขาจะแบ่ง reg*2 เป็น base+index เสมอ เพราะนั่นไม่เคยเลวร้ายไปกว่าขนาดโค้ด

ฉันสามารถบังคับให้ใช้ disp32 ด้วย lea eax, [dword 1 + rax*2] ได้ แต่นั่นไม่ได้หยุด NASM หรือ YASM จากการแยกโหมดการกำหนดแอดเดรส ดูเหมือนว่าคู่มือของ NASM จะไม่บันทึกวิธีการใช้คำหลัก strict บนตัวประกอบสเกล และ [1 + strict rax*2] ไม่ได้ประกอบ มีวิธีใช้ strict หรือไวยากรณ์อื่นๆ เพื่อบังคับให้มีการเข้ารหัสที่ต้องการของโหมดการกำหนดที่อยู่หรือไม่


nasm -O0 เพื่อปิดใช้งานการเพิ่มประสิทธิภาพไม่ทำงาน เห็นได้ชัดว่ามีเพียงการควบคุมการปรับการแทนที่สาขาแบบหลายรอบเท่านั้น ไม่ใช่การปรับให้เหมาะสม ทั้งหมด ที่ NASM ทำ แน่นอนว่าคุณคงไม่อยากทำเช่นนั้นตั้งแต่แรกสำหรับไฟล์ต้นฉบับทั้งหมด แม้ว่ามันจะได้ผลก็ตาม ฉันยังคงได้รับ

8d 84 00 01 00 00 00    lea    eax,[rax+rax*1+0x1]

วิธีแก้ปัญหาเดียวที่ฉันคิดได้คือเข้ารหัสด้วยตนเองด้วย db นี่ค่อนข้างไม่สะดวก สำหรับบันทึก การเข้ารหัสด้วยตนเองคือ:

db 0x8d, 0x04, 0x45  ; opcode, modrm, SIB  for lea eax, [disp32 + rax*2]
dd 1                 ; disp32

สเกลแฟคเตอร์ถูกเข้ารหัสด้วยไบต์ SIB สูง 2 บิต ฉันประกอบ lea eax, [dword 1 + rax*4] เพื่อรับรหัสเครื่องสำหรับรีจิสเตอร์ที่ถูกต้อง เนื่องจากการเพิ่มประสิทธิภาพของ NASM ใช้งานได้กับ *2 เท่านั้น SIB คือ 0x85 และการลดค่าฟิลด์ 2 บิตที่ด้านบนของไบต์จะลดค่าสเกลแฟคเตอร์จาก 4 เป็น 2


แต่คำถามคือ: จะเขียนมันในลักษณะที่อ่านง่ายได้อย่างไร ซึ่งทำให้ง่ายต่อการเปลี่ยนรีจิสเตอร์ และให้ NASM เข้ารหัสโหมดการกำหนดแอดเดรสให้คุณ (ฉันคิดว่ามาโครขนาดยักษ์สามารถทำได้ด้วย การประมวลผลข้อความและการเข้ารหัส db ด้วยตนเอง แต่นั่นไม่ใช่คำตอบที่ฉันกำลังมองหาจริงๆ ฉันไม่ต้องการสิ่งนี้เพื่ออะไรตอนนี้ ฉันอยากจะรู้ว่า NASM หรือ YASM มีไวยากรณ์เพื่อบังคับสิ่งนี้เป็นส่วนใหญ่)

การเพิ่มประสิทธิภาพอื่น ๆ ที่ฉันทราบเช่น mov rax, 1 การประกอบเป็น 5 ไบต์ mov eax,1 เป็นชัยชนะอย่างแท้จริงบน CPU ทั้งหมด เว้นแต่คุณต้องการคำแนะนำที่ยาวขึ้นเพื่อรับการเติมโดยไม่มี NOP และสามารถปิดใช้งานได้ด้วย mov rax, strict dword 1 เพื่อรับการเข้ารหัสแบบขยายสัญญาณ 7 ไบต์ หรือ strict qword สำหรับ 10 ไบต์ imm64


แก๊สไม่ได้ทำสิ่งนี้หรือการเพิ่มประสิทธิภาพอื่น ๆ ส่วนใหญ่ (เฉพาะขนาดของการแทนที่ทันทีและการกระจัดสาขา): lea 1(,%rax,2), %eax ประกอบเป็น
8d 04 45 01 00 00 00 lea eax,[rax*2+0x1] และเหมือนกันสำหรับเวอร์ชัน .intel_syntax noprefix

คำตอบสำหรับ MASM หรือผู้ประกอบรายอื่นก็น่าสนใจเช่นกัน


person Peter Cordes    schedule 18.02.2018    source แหล่งที่มา


คำตอบ (1)


NOSPLIT:

ในทำนองเดียวกัน NASM จะแยก [eax*2] ออกเป็น [eax+eax] เนื่องจากจะทำให้ไม่มีฟิลด์ออฟเซ็ตและประหยัดพื้นที่ ในความเป็นจริง มันจะแยก [eax*2+offset] ออกเป็น [eax+eax+offset] ด้วย
คุณสามารถต่อสู้กับพฤติกรรมนี้ได้โดยใช้คำหลัก NOSPLIT: [nosplit eax*2] จะบังคับให้สร้าง [eax*2+0] อย่างแท้จริง
[nosplit eax*1] ยังมี ผลเดียวกัน ในอีกทางหนึ่ง สามารถใช้แบบฟอร์ม EA แบบแยก [0, eax*2] ได้เช่นกัน อย่างไรก็ตาม NOSPLIT ใน [nosplit eax+eax] จะถูกละเว้น เนื่องจากความตั้งใจของผู้ใช้ที่นี่ถือเป็น [eax+eax]

lea eax, [NOSPLIT 1+rax*2]
lea eax, [1+rax*2]

00000000  8D044501000000    lea eax,[rax*2+0x1]
00000007  8D440001          lea eax,[rax+rax+0x1]
person Margaret Bloom    schedule 18.02.2018
comment
ขอบคุณ ฉันคิดว่าฉันจำได้ว่าเห็นไวยากรณ์สำหรับสิ่งนี้ที่กล่าวถึงที่ไหนสักแห่ง ฉันพลาดไปเมื่อค้นหาวันนี้ เพราะฉันคิดว่ามันจะเกี่ยวข้องกับ strict (และผมไม่ได้ค้นหาอะไรหนักมากเพราะผมอยากเขียนท่อนการแสดงใน SO :P) - person Peter Cordes; 18.02.2018
comment
ยินดีต้อนรับครับ @ปีเตอร์ Nasm doc ไม่มีอภิธานศัพท์คำหลัก IMO ฉันต้องดูซอร์สโค้ด ฉันกำลังดูว่าแอสเซมเบลอร์อื่นทำอะไร: TASM ไม่ปรับให้เหมาะสม, YASM มี NOSPLIT, MASM 5 หรือเก่ากว่าไม่ควรปรับให้เหมาะสม, MASM ใหม่ฉันไม่รู้ (ไม่แน่ใจว่าจะหาได้หรือไม่หากไม่มี Visual Studio และ ทำให้มันใช้งานได้บน Debian) - person Margaret Bloom; 18.02.2018
comment
อืม ใช่แล้ว อภิธานศัพท์จะมีประโยชน์เช่นเดียวกับ ดัชนี ที่มีอยู่ ซึ่งคุณต้องรู้ว่าคุณกำลังมองหาอะไร เมื่อมองย้อนกลับไป การดูส่วนที่อยู่ที่มีประสิทธิภาพของคู่มือก็สมเหตุสมผลแล้ว - person Peter Cordes; 18.02.2018